Advertisement
Guest User

Untitled

a guest
Apr 23rd, 2017
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.05 KB | None | 0 0
  1. """
  2. Tic Tac Toe
  3.  
  4. Author: @kevtimova
  5.  
  6. Usage:
  7.  
  8. # To Test
  9. python -m unittest tic_tac_toe.TestTicTacToe
  10.  
  11. # To Play
  12. python tic_tac_toe.py
  13.  
  14. Dependencies:
  15.  
  16. numpy
  17.  
  18. """
  19. import numpy as np
  20. import unittest
  21. import sys
  22.  
  23.  
  24. class Board:
  25. def __init__(self, size):
  26. # Board size
  27. self.size = size
  28. # Initialize board array to 0s
  29. self.board = np.zeros((self.size, self.size))
  30. # Track players' turns: 0 (first) or 1 (second)
  31. self.turn = 0
  32. # Store number of empty cells
  33. self.empty = self.size*self.size
  34. # Arrays storing sum across all rows, columns, and diagonals
  35. self.sum_rows = np.zeros(self.size)
  36. self.sum_cols = np.zeros(self.size)
  37. self.sum_diag = np.zeros(2)
  38.  
  39. def is_full(self):
  40. return not(self.empty)
  41.  
  42. def add_move(self, i, j, player):
  43. # Check if move is valid
  44. if i < self.size and j < self.size and self.board[i][j] == 0:
  45. # Record player's move on the board
  46. self.board[i][j] = 1 if player.first else -1
  47. # Update sums across row and column associated with the move
  48. self.sum_rows[i] += self.board[i][j]
  49. self.sum_cols[j] += self.board[i][j]
  50. # Update sum of diagonal(s) if the move lies on any of them
  51. if i == j:
  52. self.sum_diag[0] += self.board[i][j]
  53. if i + j == self.size - 1:
  54. self.sum_diag[1] += self.board[i][j]
  55. # Decrease number of empty cells by 1
  56. self.empty += -1
  57. self.turn = 1 - self.turn
  58. return True
  59. # Return False if move is not valid
  60. return False
  61.  
  62. def __repr__(self):
  63. rows = []
  64. for i in range(self.size):
  65. row = []
  66. for j in range(self.size):
  67. if self.board[i][j] == 0:
  68. row.append("_")
  69. elif self.board[i][j] == 1:
  70. row.append("X")
  71. else:
  72. row.append("O")
  73. row = " ".join(row)
  74. rows.append(row)
  75. return "\n".join(rows)
  76.  
  77.  
  78. class Player(object):
  79. def __init__(self):
  80. self.name = None
  81.  
  82. @property
  83. def first(self):
  84. raise NotImplementedError
  85.  
  86. def __repr__(self):
  87. return "Player {}".format(self.name)
  88.  
  89.  
  90. class PlayerOne(Player):
  91. def __init__(self):
  92. super(PlayerOne, self).__init__()
  93. self.name = "A"
  94.  
  95. @property
  96. def first(self):
  97. return True
  98.  
  99.  
  100. class PlayerTwo(Player):
  101. def __init__(self):
  102. super(PlayerTwo, self).__init__()
  103. self.name = "B"
  104.  
  105. @property
  106. def first(self):
  107. return False
  108.  
  109.  
  110. class Game:
  111. def __init__(self, size):
  112. self.size = size
  113. self.board = Board(self.size)
  114. self.players = [PlayerOne(), PlayerTwo()]
  115. self.turn = 0
  116. self.over = False
  117.  
  118. def winning_move(self, i, j):
  119. # Game is over if any column, row, or diagonal sums to +/- board size
  120. over_scores = [-self.size, self.size]
  121. if self.board.sum_rows[i] in over_scores:
  122. return True
  123. elif self.board.sum_cols[j] in over_scores:
  124. return True
  125. elif i == j and self.board.sum_diag[0] in over_scores:
  126. return True
  127. elif i+j == self.size - 1 and self.board.sum_diag[1] in over_scores:
  128. return True
  129. return False
  130.  
  131. def play(self):
  132. # Play while the game is not over
  133. while not(self.board.is_full()) and not(self.over):
  134. current_player = self.players[self.board.turn]
  135. print "Player {}'s move: (please enter comma-separated integer indices, e.g. 0,0)".format(current_player.name)
  136. # Obtain player's input
  137. try:
  138. i, j = [int(num) for num in raw_input().strip().split(",")]
  139. except:
  140. print "Invalid move.\nInput format: comma-separated integer indices, e.g. 0,0."
  141. continue
  142.  
  143. # Check if move was valid
  144. success = self.board.add_move(i, j, current_player)
  145. if not success:
  146. print "Invalid move. Indices outside of allowed range or field already claimed."
  147. continue
  148.  
  149. # Print board
  150. print self.board
  151.  
  152. # Check if game is over
  153. self.over = self.winning_move(i, j)
  154. if self.over:
  155. print "Player {} is the winner. Game over!".format(current_player.name)
  156. else:
  157. if self.board.is_full():
  158. print "No winner. Game over!"
  159.  
  160.  
  161. class TestTicTacToe(unittest.TestCase):
  162. # Verify that initial board is empty
  163. def test_board_empty(self):
  164. test_board = Board(3)
  165. self.assertTrue(test_board.empty == test_board.size**2)
  166.  
  167. # Verify that a full board is full
  168. def test_board_full(self):
  169. test_board = Board(3)
  170. test_player = PlayerOne()
  171. for i in range(test_board.size):
  172. for j in range(test_board.size):
  173. test_board.add_move(i, j, test_player)
  174. self.assertTrue(test_board.is_full())
  175.  
  176. # Verify that winning moves are detected
  177. def test_winning_move(self):
  178. # Test game and players
  179. test_game = Game(3)
  180. test_player_one = test_game.players[0]
  181. test_player_two = test_game.players[1]
  182.  
  183. # Winning configuration
  184. test_game.board.add_move(1, 1, test_player_one)
  185. self.assertFalse(test_game.winning_move(1, 1))
  186. test_game.board.add_move(0, 0, test_player_two)
  187. self.assertFalse(test_game.winning_move(0, 0))
  188. test_game.board.add_move(2, 0, test_player_one)
  189. self.assertFalse(test_game.winning_move(2, 0))
  190. test_game.board.add_move(1, 0, test_player_two)
  191. self.assertFalse(test_game.winning_move(1, 0))
  192. test_game.board.add_move(0, 2, test_player_one)
  193. self.assertTrue(test_game.winning_move(0, 2))
  194.  
  195. # No winner
  196. test_game = Game(3)
  197.  
  198. test_game.board.add_move(1, 1, test_player_one)
  199. self.assertFalse(test_game.winning_move(1, 1))
  200. test_game.board.add_move(0, 0, test_player_two)
  201. self.assertFalse(test_game.winning_move(0, 0))
  202. test_game.board.add_move(2, 0, test_player_one)
  203. self.assertFalse(test_game.winning_move(2, 0))
  204. test_game.board.add_move(0, 2, test_player_two)
  205. self.assertFalse(test_game.winning_move(0, 2))
  206. test_game.board.add_move(0, 1, test_player_one)
  207. self.assertFalse(test_game.winning_move(0, 1))
  208. test_game.board.add_move(2, 1, test_player_two)
  209. self.assertFalse(test_game.winning_move(2, 1))
  210. test_game.board.add_move(1, 0, test_player_one)
  211. self.assertFalse(test_game.winning_move(1, 0))
  212. test_game.board.add_move(1, 2, test_player_two)
  213. self.assertFalse(test_game.winning_move(1, 2))
  214. test_game.board.add_move(2, 2, test_player_one)
  215. self.assertFalse(test_game.winning_move(2, 2))
  216.  
  217. self.assertTrue(test_game.board.is_full())
  218.  
  219. # Verify that players are interchaged
  220. def test_next_turn(self):
  221. # Test game and players
  222. test_game = Game(3)
  223. test_player_one = test_game.players[0]
  224. test_player_two = test_game.players[1]
  225.  
  226. # First player's initial turn
  227. current_turn = test_game.board.turn
  228. self.assertTrue(current_turn == 0)
  229.  
  230. # Second player's turn
  231. test_game.board.add_move(1, 1, test_player_one)
  232. current_turn = test_game.board.turn
  233. self.assertTrue(current_turn == 1)
  234.  
  235. # First player's next turn
  236. test_game.board.add_move(0, 0, test_player_two)
  237. current_turn = test_game.board.turn
  238. self.assertTrue(current_turn == 0)
  239.  
  240. def run_game():
  241. while True:
  242. # Get integer board size
  243. print "Board size (please enter a positive integer):"
  244. try:
  245. n = int(raw_input())
  246. except:
  247. print "Invalid board size."
  248. continue
  249. # Play if board size is positive
  250. if n > 0:
  251. game = Game(n)
  252. game.play()
  253. break
  254. else:
  255. print "Invalid board size."
  256.  
  257. if __name__ == "__main__":
  258. run_game()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement