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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

869閲覧

[初心者]c言語でオセロを作成中の問題

ka-kosya19212

総合スコア2

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2021/09/16 12:36

編集2021/09/16 13:17

前提・実現したいこと

c言語でオセロを作成中の初心者です。ひととおり全体的な枠組みは完成したのですが、うまく挙動しません。
オセロで相手のコマをひっくり返すところがうまくいってないとは思うのですが、どこを改善すればよいのかわからないので教えてほしいです。

発生している問題・エラーメッセージ

put_checkという関数の部分がおかしいのだと思いますが、自分ではどこをかえたらいいのかわからないので教えてほしいです。よろしくお願いします。 所々いらないことを書いている部分もあるとは思うのですが、とりあえずひととり動くものを作りたいです。 ↓実行結果 自分のコマ(このコードではw固定)を置く位置を入力したあと、きちんと置かれず、謎の数字が一番上に追加されます。 12345678 1........ 2........ 3........ 4...wb... 5...bw... 6........ 7........ 8........ 0 あなたのターンです。 縦方向3 横方向5 1234119678 1........ 2........ 3........ 4...wb... 5...bw... 6........ 7........ 8........

該当のソースコード

C

1#include<stdio.h> 2#include<stdlib.h> 3#include<time.h> 4#define WHITE 1 5#define BLACK 2 6char board[9][9]; 7int turn;//自分のターン 8int sentaku; 9int i_put,j_put; 10int bamen_sentaku=1; 11//char o,a;//oは敵,aは自分 12void shokika(){ 13 board[0][0]=' '; 14 for(int a=1;a<9;a++){ 15 board[0][a]=a; 16 board[a][0]=a; 17 } 18 for(int i=1;i<9;i++){ 19 for(int j=1;j<9;j++){ 20 board[i][j]='.'; 21 } 22 23 } 24 board[4][4]=board[5][5]='w';//一旦wは自分,bが敵だとする 25 board[4][5]=board[5][4]='b'; 26} 27 28void display(){ 29 30 for(int i=0;i<9;i++){ 31 for(int j=0;j<9;j++){ 32 if(j==0&&i==0){ 33 printf("%c",board[i][j]); 34 }else if(j==0||i==0){//盤面の数字の部分はint型 35 printf("%d",board[i][j]); 36 }else{ 37 printf("%c",board[i][j]); 38 } 39 } 40 printf("\n"); 41 } 42 43} 44void shouhai(){ 45 int w_number=0; 46 int b_number=0; 47 int sum=0; 48 for(int i=1;i<9;i++){ 49 for(int j=1;j<9;j++){ 50 if(board[i][j]=='w'){ 51 ++w_number; 52 }else if(board[i][j]=='b'){ 53 ++b_number; 54 } 55 } 56 } 57 if(sum==64){ 58 printf("白%d枚、黒%d枚\n",w_number,b_number); 59 if(w_number==b_number){ 60 printf("引き分けです\n"); 61 }else if(w_number<b_number){ 62 printf("あなたの勝利です\n"); 63 }else{ 64 printf("あなたの敗北です\n"); 65 } 66 } 67} 68 69int num_kaeseru(int x,int y,int iro){//そこに打つといくつ返せるか 70 if(board[y][x]!='.'){ 71 return -1; 72 } 73 char my_iro; 74 char aite_iro; 75 if(iro==1){//自分の色がwなら 76 my_iro ='w'; 77 aite_iro ='b'; 78 }else{ 79 aite_iro = 'w'; 80 my_iro = 'b'; 81 } 82 int total=0; 83 for(int dy=-1;dy<=1;dy++){ 84 for(int dx=-1;dx<=1;dx++){ 85 int sx,sy; 86 int k=0;//めくる枚数 87 sx = x; 88 sy = y; 89 while(1){ 90 sx += dx; 91 sy += dy; 92 if(sx<=0 || sy<=0 || sx>8 || sy>8){//盤面を超えたら 93 break; 94 } 95 if(board[sy][sx]=='.'){ 96 break; 97 } 98 if(board[sy][sx]==aite_iro){ 99 k += 1; 100 } 101 if(board[sy][sx]==my_iro){ 102 total += k; 103 break; 104 } 105 } 106 } 107 } 108 return total; 109} 110 111void put_check(int x,int y,int iro){//iroは自分の色 112char my_iro; 113char aite_iro; 114if(iro==1){ 115 my_iro ='w'; 116 aite_iro ='b'; 117}else{ 118 my_iro ='b'; 119 aite_iro ='w'; 120} 121 for(int dy=-1;dy<=1;dy++){ 122 for(int dx=-1;dx<=1;dx++){ 123 int sx,sy; 124 int k=0;//めくる枚数 125 sx = x; 126 sy = y; 127 while(1){ 128 sx += dx; 129 sy += dy; 130 if(sx<=0 || sy<=0 || sx>8 || sy>8){//盤面を超えたら 131 break; 132 } 133 if(board[sy][sx]=='.'){ 134 break; 135 } 136 if(board[sy][sx]==aite_iro){ 137 k += 1; 138 } 139 if(board[sy][sx]==my_iro){ 140 for(int i=0;i<k;i++){//めくる作業 141 sx -= dx; 142 sy -= sy; 143 board[sy][sx]=my_iro; 144 } 145 break; 146 } 147 } 148 } 149 } 150} 151 152void put(){ 153 while(1){ 154 printf("あなたのターンです。\n"); 155 printf("縦方向"); scanf("%d",&j_put); 156 printf("横方向"); scanf("%d",&i_put); 157 if(num_kaeseru(i_put,j_put,WHITE)>0){ 158 break; 159 } 160 } 161 put_check(i_put,j_put,WHITE); 162} 163 164int uteru_masu(int iro){ 165 for(int y=1;y<=8;y++){ 166 for(int x=1;x<=8;x++){ 167 if (num_kaeseru(x,y,iro)>0){ 168 return 1;//1=打てるマスあり 169 } 170 } 171 } 172 return 2;//打てるマスなし 173} 174 175void computer_1(){ 176 int c_x,c_y;//コンピュータが置く位置 177 srand((unsigned int)time(NULL)); 178 while(1){ 179 c_x = rand()%8+1; 180 c_y = rand()%8+1; 181 if(num_kaeseru(c_x,c_y,BLACK)>0){ 182 break; 183 } 184 } 185 put_check(c_x,c_y,2); 186} 187void menu(){ 188 while(1){ 189 if(bamen_sentaku==1){ 190 printf("/////////////////オセロ/////////////////\n"); 191 //printf("ゲームモードを選択してください//なお2Pゲームしか実装されていない模様\n"); 192 //printf("1Pゲーム ---1\n2Pゲーム ---2\n --->"); scanf("%d",&sentaku); 193 shokika(); 194 display(); 195 printf("%d\n",num_kaeseru(5,1,1)); 196 bamen_sentaku=2; 197 }else if(bamen_sentaku==2){ 198 put(); 199 display(); 200 bamen_sentaku=3; 201 }else if(bamen_sentaku==3){ 202 computer_1(); 203 display(); 204 bamen_sentaku=4; 205 }else if(bamen_sentaku==4){ 206 if(uteru_masu(WHITE)==2 && uteru_masu(BLACK)==2){ 207 printf("試合終了です"); 208 bamen_sentaku=5; 209 }else if(uteru_masu(WHITE)==2 && uteru_masu(BLACK)==1){ 210 printf("あなたは打てないのでパスです\n"); 211 bamen_sentaku=3; 212 }else if(uteru_masu(WHITE)==1 && uteru_masu(BLACK)==2){ 213 printf("コンピュータが打てるコマがないのでパス。\n"); 214 }else{ 215 bamen_sentaku=2; 216 } 217 }else if(bamen_sentaku==5){ 218 shouhai(); 219 break; 220 } 221 } 222} 223 224int main(){ 225 menu(); 226 return 0; 227}

