こんにちは、コンテンツクリエイターのともすけです。
以下の仕様で実装した、なんちゃってオセロのコードを公開します。コードは最適化されていませんので、ご了承の上ご覧ください。貼り付けたコードは、念のためここからコピペしても動作することを確認済みです。
- 必ず白から始まります。
- 相手が置けなかったとき、再度自分の番となるようにしたつもりです。
- 両方手詰まりとなったときを考慮したつもりです。
- AIは組み込んでいません。
- GUIを使うので、tkinterを使用しています。
- 動作確認は、 windows版python3.7をインストールし、cygwinで動かしています。
import tkinter as tk
import time # 石をめくる速度を変えようと思って入れましたが、うまくいかず
# -*- coding: utf-8 -*-
color = 1
# 座標とベクトルを格納するためのクラス
class Position:
def __init__(self,x,y,dx,dy):
self.x = x+dx
self.y = y+dy
self.dx = dx
self.dy = dy
def checkZero(a,b):
if a==0:
return 0
else:
return b
def clearMap(target):
global mark_map, reserve_map
for x in range(8):
for y in range(8):
if target==0:
mark_map[x][y] = 0
else:
reserve_map[x][y] = 0
def reverse():
if color==1:
return 2
else:
return 1
def getColor(color):
if color==1:
return "white"
elif color==2:
return "black"
else:
return "no stone"
def same(a,b):
if a==b:
return True
else:
return False
#このプログラムのメインです。クリックしたところに置けるか判定します
def okeruka(mine, pos, flag, indent):
global stone_db
global reserve_map
global mark_map
ret = -10
dx_list = [-1,0,1]
dy_list = [-1,0,1]
print("{}x={}, y={}, stone={}".format(indent, pos.x, pos.y, getColor(stone_db[pos.x][pos.y])))
indent += " "
if stone_db[pos.x][pos.y]==0 and flag==0:
mark_map[pos.x-1][pos.y-1] = 1
for dx in dx_list:
for dy in dy_list:
if dx==0 and dy==0:
continue
_pos = Position(pos.x, pos.y, dx, dy)
ret = checkZero(ret, okeruka(mine, _pos, 1, indent))
else:
if stone_db[pos.x][pos.y]==0 or stone_db[pos.x][pos.y]==-1: # 石がない
clearMap(1)
return -1
else: # 石がある
if flag==1: # 同色はダメ、異色はOK
if stone_db[pos.x][pos.y]==mine: # 同色
return -2
else:
_pos = Position(pos.x, pos.y, pos.dx, pos.dy)
reserve_map[pos.x-1][pos.y-1] = 1
ret = okeruka(mine, _pos, 2, indent)
elif flag==2: # 同色、異色どちらもOK
if stone_db[pos.x][pos.y]==mine:
for i in range(8):
for j in range(8):
if reserve_map[i][j]==1:
#mark_map[i][j] = reserve_map[i][j]
mark_map[i][j] = 1
print("reserve_map")
for y in range(8):
for x in range(8):
print("{} ".format(reserve_map[x][y]), end="")
print("")
clearMap(1) # clear reserve_map
return 0
else:
_pos = Position(pos.x, pos.y, pos.dx, pos.dy)
reserve_map[pos.x-1][pos.y-1] = 1
ret = okeruka(mine, _pos, 2, indent)
return ret
# 石を置くためのメソッドです
def placeStone(x,y,color):
canvas.create_oval(offset_x+pitch*x+margin, offset_y+pitch*y+margin,
offset_x+pitch*(x+1)-margin, offset_y+pitch*(y+1)-margin,
fill = color)
print("write ({},{})".format(x,y))
def drawStone(mode):
global stone_db, mark_map
global stone_status
global finish, finish2
black = 0
white = 0
if mode==0:
for x in range(8):
for y in range(8):
if stone_db[x+1][y+1]==1:
placeStone(x, y, "white")
elif stone_db[x+1][y+1]==2:
placeStone(x, y, "black")
else:
for x in range(8):
for y in range(8):
if mark_map[x][y]==1:
if stone_db[x+1][y+1]==1:
placeStone(x, y, "white")
elif stone_db[x+1][y+1]==2:
placeStone(x, y, "black")
#time.sleep(1)
for x in range(8):
for y in range(8):
if stone_db[x+1][y+1]==1:
white += 1
elif stone_db[x+1][y+1]==2:
black += 1
stone_status.set("白:{}, 黒:{}".format(white,black))
if (white+black)==64 or finish2==1:
finish = 1
if white > black:
judge_text.set("白の勝ちです")
elif black > white:
judge_text.set("黒の勝ちです")
else:
judge_text.set("引き分けです")
def on_click(event):
global finish, finish2
global color
global mark_map, stone_db
global next_user
if finish==1:
return 0
x = event.x
y = event.y
click_x = -1
click_y = -1
for i in range(8):
for j in range(8):
if x >= (offset_x + i*pitch + margin) and x <= (offset_x + (i+1)*pitch - margin) and \
y >= (offset_y + j*pitch + margin) and y <= (offset_y + (j+1)*pitch - margin):
click_x = i+1
click_y = j+1
break
pos = Position(click_x, click_y, 0, 0)
ret = okeruka(color, pos, 0, "")
if ret==0:
print("x={}, y={}, can place".format(click_x, click_y))
print("--- mark_map ---")
for y in range(8):
for x in range(8):
print("{} ".format(mark_map[x][y]), end="")
if mark_map[x][y]==1:
stone_db[x+1][y+1] = color
#print("x={}, y={}, placed {}".format(x+1,y+1,getColor(color)))
print("")
drawStone(1)
color = reverse()
if color==1:
next_user.set("白の番です")
else:
next_user.set("黒の番です")
print("next color is {}".format(getColor(color)))
else:
print("x={}, y={}, ret={}, cannot place".format(click_x, click_y, ret))
clearMap(0)
clearMap(1)
ret = -1
for x in range(8):
for y in range(8):
pos = Position(x+1, y+1, 0, 0)
ret = checkZero(ret, okeruka(color, pos, 0, ""))
clearMap(0)
clearMap(1)
if ret==0: # 相手の石は置ける
pass
else: # 相手の石は置けないので、自分の石が置けるか確認
ret = -1
color = reverse()
for x in range(8):
for y in range(8):
pos = Position(x+1, y+1, 0, 0)
ret = checkZero(ret, okeruka(color, pos, 0, ""))
clearMap(0)
clearMap(1)
if ret==0:
if color==1:
next_user.set("黒が置けないので、白の番です")
else:
next_user.set("白が置けないので、黒の番です")
else:
finish2 = 1
drawStone(1) # 石の状態をチェックさせる(途中終了)
### start
offset_x = 10
offset_y = 10
margin = 10
pitch = 10
root = tk.Tk()
root.title("オセロ")
canvas = tk.Canvas(root, width = 700, height = 700)
canvas.pack()
canvas.bind("<Button-1>",on_click)
### label
next_user = tk.StringVar()
label = tk.Label(root, textvariable=next_user)
label.place(x=10, y=660)
next_user.set("白の番です")
stone_status = tk.StringVar()
label2 = tk.Label(root, textvariable=stone_status)
label2.place(x=200, y=660)
judge_text = tk.StringVar()
label3 = tk.Label(root, textvariable=judge_text)
label3.place(x=400, y=660)
### status
finish = 0 # 通常の終了フラグ
finish2 = 0 # 途中の終了フラグ
# 盤面描画
offset_x = 10
offset_y = 10
pitch = 80
_width = 0.0
for i in range(9):
if i==0 or i==8:
_width = 3.0
else:
_width= 1.0
canvas.create_line(offset_x, offset_y + i*pitch,
offset_x + pitch*8, offset_y + i*pitch,
width = _width)
canvas.create_line(offset_x + i*pitch, offset_y,
offset_x + i*pitch, offset_y + pitch*8,
width = _width)
### 石の配置
# -1 エリア外
# 0 何も置いてない
# 1 白
# 2 黒
stone_db = [[0] * 10 for i in range(10)] # とりあえず全面「何も置いてない」
mark_map = [[0] * 8 for i in range(8)] # 石を置き換えるデータマップ
reserve_map = [[0] * 8 for i in range(8)] # 仮の、石を置き換えるデータマップ
#print("DBG(0) : mark_map.id={}".format(id(mark_map)))
for x in range(10):
for y in range(10):
if x==0 or x==9 or y==0 or y==9:
stone_db[x][y] = -1
if (x==4 and y==4) or (x==5 and y==5):
stone_db[x][y] = 1
if (x==4 and y==5) or (x==5 and y==4):
stone_db[x][y] = 2
### 最初の石の配置
#placeStone(3,3,"black")
#placeStone(4,4,"black")
#placeStone(4,3,"white")
#placeStone(3,4,"white")
drawStone(0)
root.mainloop()
