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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

1984閲覧

オセロのプログラムがうまく動きません

fuji3131

総合スコア15

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2019/04/24 12:26

編集2019/04/24 13:34

うまく動いてくれません

オセロのプログラムを作ろうとしているのですが、肝心の「石を置き、挟んだ部分をひっくり返す」部分がうまく動いてくれません。
プログラムのエラーは出ないのですが,プログラムに入れたerrorばかり出てうまくいっていないです。

python

1import numpy as np 2 3white = 1 4black = -1 5blank = 0 6tablesize = 8 7class Board(object): 8 # 初期設定 9 def __init__(self): 10 self.cell = np.zeros((tablesize,tablesize)) 11 self.cell = self.cell.astype(int) 12 self.cell[3][3] = self.cell[4][4] = 1 13 self.cell[3][4] = self.cell[4][3] = -1 14 self.current = black 15 16 def turnchange(self): 17 self.current*= -1 18 def stonenumber(self): 19 return self.stones 20 21 def rangecheck(self,x,y): 22 if x<0 or 7<x or y<0 or 7<y: 23 return False 24 return True 25 26 def check_can_reverse(self): # 置けるかどうか 27 for i in range(8): 28 for j in range (8): 29 if not self.rangecheck(i,j): 30 return False 31 elif not self.cell[i][j] ==0: 32 return False 33 elif not self.can_reverse_stone(i,j): 34 return False 35 else: return True 36 37 def can_reverse_one(self,x,y,dx,dy): # 敵石の先に自石があるかどうか 38 length = 0 39 if self.cell[x + dx][y + dy] == 0: 40 print(x + dx, y + dy) 41 return False 42 elif self.cell[x + dx][y + dy] ==self.current: 43 return False 44 else: 45 while self.cell[x+dx][y+dy] == -self.current: 46 x +=dx 47 y +=dy 48 length += 1 49 if self.cell[x+dx][y+dy]== self.current: 50 return True 51 elif self.cell[x +dx][y +dy] ==0: 52 return False 53 continue 54 55 56 57 58 def can_reverse_stone(self,x,y): # 指定座標ではひっくり返せる石はあるか 59 print(x,y) 60 for dx in (-1,0,1): 61 for dy in (-1,0,1): 62 if dx ==dy == 0: continue 63 elif not self.cell[x + dx][y + dy] == 0: 64 continue 65 elif not self.can_reverse_one(x,y,dx,dy): 66 continue 67 else: 68 return True 69 70 def can_put_stone(self,x,y): # 入力座標に石は置けるか 71 if not self.rangecheck(x,y): 72 return False 73 elif not self.cell[x][y] == 0: 74 return False 75 elif not self.can_reverse_stone(x,y): 76 return False 77 else: return True 78 79 def reverse_stone(self,x,y): # 座標に石を置いて石をひっくり返す 80 if self.check_can_reverse(): 81 for dx in (-1,0,1): 82 for dy in (-1,0,1): 83 if self.can_reverse_one(x,y,dx,dy): 84 for k in length: 85 self.cell[x + dx*k][y + dy*k] *= -1 86 else: print('error') 87 88 def display(self): 89 print('--' * 20) 90 for i in range(8): 91 for j in range(8): 92 if self.cell[i][j] == white: 93 print('W', end = ' ') 94 elif self.cell[i][j] == black: 95 print('B', end = ' ') 96 else: 97 print('*', end = ' ') 98 print('\n', end = '') 99 100 def put_stone(self,x,y): 101 if self.can_reverse_stone(x,y): 102 self.reverse_stone(x,y) 103 self.turnchange() 104 else: 105 print('error') 106 107 108 109if __name__ == '__main__' : 110 board = Board() 111 board.display() 112 board.put_stone(3,2) 113 board.put_stone(4,2)

出力結果

python

1---------------------------------------- 2* * * * * * * * 3* * * * * * * * 4* * * * * * * * 5* * * W B * * * 6* * * B W * * * 7* * * * * * * * 8* * * * * * * * 9* * * * * * * * 10error 11error

やってみたこと

挟まれた石を全く選択出来ていないみたいなのですが、ここの改善方法がわかりませんでした。助力いただけると嬉しいです。

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

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

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

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

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

Y.H.

2019/04/24 12:34

> うまくいっていない 具体的に、どうなることを期待し、質問記載のコードで実行するとどうなり、期待した物と実行した物で何が異なっているのかを質問に記載ください。 質問するときのヒント https://teratail.com/help/question-tips を参照されて質問を記載されると回答が得られやすくなりますよ :-)
fuji3131

2019/04/24 13:04

説明不足で申し訳ありません、以後気をつけます... W(白),B(黒),*(blank)を表示する8×8の盤面のオセロを作ってます。上記のソースコードでは初期の盤面(白黒2つずつ)は出ます。しかし、「駒を置き、挟んだ駒をひっくり返す」動作をboard.put_stone(x,y)で書いたつもりなのですが、(x,y)座標を入たら表示されるのはerrorになってしまいます(作動はするのですが、どの座標でもコードに組み込んだerror表示が現れます)。 自分で色々試したところ、ひっくり返す石を見つけるcan_reverse_one関数の部分に問題があるとは思うのですが、そこの部分をどう変えればいいのかがわかりません。
Y.H.

2019/04/24 13:08

質問を編集して質問自体に追記ください。 ここに書かれていても目に付きづらいので、判る方に見てもらえない可能性が高いです。
fuji3131

2019/04/24 13:20

なんどもありがとうございます。 今修正しました!
guest

回答2

0

ベストアンサー

