黑白棋(Reversi or Othello)在西方和日本很流行。游戏经过相互翻转对方的棋子,最后以棋盘上谁的棋子多来判断胜负。python
黑白棋的每颗棋子由黑白两色组成,一面白,一面黑。每次落子,把本方颜色的棋子放在棋盘的空格上,若在横、竖、斜八个方向的任一方向上有本方棋子,则被夹在中间的对手棋子所有翻转为本方棋子颜色;而且仅在能够翻转棋 子的地方才能落子。若是一方至少有一步合法棋步可下,他就必须落子,不得弃权。git
棋盘已满或双方都没有棋子可下时棋局结束,以棋子数目来计算胜负,棋子多的一方获胜。在棋盘尚未下满时,若是一方的棋子已经被对方吃光,则棋局也结束,将对手棋子吃光的一方获胜。github
两位玩家轮流下棋,直到一方没有符合规则的落子位置,在这种状况下,剩下的一方 继续下棋,直到对手有了能够落子的位置。此时,恢复二者轮流下棋的顺序。若是一方落子在非法位置,则视为放弃本次对弈,对方获胜。ui
游戏结束的条件:spa
前3种状况以棋子数目来计算胜负,棋子多的一方获胜;第四种状况断定对方获胜。code
首先,程序询问用户棋盘的大小。接着,程序询问用户“计算机持黑棋仍是白棋”。orm
在本程序中,咱们用字母’X’表明黑棋, 用字母’O’表明白棋,而且假设老是黑棋玩家先走。blog
因此,若是计算机持黑棋,计算机就先走; 不然,程序提示人类玩家先走。游戏
每走一步,程序输出棋盘。黑白棋玩家轮流下棋,直到一个玩家无符合规则的落子位置。ip
此时,程序输出信息“O player has no valid move.”(假设白棋玩家无棋可走),而且提示黑棋玩家继续下棋。
每走一步,程序除输出棋盘外,还要检测游戏是否结束。若是程序检查出游戏结束,输出输赢信息并停止程序。输赢信息能够是: “O player wins.”, “X player wins.” 或者“Draw!”. 若是用户落子非法,程序应检测到而且输出“Invalid move.”, 结束程序,宣布赢家。
对每一个可能的落子位置,都进行尝试,计算该位置的“分值”(能够翻转的对手棋子数量),分值越高则在该位置落子越有利。计算每一个可能位置的分值,选择最大值位置落子。须要注意的是:可能有2个或多个棋盘格有相同的分值。这种状况下,选择行字母最小的棋盘格。若是两个棋盘格分值相同且在同一行,则选择列字母较小的棋盘格。
完整代码见
代码仓库
#!/usr/bin/python # -*- coding: utf-8 -*- class Board(): def __init__(self, n): self.n = n self.board = self.generateBoard() self.chess = {0: '.', 1: 'O', 2: 'X'} def generateBoard(self): # 0 empty 1 white 2 black i = int(self.n / 2) board = [[0] * self.n for _ in range(self.n)] board[i][i]=board[i-1][i-1] = 1 board[i][i-1]=board[i-1][i] = 2 return board def draw(self): index = 'abcdefghijklmnopqrstuvwxyz' print(' ',*index[:self.n]) for h,row in zip(index,self.board): print(h,*map('.OX'.__getitem__,row)) print()
#!/usr/bin/python # -*- coding: utf-8 -*- from board import Board import itertools import operator import collections from functools import reduce from constant import Status class Reversi(): _DIRECTIONS = [(1,0),(1,1),(1,-1),(-1,0),(-1,1),(-1,-1),(0,1),(0,-1)] def __init__(self, n, turn): self.n = n # board dimension self.b = Board(n) # board self.turn = 0 if turn == 'X' or turn == 'x' else 1 # player turn self.step = 1 # game step self.status = Status.WAIT # game status def isValidPosition(self,x,y): return 0 <= x < self.n and 0 <= y < self.n def nextPosition(self,direction,x,y): x+=direction[0] y+=direction[1] return x,y def score(self,r,c): return list(itertools.chain.from_iterable([self.scoreDirection(r+m[0],c+m[1],m,self.step%2+1,[]) for m in Reversi._DIRECTIONS])) def scoreDirection(self,x,y,direction,color,turn): if not self.isValidPosition(x,y) or self.b.board[x][y]==0 : return [] if self.b.board[x][y]!=color: turn+=[(x,y)] return self.scoreDirection(*self.nextPosition(direction,x,y),direction,color,turn) else: return turn def checkPut(self, pos): # check person put assert len(pos)>=2 , 'move position disable' r = ord(pos[0]) - 97 c = ord(pos[1]) - 97 assert 0 <= r < self.n and 0 <= c < self.n, 'move position disable' turnList = self.score(r, c) if turnList: # turn chess for x,y in turnList+[(r,c)]: self.b.board[x][y] = self.step % 2+1 return True else: return False def checkGame(self): # check game status empty,oNum,xNum = operator.itemgetter(0,1,2)(collections.Counter(itertools.chain.from_iterable(self.b.board))) hasPut = True pos,turnList = self.aiPut() if not turnList: self.step += 1 posNext,turnListNext = self.aiPut() if not turnListNext: hasPut = False else: self.step -= 1 print('{} player has no valid move'.format(self.b.chess[self.step % 2+1])) self.step -= 1 self.turn -= 1 print('{} player go on'.format(self.b.chess[self.step % 2+1])) if empty ==0 or oNum==0 or xNum == 0 or not hasPut: self.status = [Status.DRAW.value,Status.OWIN.value,Status.XWIN.value][(oNum > xNum)-(oNum<xNum)] def cmp(self,a,b): if len(a[1])>len(b[1]): return a elif len(a[1])==len(b[1]) and a[0]<b[0]: return a else: return b def aiPut(self): # computer put allPos = filter(lambda pos : self.b.board[pos[0]][pos[1]]==0,itertools.product(range(self.n),repeat=2)) allScoreForPos = map(lambda pos: [pos,self.score(pos[0],pos[1])],allPos) maxScorePos = reduce(self.cmp,allScoreForPos,[(),[]]) return maxScorePos[0],maxScorePos[1] def aiPlay(self): pos,turnList = self.aiPut() if turnList: print('Computer places {} at {}'.format(self.b.chess[self.step % 2+1],chr(pos[0]+97)+chr(pos[1]+97))) for x,y in turnList+[pos]: self.b.board[x][y] = self.step % 2+1 reversi.b.draw() self.step += 1 self.turn += 1 def pPlay(self): pos = input('Enter move for {} (RowCol):'.format(self.b.chess[self.step % 2+1])) if self.checkPut(pos): reversi.b.draw() self.step += 1 self.turn += 1 else: print('Invalid move') def play(self): self.status = Status.ONGOING plays = [self.aiPlay,self.pPlay] while self.status == Status.ONGOING: plays[self.turn % len(plays)]() self.checkGame() else: print('Game over. {}'.format(Status(self.status))) if __name__ == "__main__": print('Enter the board dimension:') try: n = int(input()) except Exception as e: print('the board dimension is invalid, start game with default dimension = 4') n = 4 assert 4 <= n <= 26 and n % 2 == 0, 'the board dimension is disable' print('Computer plays (X/O):') turn = input() assert turn in ['X','x','O', 'o'], 'the symbol of computer is disable' # generate game reversi = Reversi(n, turn) # draw board reversi.b.draw() reversi.play() input('Enter to quit')