# 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