試したこと

このコードを実行したところ、コマを置く位置を指定したときに、カードがうまくいかず、おかしな挙動をします。pythonゲームアルゴリズム入門という書籍を参考しつつ、c言語で作ってみようとしているのですが、うまく行かないので、改善点を教えてほしいです。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

thkana

2021/09/16 12:46

漠然と「うまく挙動しません」「おかしな挙動をします」というのではなく、 ・こういう動作を期待して ・こういうプログラムを組んだ(この部分はありますが)ら ・期待と違う、こういうことが起こった という「観察できる事実」を具体的に書いてください。そうでないと、回答者はあなたのプログラムを全部チェックしなければならなくなります。
tatsu99

2021/09/16 12:53

computer_1(); は computer_LV1(); の間違いでしょうか。提示されたソースをコンパイルすると、 computer_1でエラーになります。
jimbe

2021/09/16 12:54

全然ご質問に関係無く「どうでもいい」と言われそうですが、変数名や関数名に英語とローマ字日本語を混在させないで頂きたいです。
ka-kosya19212

2021/09/16 13:08 編集

tatsu99様 コードを修正いたしました。
ka-kosya19212

2021/09/16 13:18 編集

jimbe様 基本的にはpythonのゲームプログラミングの本の関数の名前をそのままつかっています。 混在しないほうがいいのは、そのとおりだと思うのであとで改善したいと思います。
ka-kosya19212

