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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C++

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

Q&A

解決済

3回答

9158閲覧

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

van-0215

総合スコア89

C++

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

0グッド

0クリップ

投稿2015/03/29 07:23

lang

1コード 2#include <iostream> 3#include <curses.h> 4#include <cstdio> 5using namespace std; 6int ban[111]={0};//8*8マスをゲームには使用,横軸9マス目は改行場所 7int dir[]={-10,-9,-8,-1,1,8,9,10};//1次元配列だから8方向への距離 8int turn=1,put=0;//自分は1、相手は2 9int check();//ひっくり返せるコマ数をチェック 10int main(){ 11 initscr();//スクリーンの初期化 12 noecho();//キー入力した文字を表示しないモード 13 keypad(stdscr,TRUE);//カーソルキーを有効化 14 int key;//ASCII コード(1バイトの数値,0x00 〜 0xFF) だけでは表わしきれない程に多数ある特殊キーにも 番号(4バイトの数値,0x00000100 〜 0xFFFFFFFF)が割り当てられているから 15 16 int x,y; 17 //int koma[4]={-,o,x,\n};//この配列は使わないがルール確認のため。(-)は何も置いてない、(o)は自分のコマ,(x)は敵のコマ 18 ban[30]=ban[40]=1;//自分の初期コマ(o)の配置 19 ban[31]=ban[39]=2;//敵の初期コマ(x)の配置 20 for(int i=8;i<=72;i+=9){//改行地 21 ban[i]=3; 22 } 23 24 for(int j=0;j<72;j++){ 25 if(ban[j]==0)printw("-"); 26 else if(ban[j]==1)printw("o"); 27 else if(ban[j]==2)printw("x"); 28 else if(ban[j]==3)printw("\n"); 29 } 30 31 for(int i=0;;i++){//すべての盤面にコマを置くまで続ける 32 if(turn==1){//自分のターンだったら 33 x=0; 34 y=0; 35 move(y,x); 36 while(1){//十時キーでの置き場移動(curses) Enterで位置確 37 key=getch();//十字キーの入力 38 if(key=='\n')break; 39 switch (key){ 40 case KEY_UP: y--; break;//上へ 41 case KEY_DOWN: y++; break;//下へ 42 case KEY_LEFT: x--; break;//左へ 43 case KEY_RIGHT: x++; break;//右へ 44 } 45 move(y,x); 46 refresh();//スクリーンのリフレッシュ 47 } 48 put=((y+1)*9)-x;//置いた位置(Enterで決定した位置) 49 check(); 50 }else{ 51 put++;//COMの置く場所を決める(banの0番地から順番に見ていき置ける場所に置くという雑魚) 52 check(); 53 } 54 if(i==100)break;//ここはとりあえず適当です。 55 } 56} 57 58int check(){ 59 int cnt=0; 60 int line=0; 61 int tasu=0; 62 if(ban[put]==0){//置ける可能性あり(何も置いてなかった) 63 for(int i=0;i<8;i++){//全方向を調べる 64 cnt=0; 65 tasu=0; 66 for(line=put+dir[i];ban[line]==3-turn/*敵のコマがある間*/;line+=dir[i]){//条件に3-turnと入れておけば相手の駒か自分の駒かがわかる 67 cnt++;//相手のコマの枚数をカウント 68 } 69 if(cnt>=1 && ban[line]==turn){//間にコマが一枚以上存在し、その上端が自分のコマだったら 70 for(int j=0;j<cnt;j++){//実際にひっくり返す 71 ban[put+tasu]=turn; 72 tasu+=dir[i]; 73 } 74 } 75 } 76 } 77} 78

現在高校生です。 簡単な人対コンピュータのプログラムをC++とcursesをつかい書いております。
添付コードのように書いたのですが、盤面とcursesによるカーソル移動はできるもののEnterを押し置く場所の決定をしても、(0,0)にカーソルが移動し何も動作しません。
どうしたらよいでしょうか?
ちなみに参考とさせていただいてるウェブページのリンクをはっておきます。 回答の方よろしくお願いします。

http://tricky-code.net/nicecode/code42oseroai.php

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

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

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

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

投稿2015/03/29 11:10

編集2015/04/04 10:17
yuragumo

総合スコア39

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

直接の回答ではありませんが、
プログラムの動作を調べる方法を習得するとよいです。

  • デバッガーを使う。
  • ログ出力する。

そうすれば、プログラムが思い通りの動作をしなかった場合の調査をすることができるようになります。

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

動作デモ

投稿2015/04/02 21:01

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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/02 17:12

編集2015/04/02 17:14
majiponi

総合スコア1720

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yuragumo

2015/04/04 10:16

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問