[Python] 黑白棋(翻转棋)小游戏
[Python] 黑白棋(翻轉(zhuǎn)棋)小游戲
游戲介紹
黑白棋(Reversi or Othello)在西方和日本很流行。游戲通過(guò)相互翻轉(zhuǎn)對(duì)方的棋子,最后以棋盤上誰(shuí)的棋子多來(lái)判斷勝負(fù)。
規(guī)則
黑白棋的每顆棋子由黑白兩色組成,一面白,一面黑。每次落子,把本方顏色的棋子放在棋盤的空格上,若在橫、豎、斜八個(gè)方向的任一方向上有本方棋子,則被夾在中間的對(duì)手棋子全部翻轉(zhuǎn)為本方棋子顏色;并且僅在可以翻轉(zhuǎn)棋 子的地方才能落子。如果一方至少有一步合法棋步可下,他就必須落子,不得棄權(quán)。
棋盤已滿或雙方都沒(méi)有棋子可下時(shí)棋局結(jié)束,以棋子數(shù)目來(lái)計(jì)算勝負(fù),棋子多的一方獲勝。在棋盤還沒(méi)有下滿時(shí),如果一方的棋子已經(jīng)被對(duì)方吃光,則棋局也結(jié)束,將對(duì)手棋子吃光的一方獲勝。
勝負(fù)判定
兩位玩家輪流下棋,直到一方?jīng)]有符合規(guī)則的落子位置,在這種情況下,剩下的一方 繼續(xù)下棋,直到對(duì)手有了可以落子的位置。此時(shí),恢復(fù)兩者輪流下棋的順序。如果一方落子在非法位置,則視為放棄本次對(duì)弈,對(duì)方獲勝。
游戲結(jié)束的條件:
前3種情況以棋子數(shù)目來(lái)計(jì)算勝負(fù),棋子多的一方獲勝;第四種情況判定對(duì)方獲勝。
人機(jī)對(duì)弈流程
首先,程序詢問(wèn)用戶棋盤的大小。接著,程序詢問(wèn)用戶“計(jì)算機(jī)持黑棋還是白棋”。
在本程序中,我們用字母’X’代表黑棋, 用字母’O’代表白棋,并且假設(shè)總是黑棋玩家先走。
所以,如果計(jì)算機(jī)持黑棋,計(jì)算機(jī)就先走; 否則,程序提示人類玩家先走。
每走一步,程序輸出棋盤。黑白棋玩家輪流下棋,直到一個(gè)玩家無(wú)符合規(guī)則的落子位置。
此時(shí),程序輸出信息“O player has no valid move.”(假設(shè)白棋玩家無(wú)棋可走),并且提示黑棋玩家繼續(xù)下棋。
每走一步,程序除輸出棋盤外,還要檢測(cè)游戲是否結(jié)束。如果程序檢查出游戲結(jié)束,輸出輸贏信息并中止程序。輸贏信息可以是: “O player wins.”, “X player wins.” 或者“Draw!”. 如果用戶落子非法,程序應(yīng)檢測(cè)到并且輸出“Invalid move.”, 結(jié)束程序,宣布贏家。
計(jì)算機(jī)選擇落子位置的策略
對(duì)每個(gè)可能的落子位置,都進(jìn)行嘗試,計(jì)算該位置的“分值”(可以翻轉(zhuǎn)的對(duì)手棋子數(shù)量),分值越高則在該位置落子越有利。計(jì)算每個(gè)可能位置的分值,選擇最大值位置落子。需要注意的是:可能有2個(gè)或多個(gè)棋盤格有相同的分值。這種情況下,選擇行字母最小的棋盤格。如果兩個(gè)棋盤格分值相同且在同一行,則選擇列字母較小的棋盤格。
程序執(zhí)行
代碼
完整代碼見(jiàn)
代碼倉(cāng)庫(kù)
棋盤代碼
#!/usr/bin/python # -*- coding: utf-8 -*-class Board():def __init__(self, n):self.n = nself.board = self.generateBoard()self.chess = {0: '.', 1: 'O', 2: 'X'}def generateBoard(self):# 0 empty 1 white 2 blacki = int(self.n / 2)board = [[0] * self.n for _ in range(self.n)]board[i][i]=board[i-1][i-1] = 1board[i][i-1]=board[i-1][i] = 2return boarddef 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 Statusclass 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 dimensionself.b = Board(n) # boardself.turn = 0 if turn == 'X' or turn == 'x' else 1 # player turnself.step = 1 # game stepself.status = Status.WAIT # game statusdef isValidPosition(self,x,y):return 0 <= x < self.n and 0 <= y < self.ndef nextPosition(self,direction,x,y):x+=direction[0]y+=direction[1]return x,ydef 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 turndef checkPut(self, pos):# check person putassert len(pos)>=2 , 'move position disable'r = ord(pos[0]) - 97c = ord(pos[1]) - 97assert 0 <= r < self.n and 0 <= c < self.n, 'move position disable'turnList = self.score(r, c)if turnList:# turn chessfor x,y in turnList+[(r,c)]:self.b.board[x][y] = self.step % 2+1return Trueelse:return Falsedef checkGame(self):# check game statusempty,oNum,xNum = operator.itemgetter(0,1,2)(collections.Counter(itertools.chain.from_iterable(self.b.board)))hasPut = Truepos,turnList = self.aiPut()if not turnList:self.step += 1posNext,turnListNext = self.aiPut()if not turnListNext:hasPut = Falseelse:self.step -= 1print('{} player has no valid move'.format(self.b.chess[self.step % 2+1]))self.step -= 1self.turn -= 1print('{} 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 aelse:return bdef aiPut(self):# computer putallPos = 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+1reversi.b.draw()self.step += 1self.turn += 1def 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 += 1self.turn += 1else:print('Invalid move')def play(self):self.status = Status.ONGOINGplays = [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 = 4assert 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 gamereversi = Reversi(n, turn)# draw boardreversi.b.draw()reversi.play()input('Enter to quit')總結(jié)
以上是生活随笔為你收集整理的[Python] 黑白棋(翻转棋)小游戏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java 百万级数据处理_一次性查询百万
- 下一篇: ubuntu忘记mysql密码,怎么办