質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • C++

    3581questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

超簡単なオセロプログラミング (curses,C++を使用)

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 2,928

van-0215

score 56

コード
#include <iostream>
#include <curses.h>
#include <cstdio>
using namespace std;
int ban[111]={0};//8*8マスをゲームには使用,横軸9マス目は改行場所
int dir[]={-10,-9,-8,-1,1,8,9,10};//1次元配列だから8方向への距離
int turn=1,put=0;//自分は1、相手は2
int check();//ひっくり返せるコマ数をチェック
int main(){
  initscr();//スクリーンの初期化
  noecho();//キー入力した文字を表示しないモード
  keypad(stdscr,TRUE);//カーソルキーを有効化
  int key;//ASCII コード(1バイトの数値,0x00 〜 0xFF) だけでは表わしきれない程に多数ある特殊キーにも 番号(4バイトの数値,0x00000100 〜 0xFFFFFFFF)が割り当てられているから
  
  int x,y;
  //int koma[4]={-,o,x,\n};//この配列は使わないがルール確認のため。(-)は何も置いてない、(o)は自分のコマ,(x)は敵のコマ
  ban[30]=ban[40]=1;//自分の初期コマ(o)の配置
  ban[31]=ban[39]=2;//敵の初期コマ(x)の配置
  for(int i=8;i<=72;i+=9){//改行地
    ban[i]=3;
  }
  
  for(int j=0;j<72;j++){
    if(ban[j]==0)printw("-");
    else if(ban[j]==1)printw("o");
    else if(ban[j]==2)printw("x");
    else if(ban[j]==3)printw("\n");
  }

  for(int i=0;;i++){//すべての盤面にコマを置くまで続ける
    if(turn==1){//自分のターンだったら
      x=0;
      y=0;
      move(y,x);
      while(1){//十時キーでの置き場移動(curses) Enterで位置確
    key=getch();//十字キーの入力
    if(key=='\n')break;
    switch (key){
    case KEY_UP:    y--; break;//上へ
    case KEY_DOWN:    y++; break;//下へ
    case KEY_LEFT:    x--; break;//左へ
    case KEY_RIGHT:    x++; break;//右へ
    }
    move(y,x);
    refresh();//スクリーンのリフレッシュ
      }
      put=((y+1)*9)-x;//置いた位置(Enterで決定した位置)
      check();
    }else{
      put++;//COMの置く場所を決める(banの0番地から順番に見ていき置ける場所に置くという雑魚)
      check();
    }
    if(i==100)break;//ここはとりあえず適当です。
  }
}

int check(){
  int cnt=0;
  int line=0;
  int tasu=0;
  if(ban[put]==0){//置ける可能性あり(何も置いてなかった)
    for(int i=0;i<8;i++){//全方向を調べる
      cnt=0;
      tasu=0;
      for(line=put+dir[i];ban[line]==3-turn/*敵のコマがある間*/;line+=dir[i]){//条件に3-turnと入れておけば相手の駒か自分の駒かがわかる
    cnt++;//相手のコマの枚数をカウント
      }
      if(cnt>=1 && ban[line]==turn){//間にコマが一枚以上存在し、その上端が自分のコマだったら
    for(int j=0;j<cnt;j++){//実際にひっくり返す
      ban[put+tasu]=turn;
      tasu+=dir[i];
    }
      }
    }
  }
}
現在高校生です。 簡単な人対コンピュータのプログラムをC++とcursesをつかい書いております。
添付コードのように書いたのですが、盤面とcursesによるカーソル移動はできるもののEnterを押し置く場所の決定をしても、(0,0)にカーソルが移動し何も動作しません。
どうしたらよいでしょうか?
ちなみに参考とさせていただいてるウェブページのリンクをはっておきます。 回答の方よろしくお願いします。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

このコードだと毎ループx,yに0クリアとmoveかけてるから、0,0にカーソルが戻るのは正常?ですね。
となると、問題はbanに書き込みが行われないか反映されていないという事になりますが、正常値を与えればbanへの書き込みはcheck関数内で通るようになっています。
なので、反映されないというのが問題点になるのですが、そこに焦点を当てて追ってみると「banを使ってprintfしているのが、ループ突入前しかない」事がわかります。
つまり、せっかく変数を書き換えたのに、それを使っていないわけです。

なので、「banを使ってprintf」する処理をループ内に埋め込めば、解決するでしょう。

後、とりあえず気になった点を。
・while(1)をdo~whileにして、終了条件をkey=='\n'にしたほうがいいかと。(無限ループは多用しないほうがいい。)
・xを位置を求める際に使用している方法「-」なのに、右方向が「+」なのは逆ではないですか?
・x,yが上限下限を超える際の処理が入っていない。
・可能なら、banを二重配列にするほうが可読性が高まっていいと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

当初の質問に対しては、yuragumoさんの回答の前半で過不足ないと思います。

後半について、いくつか気になった点があるので補足。
・ban配列の初期化: 問題ありません。
(参考HP: http://cpplover.blogspot.jp/2010/09/blog-post_18.html )
・while(1): 問題ありません。(後述)
・x,yの範囲: check関数にも同様の、致命的なバグが潜んでいます。

個人的に気になった点は以下の2点です。
・ずっと俺のターン。
・check関数は「check」と名乗る以上、あくまで石を置けるか判定するにとどめるべき。
(石を置く処理は、putdiscなど、もっとわかりやすい関数名にすべき)

他にも気になる点は多々ありますが、本質から離れてしまうので、程々にしておきます。
連絡をいただければいくらでもおつきあいいたします。

<発展的内容>
*1 ループの書き換えはあまりオススメできません。バグの原因となります。
while(1){ A; if(C) break; B; } というループは
A; while(!C){ B;A; } と書き換え可能です。

以上、長文失礼しました。
ですが下の書き方の場合、Aを2箇所に、全く同じように書くことになります。
後日、Aの内容を書き換える必要ができたとき、両方修正する必要があることを見落とし、
バグを埋め込んでしまう、という事例は多々あります。
今回のケースのような場合にAの内容を繰り返して記述する必然性は皆無なので、
現状のままでよい、と考えました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/04 19:16

    初期化子足りない分0埋め自動的にする機能があったんですね。
    いつも静的変数の自動初期化か、そうでなければ明示的な初期化しか行ってこなかったので、勘違いしていました。

    訂正、ありがとうございます。

    キャンセル

0

直接の回答ではありませんが、
プログラムの動作を調べる方法を習得するとよいです。
- デバッガーを使う。
  - ログ出力する。
そうすれば、プログラムが思い通りの動作をしなかった場合の調査をすることができるようになります。


2 年前に javascipt(coffee-script) で作成した 人間 対 コンピュータ のオセロがあります。
コンピュータ側の思考ルーチンの参考になれば幸いです。

- リバーシ https://github.com/katoy/sample-enchant/tree/master/reversi
動作デモ

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

関連した質問

同じタグがついた質問を見る

  • C++

    3581questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。