興味が湧いたのでデバッグしてみました。

  1. 確認の順番が「ひっくり返せるか(can_reverse_stone())」→「置けるか(check_can_reverse())」になっていますが逆のほうが適切です。また「置けるか」の中に「ひっくり返せるか」が含まれるため、put_stone()ではcan_reverse_stone()ではなくcheck_can_reverse()で確認するのが良いでしょう。
  2. check_can_reverse()は全座標を対象に置けるか確認しているため、ターン毎の確認としては適切に動作しません。引数にx,yを渡して、その座標について置けるか確認しましょう。
  3. reverse_stone()check_can_reverse()を実行していますが、ひっくり返せるかどうかは確認済みなので、再確認する必要はありません。
  4. reverse_stone()lengthが定義されていないため、最後の石ひっくり返す行でエラーが出ます。can_reverse_one()lengthを返すようにすると良いです。
  5. put_stone()で指定座標に石を置いていません。
  6. display()xyが逆になっています。

以上をまとめると次のようになります。

python

1import numpy as np 2 3white = 1 4black = -1 5blank = 0 6tablesize = 8 7class Board(object): 8 # 初期設定 9 def __init__(self): 10 self.cell = np.zeros((tablesize,tablesize)) 11 self.cell = self.cell.astype(int) 12 self.cell[3][3] = self.cell[4][4] = white 13 self.cell[3][4] = self.cell[4][3] = black 14 self.current = black 15 16 def turnchange(self): 17 self.current*= -1 18 def stonenumber(self): 19 return self.stones 20 21 def rangecheck(self,x,y): 22 if x<0 or tablesize<=x or y<0 or tablesize<=y: 23 return False 24 return True 25 26 def check_can_reverse(self, x, y): # 置けるかどうか 27 if not self.rangecheck(x, y): 28 return False 29 elif not self.cell[x][y] == blank: 30 return False 31 elif not self.can_reverse_stone(x, y): 32 return False 33 else: 34 return True 35 36 def can_reverse_one(self,x,y,dx,dy): # 敵石の先に自石があるかどうか 37 length = 0 38 if self.cell[x + dx][y + dy] == blank: 39 print(x + dx, y + dy) 40 return False 41 elif self.cell[x + dx][y + dy] ==self.current: 42 return False 43 else: 44 while self.cell[x+dx][y+dy] == -self.current: 45 x +=dx 46 y +=dy 47 length += 1 48 if self.cell[x+dx][y+dy]== self.current: 49 return length 50 elif self.cell[x +dx][y +dy] ==blank: 51 return False 52 continue 53 54 def can_reverse_stone(self,x,y): # 指定座標ではひっくり返せる石はあるか 55 print(x,y) 56 for dx in (-1,0,1): 57 for dy in (-1,0,1): 58 if dx ==dy == 0: continue 59 elif self.cell[x + dx][y + dy] == blank: 60 continue 61 elif not self.can_reverse_one(x,y,dx,dy): 62 continue 63 else: 64 return True 65 66 def can_put_stone(self,x,y): # 入力座標に石は置けるか 67 if not self.rangecheck(x,y): 68 return False 69 elif not self.cell[x][y] == blank: 70 return False 71 elif not self.can_reverse_stone(x,y): 72 return False 73 else: return True 74 75 def reverse_stone(self, x, y): # 座標に石を置いて石をひっくり返す 76 for dx in (-1, 0, 1): 77 for dy in (-1, 0, 1): 78 length = self.can_reverse_one(x, y, dx, dy) 79 if length > 0: 80 for l in range(length): 81 k = l+1 82 self.cell[x + dx*k][y + dy*k] *= -1 83 84 def display(self): 85 print('--' * 20) 86 for y in range(tablesize): 87 for x in range(tablesize): 88 if self.cell[x][y] == white: 89 print('W', end = ' ') 90 elif self.cell[x][y] == black: 91 print('B', end = ' ') 92 else: 93 print('*', end = ' ') 94 print('\n', end = '') 95 96 def put_stone(self,x,y): 97 if self.check_can_reverse(x,y): 98 self.cell[x][y] = self.current 99 self.reverse_stone(x,y) 100 self.turnchange() 101 else: 102 print('error') 103 104 105 106if __name__ == '__main__' : 107 board = Board() 108 board.display() 109 board.put_stone(3,2) 110 board.put_stone(4,2) 111 board.display()

output

1* * * * * * * * 2* * * * * * * * 3* * * B W * * * 4* * * B W * * * 5* * * B W * * * 6* * * * * * * * 7* * * * * * * * 8* * * * * * * *

コード中でマジックナンバー(1-1, 7)を多用していますが、せっかくwhite=1,black=-1,tablesize=8を定義しているのですからこれを使いましょう。
可読性に繋がり、バグを抑えられますよ。

投稿2019/04/25 01:18

編集2019/04/25 01:23
y.nakamura

総合スコア190

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

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

fuji3131

2019/04/25 03:08

回答に加えてアドバイスまでしていただき、ありがとうございます!きちんと動きました!
guest

0

ちょっと試しただけなんで答えになるか?
ここでブレークした
ブレーク貼ったらここで止まりました。(まだ先は見ていません)

投稿2019/04/24 13:24

cateye

総合スコア6851

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

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

fuji3131

2019/04/24 13:33

オセロであるなら入力座標のどちらか1つ(たぶん(3,2)の方)はerrorで止まるのではなくその上のifの方に動くつもりで作ったのですが、両方ともerrorの方に行ってしまいます。 敵石検知の部分が問題だと思うのですが...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問