我有两个文件用于python 3的可逆游戏。我的第一个文件叫做reverse.py。它实现了(a)对游戏的高级控制(例如,从计算机玩家和人类玩家那里获得动作,确定玩家是否用完了动作,确定游戏结束并宣布游戏结果),(b)通过QuickDraw渲染游戏,以及(c)从人类玩家那里获取输入。
这是文件:
from game import *
from copy import deepcopy
from time import sleep
import sys
from subprocess import PIPE,Popen
from threading import Thread
from queue import Queue,Empty
def ParseEvent() :
r=receive()
if r==None:return None,None
s=[x.rstrip().strip() for x in r.split(":")]
return s[0],s[1]
def highlight(move):
send( 'color 255 0 0n circle %d %d 11n' %
(240+(move[0]+0.5)*40, 100+(move[1]+0.5)*40))
def stone(x,y,turn):
send('color %d %d %dn' %
(255*(1-turn),255*(1-turn),255*(1-turn)))
send('fillcircle %d %d %dn' %
(240+(x+0.5)*40, 100+(y+0.5)*40, 17))
def draw(board):
send('color 20 20 20n clearn color 15 15 100n')
send( 'button button1 600 20 100 20 "Calculate W:L"')
send('fillrect %d %d %d %dn' % (240,100,320,320))
send('color 0 70 0n')
for i in range(1,8):
send('line %d %d %d %dn' %
(240+i*40,100, 240+i*40,420))
send('line %d %d %d %dn' %
(240, 100+i*40, 560, 100+i*40))
for i in range(8):
for j in range(8):
if board[i][j] >= 0:
stone(i, j, board[i][j])
def makeBoard():
board = []
for i in range(8):
board.append([])
for j in range(8):
board[i].append(-1)
board[3][3], board[4][4], board[3][4], board[4][3] = 0,0,1,1
return board
def _queueqd(ip,q):
for line in iter(ip.readline,b''):
q.put(line)
ip.close()
def send(*args):
s=""
for a in args:
s+=str(a)
if s[-1]!=" ":s+=" "
if s!="":
op.write((s[:-1]+"n").encode('utf-8'))
else:
op.write("n".encode('utf-8'))
def receive():
try:
return qdq.get_nowait().decode('utf-8')[:-1]
except Empty:
return None
def running():
return qdp.poll()==None
def simulate(numTimes=1000):
w=0
b=0
for i in range(numTimes):
goesFirst=i&1
gb=makeBoard()
sg = Game(gb, goesFirst)
count = 4
while count < 64: # max num of stones is 64
sg.get_moves()
if sg.moves == []:
sg.turn = 1 - sg.turn
sg.get_moves()
if sg.moves!= []:
continue
sg.turn = 1 - sg.turn
break
if sg.turn==0:
mv = sg.select_move()
else:
mv= sg.moves[int(len(sg.moves)*random.random())]
sg.play_move(mv)
sg.turn=1-sg.turn
count+=1
num_white, num_black = sg.final_result()
if num_white>num_black:w+=1
if num_black>num_white:b+=1
return w/b
try:
qdp = Popen("java -jar quickdraw.jar",shell=True,stdout=PIPE,stdin=PIPE)
op=qdp.stdin
qdq = Queue()
qdt = Thread(target=_queueqd,args=(qdp.stdout,qdq))
qdt.daemon=True
qdt.start()
except:
print("quickdraw.jar must be in the same directory as this python script.")
quit()
send( "mouseclick Truen" )
# initialize the board, get ready for the game
board =makeBoard()
draw(board)
# game time, let's play...
# human player is white and moves first
g = Game(board, 0)
count = 4
while count < 64: # max num of stones is 64
g.get_moves()
if g.moves == []:
g.turn = 1 - g.turn
g.get_moves()
if g.moves!= []:
continue
g.turn = 1 - g.turn
break
if g.turn == 0:
while running():
event, val = ParseEvent()
if event == "MouseClicked":
val=[ int(x) for x in val.split(",")]
move = [(val[0]-240)//40, (val[1]-100)//40]
if move in g.moves: break
elif event=="ButtonClicked":
send("colour 20 20 20nfillrect 600 50 200 50ncolour 255 255 255")
send('text "Calculating..." 600 80')
r=simulate()
send("colour 20 20 20nfillrect 600 50 200 50ncolour 255 255 255")
send("text ",'"W:L=',r,'"'," 600 80")
else:
move = g.select_move()
stone(move[0], move[1], g.turn)
highlight(move)
sleep(1)
board = deepcopy(g.board)
g.play_move(move)
g.turn=1-g.turn
for i in range(8):
for j in range(8):
if board[i][j]!= g.board[i][j]:
stone(i,j,1-g.turn)
sleep(1)
stone(move[0], move[1], 1-g.turn) # redraw to de-highlight
count += 1
# game over, let's announce the result:
num_white, num_black = g.final_result()
send('color 255 255 255n')
if num_black > num_white:
send('text "black wins!" 370 470n')
elif num_black < num_white:
send('text "white wins!" 370 470n')
else:
send('text "tie!" 390 470n')
send('text "black:" 325 500n')
send('text "%d" 375 500n' % num_black)
send('text "white:" 425 500n')
send('text "%d" 475 500n' % num_white)
while running():
pass
这个文件就完成了。我的第二个文件名为Game.py。第一个文件导入这个文件,用于玩家可以进行的移动。
import random
class Game:
delta = [[0,-1],[1,-1],[1,0],[1,1],[0,1],
[-1,1],[-1,0],[-1,-1]]
def __init__(self, board, turn):
self.board = board
self.turn = turn
self.moves = self.get_moves()
def check_move(self, move, d):
pass #which I have to figure out!
def get_moves(self):
pass ##################
def select_move(self):
pass ##################
def play_move(self, move):
m,n=move[0],move[1]
for d in range(8):
i, j = m, n
if self.check_move(move,d):
i, j = i+self.delta[d][0], j+self.delta[d][1]
while self.board[i][j] == 1-self.turn:
self.board[i][j] = self.turn
i, j = i+self.delta[d][0], j+self.delta[d][1]
self.board[m][n]=self.turn
def final_result(self):
black, white = 0, 0 # color 0 is white
for i in range(8):
for j in range(8):
if self.board[i][j] == 0: white += 1
elif self.board[i][j] == 1: black += 1
return white,black
我应该填写三个缺失的定义。check move(self,move,d)方法检查给定的移动是否沿着某个方向d被验证,假设给定的游戏回合。它相应地返回True或False。换句话说,如果从移动指定的网格开始,可以捕获沿方向d的多个对手石头,则应返回True。这个方法在其他方法中使用可能很方便,如get moves()和play move()。get move(self)方法会找到当前回合的所有有效移动,并在列表中返回它们。例如,如果在[2,4]和[3,6]处有两个移动,则返回值应为[[2,4],[3,6]]。select move(self)方法从self.move中选择一个移动并返回。显然,最简单的方法是返回随机移动。所以基本上我知道这三个函数中的每一个应该做什么,以及为什么游戏需要它们,但我不知道如何对它们进行编码。。。如有任何帮助或指导,我们将不胜感激!!
所以基本上我有一个"check_move"函数的基础:
def check_move(self,move,d):
check neighboring tile:
if empty:
False #can't move
if enemy present:
while there are enemy pieces:
True #can move
这是正确的方向吗?
所以对于get_moves,我有这样的推理:
def get_moves(self): # grid[ij]
for i in range
for j in range
check for possible move directions:
check move again:
if yes then append[ij] to a list of valid moves
return list of valid moves
我认为,在开始编写代码之前,您应该首先考虑在Reversi中定义有效移动的内容。试着用英语写下定义是什么。例如,以下是我几秒钟内就能想到的条件:
- 测试的磁贴必须为空
- 在选定的方向上,测试的瓦片旁边必须有一个敌方碎片
- 在给定的方向上越过敌人的碎片,可能会有更多的敌人碎片
- 经过所有敌人的棋子后,必须有一个己方棋子(而不是空位或棋盘边缘)
我不确定这是否全面,但这是一个合理的开始。然后,思考如何测试每一个。有些可能很容易相互流动,而另一些可能是单独的测试。
我也会毫不犹豫地阅读和改编您收到的现有代码。例如,位于要实现的方法下面的play_move
方法执行的循环与check_move
方法中想要的循环非常相似(尽管它是翻转瓦片,而不是检查它们是否可以翻转)。