You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
9.0 KiB
Python
243 lines
9.0 KiB
Python
# https://boardgamegeek.com/thread/344992/brandubh-or-starting-examine-tafl-games-play
|
|
# https://en.wikipedia.org/wiki/Tafl_games
|
|
class Brandubh:
|
|
def __init__(self, data):
|
|
self.game_name = '\nBrandubh\n'
|
|
self.pieces = [' a ', ' d ']
|
|
self.winner = data['winner']
|
|
self.current_player = data['current_ps_turn']
|
|
self.piece = self.pieces[data['piece_index']]
|
|
self.instructions = """
|
|
Brandubh (Pronounced brran-doov)
|
|
|
|
Instructions:
|
|
The first player plays as the attacker (pieces marked 'a').
|
|
The second player plays as the defender ('d). The defender has a leader/king ('D).
|
|
|
|
Objective:
|
|
The first player's objective is to capture the second player's leader/king.
|
|
The second player's objective is to get the king to one of the corners of the board.
|
|
|
|
Movement:
|
|
All pieces move the same: as many spaces as a player would like in any orthagonal
|
|
direction (up, down, left, right). Pieces cannot move through or jump over other
|
|
pieces. Only the king can occupy the center square, though other pieces may move
|
|
THROUGH the central square.
|
|
|
|
Capture:
|
|
A player may capture an enemy by moving a piece against an enemy piece in a way
|
|
that flanks the enemy piece (surrounds on two sides on the same axis). A player
|
|
may move their piece between two enemy pieces without being captured. A piece
|
|
may also be captured if it is next to a corner piece and an enemy piece is moved
|
|
such that it flanks the piece using the corner as a friendly piece to complete
|
|
the capture. Either side may use the corners in this way. The king performs
|
|
captures the same as any other piece and can be captured the same way as any
|
|
other piece.
|
|
|
|
Gameplay:
|
|
Players alternate turns moving one piece per turn until either the king is dead
|
|
or the king escapes to a corner.
|
|
|
|
More information:
|
|
https://en.wikipedia.org/wiki/Tafl_games
|
|
http://dragonheelslair.com/en/rulesbrandubh.php
|
|
"""
|
|
|
|
self.p1 = data['p1']
|
|
self.p2 = data['p2']
|
|
self.board = data['board']
|
|
self.piece_index = data['piece_index']
|
|
|
|
|
|
def print_challenge_text(self):
|
|
print(self.game_name)
|
|
if self.winner:
|
|
print('{} vs. {}: {} won!'.format(self.p1, self.p2, self.winner))
|
|
else:
|
|
print('{} vs. {}: {}\'s turn {}'.format(self.p1, self.p2, self.current_player, self.piece))
|
|
|
|
def alpha_to_number(self, move):
|
|
table_str = {"a": 0, "b": 1, "c": 2, "d": 3, "e": 4, "f": 5, "g": 6}
|
|
table_num = {"1": 0, "2": 1, "3": 2, "4": 3, "5": 4, "6": 5, "7": 6}
|
|
if move[0] in table_str and move[1] in table_num:
|
|
return [table_str[move[0]], table_num[move[1]]]
|
|
return False
|
|
|
|
|
|
def print_board(self):
|
|
letters = ['A','B','C','D','E','F','G']
|
|
print('\n\n ' + ''.join([' ' + str(i) + ' ' for i in range(1,8)]))
|
|
for x in range(7):
|
|
print(' ' + letters[x] + ''.join(self.board[x]))
|
|
print('')
|
|
|
|
|
|
def get_input(self):
|
|
print("Enter your move as piece then destination (ex 'B1 B5')")
|
|
print('Or (q)uit, (f)orfeit, (instructions).\n')
|
|
while True:
|
|
move = input('> ')
|
|
if move in ['q', 'quit', 'exit']:
|
|
return False
|
|
elif move in ['f', 'forfeit']:
|
|
while True:
|
|
verify = input('Are you sure (y/n)? ')
|
|
if verify in ['y', 'yes']:
|
|
self.winner = self.p1 if self.p2 == self.current_player else self.p2
|
|
res = {"winner": self.winner, "board": self.board, "move": False, "message": "{} forfeit, {} wins!".format(self.current_player, self.winner)}
|
|
return res
|
|
elif verify in ['n', 'no']:
|
|
print('Forfeit canceled')
|
|
return False
|
|
elif move in ['i', 'instructions']:
|
|
print(self.instructions)
|
|
continue
|
|
elif len(move) != 5:
|
|
issue = 'many' if len(move) > 5 else 'few'
|
|
print("Invalid entry, too {} characters".format(issue))
|
|
continue
|
|
else:
|
|
moves = move.split(" ", 1)
|
|
if len(moves) != 2:
|
|
print("Invalid entry")
|
|
continue
|
|
moves[0] = list(moves[0].strip().lower())
|
|
moves[1] = list(moves[1].strip().lower())
|
|
start = self.alpha_to_number(moves[0])
|
|
end = self.alpha_to_number(moves[1])
|
|
piece = self.board[start[0]][start[1]]
|
|
if not start or not end:
|
|
print("Invalid coordinates")
|
|
continue
|
|
if piece.lower() != self.piece:
|
|
print("That is not a valid piece to move. Try again...")
|
|
continue
|
|
validation = self.validate_move(start, end, piece)
|
|
if not validation["success"]:
|
|
print(validation["error"])
|
|
continue
|
|
self.do_move(start, end)
|
|
self.do_captures(end)
|
|
status = self.game_over()
|
|
res = {'winner': self.winner, 'board': self.board, 'move': True}
|
|
if status:
|
|
res["winner"] = status
|
|
res["message"] = "{} won the match!".format(status)
|
|
else:
|
|
res['message'] = "Your move has been placed."
|
|
return res
|
|
|
|
|
|
def validate_move(self, beg, end, icon):
|
|
king = (icon == " D ")
|
|
if beg[0] < 0 or beg[1] < 0 or end[0] < 0 or end[1] < 0 or beg[0] > 6 or beg[1] > 6 or end[0] > 6 or end[1] > 6:
|
|
return {
|
|
"success": False,
|
|
"error": "That move would take you off the board!"
|
|
}
|
|
|
|
if beg[0] != end[0] and beg[1] != end[1]:
|
|
return {
|
|
"success": False,
|
|
"error": "You must move orthagonally..."
|
|
}
|
|
|
|
if not king and end in [[0,0],[0,6],[6,0],[6,6],[3,3]]:
|
|
return {
|
|
"success": False,
|
|
"error": "Only the king ('D') can move to that space!"
|
|
}
|
|
|
|
direction = self.get_direction(beg, end)
|
|
run = beg.copy()
|
|
while run != end:
|
|
run = [run[0] + direction[0], run[1] + direction[1]]
|
|
if self.board[run[0]][run[1]] in [' a ', ' d ', ' D ']:
|
|
return {
|
|
"success": False,
|
|
"error": "There is a piece in the way!"
|
|
}
|
|
return {"success": True, "error": ""}
|
|
|
|
|
|
def do_move(self, beg, end):
|
|
end_piece = self.board[end[0]][end[1]]
|
|
self.board[end[0]][end[1]] = self.board[beg[0]][beg[1]]
|
|
self.board[beg[0]][beg[1]] = end_piece
|
|
if beg == [3,3]:
|
|
self.board[3][3] = ' * '
|
|
|
|
|
|
def get_direction(self, b, e):
|
|
dir1 = e[0] - b[0]
|
|
dir2 = e[1] - b[1]
|
|
if dir1 > 0:
|
|
dir1 = 1
|
|
elif dir1 < 0:
|
|
dir1 = -1
|
|
|
|
if dir2 > 0:
|
|
dir2 = 1
|
|
elif dir2 < 0:
|
|
dir2 = -1
|
|
|
|
return [dir1, dir2]
|
|
|
|
|
|
def do_captures(self, pos):
|
|
enemy = self.pieces[abs(self.piece_index - 1)]
|
|
friend = self.piece
|
|
dirs = [[0,1],[0,-1],[1,0],[-1,0]]
|
|
for x in dirs:
|
|
start = pos.copy()
|
|
remove = []
|
|
steps = 0
|
|
while True:
|
|
prev = start.copy()
|
|
start[0] += x[0]
|
|
start[1] += x[1]
|
|
if start[0] < 0 or start[1] < 0 or start[0] > 6 or start[1] > 6:
|
|
break
|
|
steps += 1
|
|
if steps % 2 == 0:
|
|
if self.board[start[0]][start[1]].lower() in [friend, ' * ']:
|
|
if start == [3,3] and self.board[start[0]][start[1]] == ' * ':
|
|
break
|
|
self.board[prev[0]][prev[1]] = ' - '
|
|
continue
|
|
else:
|
|
break
|
|
else:
|
|
if self.board[start[0]][start[1]].lower() == enemy:
|
|
continue
|
|
else:
|
|
break
|
|
|
|
|
|
|
|
def game_over(self):
|
|
count = self.count_pieces()
|
|
if count[" D "] == 0:
|
|
return self.p1
|
|
elif count[" a "] == 0:
|
|
return self.p2
|
|
elif self.board[0][0] == " D " or self.board[0][6] == " D " or self.board[6][0] == " D " or self.board[6][6] == " D ":
|
|
return self.p2
|
|
return False
|
|
|
|
|
|
def count_pieces(self):
|
|
holder = {" a ": 0, " d ": 0, " D ": 0}
|
|
for x in self.board:
|
|
for y in x:
|
|
if y in [" a ", " d ", " D "]:
|
|
holder[y] += 1
|
|
return holder
|
|
|
|
|
|
def is_king(self, row, col):
|
|
piece = self.board[row][col]
|
|
if piece == ' D ':
|
|
return True
|
|
return False
|