〇×ゲームに続き、Pythonでオセロづくりに挑戦。
COM側をつくるにあたり、以前、プチコンBASICで作った自作のOshello(オシェロ)のプログラムを見直してみた。(自作でありながら、それは最初とても困難なことであった)
それは、取れる駒に加えて取られる駒を考慮するというものだったが、あまりうまくいっておらず、実際のところ全然強くなかった。
その時は、とりあえず動いていたし、そのままにしてしまったが、今回は、試行錯誤の末に、とにかく取り返される駒が少ない手を選択するというふうに改良してみた。
最初は、ひいき目に「強くなったのでは!?」とぬか喜びしたのだったが、いずれそうでもない事が発覚する・・・。
参考にしているのが自作のプログラムだけってところが一番の問題点かもね?
※盤の情報をコピーするのに、コピーの関数が用意されているみたいだったが、やってみたらエラーが出て他のことが進まなくなってしまったので、単純にfor文で代入している。
【遊び方】
毎回、ランダムに先手後手が決まります。必ず先手が黒、後手が白。
マウスで駒を置く場所をクリックしてください。
一瞬で駒が返るので、返った駒は縁が黄色で表示され、駒の置かれた位置は盤に割りふられた数字(横/縦0~7)で確認出来ます。
プレイヤーのパスも自動で判断し(駒を置ける場所がない)、盤が埋まるか両者パスで終了。
しばらく待つか画面をクリックすると再びゲームがはじまります。
【リスト】
# オセロ 2020の晩夏 by kameyoko
import tkinter
import random
# 変数、リスト設定
BOARD = []
BOARD_C = []
for i in range(8):
BOARD.append([0]*8)
BOARD_C.append([0]*8)
fnt = ["Time New Roman", 16]
P_COL = [None,"black", "white"]
O_COL = ["black","yellow"]
SYM = [None,"黒","白"]
SCORE = [ 0, 0, 0]
CT = [ 0, 0, 0]
MSG = ["あなたの負けです",
"引き分けです" ,
"あなたの勝ちです"
]
ms_y = 0
ms_x = 0
ms_c = 0
# マウス関係
def ms_move(e):
global ms_y, ms_x
ms_y = e.y
ms_x = e.x
def ms_click(e):
global ms_c
ms_c = 1
def ms_release(e):
global ms_c
ms_c = 0
def dsp_board(): # 盤を表示
cvas.delete("GR")
cvas.create_rectangle(40, 40, 360, 360, fill="green", outline="black", width=3, tag="GR")
for i in range(1, 8):
cvas.create_line(40+40*i, 40, 40+40*i, 360, fill="black", width=3, tag="GR")
cvas.create_line(40, 40+40*i, 360, 40+40*i, fill="black", width=3, tag="GR")
for y in range(8):
for x in range(8):
if BOARD[y][x] > 0:
dsp_piece(x, y, BOARD[y][x])
cvas.update()
copy_board()
def dsp_piece(x, y, e): # 駒を表示
a = (BOARD[y][x] != BOARD_C[y][x])
cvas.create_oval(40+40*x+10, 40+40*y+10, 40+40*x+30, 40+40*y+30, fill=P_COL[e], outline=O_COL[a], width=2, tag="GR")
def init_board(): # 盤の初期化
global turn, tmr, pl, p1, p2
turn = 1
tmr = 0
p1 = 0
p2 = 0
for y in range(8):
for x in range(8):
BOARD[y][x] = 0
BOARD[3][3] = 1
BOARD[4][3] = 2
BOARD[3][4] = 2
BOARD[4][4] = 1
copy_board()
dsp_board()
cvas.delete("TX1","TX3","TX4","TX5","TX6")
for i in range(8):
cvas.create_text(60+i*40, 20, text=str(i), fill="black", font=fnt, tag="TX1")
cvas.create_text(20, 60+i*40, text=str(i), fill="black", font=fnt, tag="TX1")
pl = random.randint(1,2)
dsp_msg(200, 380, "あなたは"+SYM[pl]+"です","TX2")
def check_piece(bx, by, e, f): # 駒のチェック
cc = 0
for i in range(-1, 2):
for j in range(-1, 2):
if i!=0 or j!=0:
c = 1
while 0 <= by+i*c and by+i*c < 8 and 0 <= bx+j*c and bx+j*c < 8:
if BOARD[by+i*c][bx+j*c] == e:
if c > 1:
cc += c-1
for k in range(1,c):
cc += (by+i*k == 0 or by+i*k == 7 or bx+j*k == 0 or bx+j*k == 7)*9
if f == 1: BOARD[by+i*k][bx+j*k] = e
break
elif BOARD[by+i*c][bx+j*c] == 0: break
else: c += 1
if cc > 0 and f == 1: BOARD[by][bx] = e
return cc
def player(): # プレイヤー処理
global ms_y, ms_x, ms_c, turn, p1
p1 = 0
c = 0
for y in range(8):
for x in range(8):
if BOARD[y][x] == 0:
a = check_piece(x, y, turn, 0)
if a > c: c = a
if c > 0:
if ms_c == 1:
if 40 <= ms_y and ms_y < 360 and 40 <= ms_x and ms_x < 360:
y = int((ms_y-40)/40)
x = int((ms_x-40)/40)
if BOARD[y][x] == 0:
a = check_piece(x, y, turn, 1)
if a > 0:
dsp_board()
dsp_msg(100+(turn-1)*200,400,SYM[turn] + ":{}/{}".format(x, y),"TX3")
turn = turn ^ 3
else:
dsp_msg(100+(turn-1)*200,400,SYM[turn] + ":パス","TX3")
p1 = 1
turn = turn ^ 3
def com(): # COM処理
global turn, p2
pt = 300
cy = 0
cx = 0
for y1 in range(8):
for x1 in range(8):
if BOARD[y1][x1] == 0:
c1 = check_piece(x1, y1, turn, 1)
if c1 > 0:
if (y1 == 0 or y1 == 7) and (x1 == 0 or x1 == 7): lt = -300-c1 # 四隅優先
else: # 置いた場合の取られる駒を計算
lt = 0
for y2 in range(8):
for x2 in range(8):
if BOARD[y2][x2] == 0:
c2 = check_piece(x2, y2, turn ^ 3, 0)
if c2 > 0:
c2 += (y2 == 0 or y2 == 7)*10 + (x2 == 0 or x2 == 7)*10
lt += c2
if lt == 0: # 相手がパスになる場合
c1 +=(y1 == 0 or y1 == 0)*10 + (x1 == 0 or x1 == 7)*10
lt = -c1
past_board()
if lt < pt: # 取られる駒が少ない手を選択
pt = lt
cy = y1
cx = x1
elif lt == pt and random.randint(1,10) < 5:
cy = y1
cx = x1
if pt < 300:
check_piece(cx, cy, turn, 1)
dsp_board()
dsp_msg(100+(turn-1)*200,400,SYM[turn] + ":{}/{}".format(cx, cy),"TX4")
p2 = 0
else:
dsp_msg(100+(turn-1)*200,400,SYM[turn] + ":パス","TX4")
p2 = 1
turn = turn ^ 3
def copy_board(): # 盤のコピー
for i in range(8):
for j in range(8):
BOARD_C[i][j] = BOARD[i][j]
def past_board(): # 盤を戻す
for i in range(8):
for j in range(8):
BOARD[i][j] = BOARD_C[i][j]
def count_board(): # 駒のカウント
global pl
CT[1] = 0
CT[2] = 0
for y in range(8):
for x in range(8):
CT[BOARD[y][x]] += 1
w = 1 + (CT[pl] > CT[pl ^ 3]) - (CT[pl] < CT[pl ^ 3])
msg2 = MSG[w]
SCORE[w] += 1
msg1 = "黒{} 白{}".format(CT[1],CT[2])
cvas.delete("TX3","TX4")
dsp_msg(200, 420, msg1, "TX5")
dsp_msg(200, 440, msg2, "TX6")
dsp_score()
def dsp_msg(x, y, txt,tg): # メッセージ表示
cvas.delete(tg)
cvas.create_text(x, y, text=txt, fill="black", font=fnt, tag=tg)
cvas.update()
def dsp_score(): dsp_msg(200, 460, "{}勝{}敗{}分".format(SCORE[2],SCORE[0],SCORE[1]), "TX7") # スコア表示
def game_main(): # メイン処理
global turn,tmr, p1, p2, pl
if tmr == 0:
if turn == pl: player()
else: com()
if p1 == 1 and p2 == 1:
count_board()
tmr = 450
else:
tmr = tmr - 1
if tmr ==0 or ms_c == 1: init_board()
root.after(100, game_main)
# 初期設定
root = tkinter.Tk()
root.title("オセロ")
root.resizable(False, False)
root.bind("<Motion>", ms_move)
root.bind("<ButtonPress>", ms_click)
root.bind("<ButtonRelease>", ms_release)
cvas = tkinter.Canvas(root, width=400, height=480, bg="white")
cvas.pack()
init_board()
game_main()
cvas.mainloop()
※コメント投稿者のブログIDはブログ作成者のみに通知されます