Last active
April 16, 2020 14:47
-
-
Save fbparis/c05c3d0a5ffcc0b0374c090e958f6561 to your computer and use it in GitHub Desktop.
Simulate niya games with alternative rules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import product, combinations | |
from random import sample | |
# 0 1 2 3 | |
# 4 5 6 7 | |
# 8 9 A B | |
# C D E F | |
cards = list(product('ABCD', '0123', repeat=1)) | |
border = [0, 1, 2, 3, 7, 11, 15, 14, 13, 12, 8, 4] | |
figures = {'0123', '4567', '89AB','CDEF', '048C', '159D', '26AE', '37BF', '05AF', '369C', '0145', '1256', '2367', '4589', '569A', '67AB', '89CD', '9ADE', 'ABEF'} | |
def niya(board, possibleMoves, myFigures, opponentFigures, depth=0): | |
playerId = depth % 2 | |
if len(possibleMoves) == 0: | |
return None, -1 | |
if depth >= 6: # need at least 4 tokens to win | |
for moveIndex in possibleMoves: | |
coord = '%X' % moveIndex | |
for figure in myFigures: | |
if coord in figure: | |
win = True | |
for c in figure: | |
if c == coord: | |
continue | |
if board[int(c, 16)] != ('P', playerId): | |
win = False | |
break | |
if win: | |
return moveIndex, 1 | |
if depth == 15: # draw | |
return moveIndex, 0 | |
bestScore = 2 | |
for moveIndex in possibleMoves: | |
coord = '%X' % moveIndex | |
move, score = niya([board[i] if i != moveIndex else ('P', playerId) for i in range(16)], [i for i in range(16) if i != moveIndex and (board[i][0] == board[moveIndex][0] or board[i][1] == board[moveIndex][1])], {x for x in opponentFigures if coord not in x}, myFigures, depth + 1) | |
if score < bestScore: | |
bestMove, bestScore = moveIndex, score | |
if score == -1: | |
break | |
return bestMove, -bestScore | |
def best_move(board, possibleMoves, myFigures, opponentFigures, depth=0): | |
playerId = depth % 2 | |
if len(possibleMoves) == 0: | |
return None, -1 | |
if depth == 1: # last player plays twice on first turn | |
bestScore = 2 | |
for move1, move2 in combinations(possibleMoves, 2): | |
if board[move1][0] != board[move2][0] and board[move1][1] != board[move2][1]: # only valid moves | |
continue | |
coord1, coord2 = '%X' % move1, '%X' % move2 | |
move, score = best_move([board[i] if i not in (move1, move2) else ('P', playerId) for i in range(16)], [i for i in range(16) if i not in (move1, move2) and (board[i][0] == board[move2][0] or board[i][1] == board[move2][1])], {x for x in opponentFigures if coord1 not in x and coord2 not in x}, myFigures, depth + 1) | |
if score < bestScore: | |
bestMove, bestScore = (move1, move2), score | |
if score == -1: | |
break | |
return bestMove, -bestScore | |
elif depth >= 5: # need at least 4 tokens to win | |
for moveIndex in possibleMoves: | |
coord = '%X' % moveIndex | |
for figure in myFigures: | |
if coord in figure: | |
win = True | |
for c in figure: | |
if c == coord: | |
continue | |
if board[int(c, 16)] != ('P', playerId): | |
win = False | |
break | |
if win: | |
return moveIndex, 1 | |
if depth == 14: # draw | |
return moveIndex, 0 | |
bestScore = 2 | |
for moveIndex in possibleMoves: | |
coord = '%X' % moveIndex | |
move, score = best_move([board[i] if i != moveIndex else ('P', playerId) for i in range(16)], [i for i in range(16) if i != moveIndex and (board[i][0] == board[moveIndex][0] or board[i][1] == board[moveIndex][1])], {x for x in opponentFigures if coord not in x}, myFigures, depth + 1) | |
if score < bestScore: | |
bestMove, bestScore = moveIndex, score | |
if score == -1: | |
break | |
return bestMove, -bestScore | |
if __name__ == '__main__': | |
N = 100 | |
win, draw = [], [] | |
for i in range(N): | |
move, score = niya(sample(cards, 16), border, figures.copy(), figures.copy()) # Niya rules | |
# move, score = best_move(sample(cards, 16), [5, 6, 10, 9, 0, 3, 15, 12, 1, 2, 7, 11, 14, 13, 8, 4], figures.copy(), figures.copy()) # Alternative rules | |
print('%d: %X, %d' % (i, move, score)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment