Advertisement
Guest User

Untitled

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