#!/usr/bin/env python3 """Sample implementation for Python Workshop at the Krautspace.""" from itertools import chain from copy import deepcopy SYMBOLS = (" ", "X", "O") PLAYER1 = 1 PLAYER2 = 2 PLAYERS = (PLAYER1, PLAYER2) def game_to_str(game): """Convert a game state into a string.""" lines = ("|".join(SYMBOLS[pos] for pos in row) for row in game) lines = reversed(tuple("{} {}".format(num + 1, line) for num, line in enumerate(lines))) return "\n -----\n".join(lines) + "\n a b c" def winner(game): """Determine winner of game. Returns 0 if there is no winner.""" diagonals = (tuple(row[i] for i, row in enumerate(game)), tuple(list(reversed(row))[i] for i, row in enumerate(game))) lanes = chain(game, zip(*game), diagonals) for lane in lanes: for player in (PLAYER1, PLAYER2): if all(x == player for x in lane): return player return 0 def _domove(game, move, player): """Update game state with a move.""" try: column = ord(move[0]) - 97 row = int(move[1]) - 1 except (IndexError, ValueError): print("Unable to parse move.") return False try: if game[row][column]: print("Allready taken.") return False except IndexError: print("Outside of board.") return False game[row][column] = player return True def tictactoe(player1, player2, output=True): """Orchestrate the game by alternatingly invoking the players.""" game = [[0 for _ in range(3)] for _ in range(3)] moves = 0 players = (player1, player2) while not winner(game) and moves < 9: tries = 0 while tries < 42: tmp = deepcopy(game) player = PLAYERS[moves % 2] move = players[moves % 2](tmp, player) if _domove(game, move, player): break tries += 1 else: raise RuntimeError("Unable to make valid move.") moves += 1 if output: print("Final board is:") print(game_to_str(game)) if winner(game): print("Player {} has won!".format(SYMBOLS[winner(game)])) else: print("Draw!") return winner(game) def human_player(game, player): """Get moves from terminal.""" print("Current board is:") print(game_to_str(game)) return input("Your move as {}: ".format(SYMBOLS[player])) def compete(game, ai1, ai2, runs=1000): """Benchmark to AIs against each other.""" results12 = [0, 0] results21 = [0, 0] for _ in range(runs): res = game(ai1, ai2, output=False) if res: results12[res - 1] += 1 for _ in range(runs): res = game(ai2, ai1, output=False) if res: results21[res - 1] += 1 print(("In {} runs the result is {}:{} for AI1 starting " "and {}:{} for AI2 starting").format( runs, results12[0], results12[1], results21[0], results21[1])) if __name__ == "__main__": tictactoe(human_player, human_player)