2021/09/16 13:18

thkana様 実行結果を載せました。
jimbe

2021/09/16 13:34

> 本の関数の名前をそのままつかっています 駄文に返信ありがとうございます、了解です。 python では有りなのでしょうけれど、なんともまぁ。
guest

回答2

0

見た感じ、ここじゃないでしょうか。

c

1 for(int i=0;i<k;i++){//めくる作業 2 sx -= dx; 3 sy -= sy; //!!!!! 4 board[sy][sx]=my_iro; 5 }

弄ってみました。
置ける場所等を何度も探すのを避けるため、points 配列を用意しました。
Delta 構造体と Point 構造体が同じですが、まぁ雰囲気ということで。

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <memory.h> 4#include <time.h> 5#include <stdarg.h> 6 7#define WHITE 'w' 8#define BLACK 'b' 9#define SPACE '.' 10 11#define TRUE 1 12#define FALSE 0 13 14#define SIZE 8 15 16#ifndef NULL 17#define NULL ((void)0) 18#endif 19 20char board[SIZE][SIZE]; 21 22//初期化 23void init(){ 24 srand((unsigned int)time(NULL)); 25 26 memset(board, SPACE, sizeof(board)); 27 board[SIZE/2-1][SIZE/2-1]=board[SIZE/2][SIZE/2]=WHITE;//一旦wは自分,bが敵だとする 28 board[SIZE/2-1][SIZE/2]=board[SIZE/2][SIZE/2-1]=BLACK; 29} 30 31//盤面表示 32void print(){ 33 printf(" "); 34 for(int x=0; x<SIZE; x++){ 35 printf("%d", x+1); 36 } 37 printf("\n"); 38 for(int y=0; y<SIZE; y++){ 39 printf("%d", y+1); 40 for(int x=0; x<SIZE; x++){ 41 printf("%c", board[y][x]); 42 } 43 printf("\n"); 44 } 45} 46 47//結果 48void judgement(){ 49 int w_count = 0; 50 int b_count = 0; 51 for(int y=0; y<SIZE; y++){ 52 for(int x=0; x<SIZE; x++){ 53 if(board[y][x] == WHITE){ 54 ++w_count; 55 } else if(board[y][x] == BLACK){ 56 ++b_count; 57 } 58 } 59 } 60 61 printf("白%d枚、黒%d枚\n",w_count, b_count); 62 if(w_count == b_count){ 63 printf("引き分けです\n"); 64 }else if(w_count > b_count){ 65 printf("あなたの勝利です\n"); 66 }else{ 67 printf("あなたの敗北です\n"); 68 } 69} 70 71//8方向 72typedef struct Delta { int x, y; } Delta; 73Delta deltas[] = { 74 {-1,-1}, {0,-1}, {1,-1}, 75 {-1, 0}, {1, 0}, 76 {-1, 1}, {0, 1}, {1, 1} 77}; 78 79//座標保持用バッファ 80typedef struct Point { int x, y; } Point; 81Point points[SIZE*SIZE]; 82 83//x,y に打った場合にひっくり返せる数を返す. 84//keepPoints に TRUE を指定すると, ひっくり返せる各座標を points に格納する. 85int acquiredPoints(int x, int y, int color, int keepPoints){ 86 int total = 0; 87 if(board[y][x] != SPACE) return total; 88 89 for(int i=0; i<sizeof(deltas)/sizeof(Delta); i++) { 90 Delta *d = &deltas[i]; 91 92 for(int sx=x+d->x, sy=y+d->y, count=0; 93 sx>=0 && sy>=0 && sx<SIZE && sy<SIZE && board[sy][sx]!=SPACE; 94 sx+=d->x, sy+=d->y, count++){ 95 if(board[sy][sx] == color) { //挟める 96 total += count; 97 break; 98 } 99 if(keepPoints) { 100 points[total + count].x = sx; 101 points[total + count].y = sy; 102 } 103 } 104 } 105 return total; 106} 107 108//x,y と points の各座標に color を設定する. 109void acquired(int x, int y, int total, int color) { 110 board[y][x] = color; 111 for(int i=0; i<total; i++) { 112 board[points[i].y][points[i].x] = color; 113 } 114} 115 116//打てる各座標を points に格納しその件数を返す. 117int availablePoints(int color) { 118 int count = 0; 119 for(int y=0; y<SIZE; y++){ 120 for(int x=0; x<SIZE; x++){ 121 if(acquiredPoints(x, y, color, FALSE) > 0) { 122 points[count].x = x; 123 points[count].y = y; 124 count ++; 125 } 126 } 127 } 128 return count; 129} 130 131int input(int min, int max, char *fmt, ...) { 132 int v; 133 va_list arg_ptr; 134 do { 135 va_start(arg_ptr, fmt); 136 vprintf(fmt, arg_ptr); 137 va_end(arg_ptr); 138 139 scanf("%d",&v); 140 } while(v < min || max < v); 141 return v; 142} 143 144void turnPlayer(int color){ 145 int count = availablePoints(color); 146 if(count == 0) { 147 printf("あなたは打てないのでパスです\n"); 148 return; 149 } 150 151 int x, y, total; 152 printf("あなた('%c')のターンです。\n", color); 153 while(1) { 154 x = input(1, SIZE, "横方向(x:1-%d)", SIZE); 155 y = input(1, SIZE, "縦方向(y:1-%d)", SIZE); 156 if(x>=1 && y>=1 && x<=SIZE && y<=SIZE && (total = acquiredPoints(x-1, y-1, color, TRUE)) > 0){ 157 acquired(x-1, y-1, total, color); 158 print(); 159 return; 160 } 161 printf("そこには打てません。\n"); 162 } 163} 164 165void turnComputer(int color) { 166 int count = availablePoints(color); 167 if(count == 0) { 168 printf("コンピュータが打てるコマがないのでパス。\n"); 169 return; 170 } 171 172 Point point = points[rand() % count]; //コピー 173 int total = acquiredPoints(point.x, point.y, color, TRUE); 174 acquired(point.x, point.y, total, color); 175 printf("コンピュータ('%c')は x%d,y%d に打ちました。\n", color, point.x+1, point.y+1); 176 print(); 177} 178 179int main(){ 180 printf("/////////////////オセロ/////////////////\n"); 181 init(); 182 print(); 183 184 while(1) { 185 turnPlayer(WHITE); 186 turnComputer(BLACK); 187 188 if(!availablePoints(WHITE) && !availablePoints(BLACK)){ 189 break; 190 } 191 } 192 193 printf("試合終了です\n"); 194 judgement(); 195 return 0; 196}

投稿2021/09/16 13:37

編集2021/09/17 16:10
jimbe

総合スコア12754

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

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

ka-kosya19212

2021/09/16 13:52

コードを書き換えたら正しく動作するようになりました。返信ありがとうございました。
jimbe

2021/09/16 14:15

念の為、teratail はバグを取ってもらう所ではありませんので、ご留意ください。
guest

0

ベストアンサー

C

1void put_check(int x,int y,int iro){//iroは自分の色 2 char my_iro; 3 char aite_iro; 4 5 if(iro==1){ 6 my_iro ='w'; 7 aite_iro ='b'; 8 }else{ 9 my_iro ='b'; 10 aite_iro ='w'; 11 } 12 13 board[y][x]=my_iro; //----追加---- (x,y) に my_iro を置く 14 15 for(int dy=-1;dy<=1;dy++){ 16 for(int dx=-1;dx<=1;dx++){ 17 int sx,sy; 18 int k=0;//めくる枚数 19 sx = x; 20 sy = y; 21 while(1){ 22 sx += dx; 23 sy += dy; 24 if(sx<=0 || sy<=0 || sx>8 || sy>8){//盤面を超えたら 25 break; 26 } 27 if(board[sy][sx]=='.'){ 28 break; 29 } 30 if(board[sy][sx]==aite_iro){ 31 k += 1; 32 } 33 if(board[sy][sx]==my_iro){ 34 for(int i=0;i<k;i++){//めくる作業 35 sx -= dx; 36 sy -= dy; //----修正--- sy -= sy; になっちゃってますよ 37 board[sy][sx]=my_iro; 38 } 39 break; 40 } 41 } 42 } 43 } 44}

ですね。

2点あって、めくる前に、そもそもboard[y][x]の自分の石を置かないといけません。

C

1board[y][x]=my_iro;

それから、

C

1sy -= dy;

ですね。ベクトル (dx,dy) は、置いた石から検査する方向を示しています。
自分の石がみつかったら、バックして元の石までひっくり返す、ということを
していますね。おそらく -sy は打ち間違いだと思いますが。

初心者とは思えません。プログラムは綺麗だと思いました。

投稿2021/09/16 13:35

ak.n

総合スコア291

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

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

ka-kosya19212

2021/09/16 13:54

そのとおりに書き換えたら正しく動作するようになりました!わざわざ丁寧にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問