Guest User

Untitled

a guest
Oct 19th, 2017
364
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.23 KB | None | 0 0
  1. '''
  2. Module for the connect four game
  3.  
  4. Written by aozdemir for Foundations of Computing, Loomis Chaffee Fall 2017
  5. '''
  6.  
  7. import multiprocessing
  8. import time
  9. import random
  10.  
  11. ROWS = 6
  12. COLUMNS = 7
  13. STREAK = 4
  14. TIMEOUT = 1 # seconds
  15. PLY = 3
  16.  
  17. # A board is a list of 6 rows
  18. # A row is a list of 7 characters
  19. # A character is 'X', 'O', or ' '
  20.  
  21. def print_board(board):
  22. ''' prints the board with column numbers '''
  23. for row in board:
  24. print('|%s|' % ' '.join(row))
  25. print('+-------------+')
  26. print('|0 1 2 3 4 5 6|')
  27. print('+-------------+')
  28.  
  29.  
  30. def _column_from_user(board, piece):
  31. ''' Gets a move from the user that is valid for `board` '''
  32. print('%s to move' % piece)
  33. while True:
  34. column = raw_input('Enter a column number: ')
  35. if column not in ['0', '1', '2', '3', '4', '5', '6']:
  36. print('Invalud column number!')
  37. continue
  38. column = int(column)
  39. if _is_valid_move(board, column):
  40. return column
  41. else:
  42. print('That column is full!')
  43.  
  44. def get_move(queue, board, piece, ply, ai):
  45. queue.put(ai(_copy_board_as_tuple(board), piece, ply))
  46.  
  47. def _column_from_ai(board, piece, ai, ply):
  48. ''' Gets a move from `ai` that is valid for `board`
  49. `ai` should be a function that takes `board`, `piece`, and `ply`,
  50. and returns a column number in range(7).
  51. If `ai` fails to do so, or takes too long, a random (valid)
  52. choice will be made for it.
  53. '''
  54.  
  55. queue = multiprocessing.Queue(1)
  56. p = multiprocessing.Process(target=get_move, args=(queue,board,piece,ply,ai))
  57. p.start()
  58. start = time.time()
  59. p.join(TIMEOUT)
  60. if p.is_alive():
  61. p.terminate()
  62. print('The AI took longer than %s seconds and was killed' % TIMEOUT)
  63. p.join()
  64. return _random_move(board, piece)
  65. if p.exitcode != 0:
  66. print('The AI threw an exception')
  67. return _random_move(board, piece)
  68. move = queue.get_nowait()
  69. if move not in range(COLUMNS) or not _is_valid_move(board, move):
  70. print_board(board)
  71. print('The AI made the move %s, which is invalid on the above board!'% move)
  72. return _random_move(board, piece)
  73. secs = time.time() - start
  74. print('The AI for %s took %.3f seconds' % (piece, secs))
  75. return move
  76.  
  77. def _random_move(board, piece):
  78. ''' returns a random valid move on `board` as a column number '''
  79. m = random.choice(_valid_moves(board))
  80. print('Making a random valid move for %s: %d' % (piece, m))
  81. return m
  82.  
  83. def _copy_board_as_tuple(board):
  84. ''' copies board '''
  85. return tuple(tuple(row) for row in board)
  86.  
  87. def _copy_board(board):
  88. ''' copies board '''
  89. return [list(row) for row in board]
  90.  
  91. def _valid_moves(board):
  92. ''' returns a list of valid moves, in the form of column numbers '''
  93. return [i for i in xrange(COLUMNS) if board[0][i] == ' ']
  94.  
  95. def _is_valid_move(board, column):
  96. ''' returns whether a piece may be dropped in `column` '''
  97. return board[0][column] == ' '
  98.  
  99. def _make_move_mut(board, column, piece):
  100. ''' drops `piece` in `column`, modifying `board`
  101. Does nothing for a full column.
  102. '''
  103. for i in reversed(xrange(ROWS)):
  104. if board[i][column] == ' ':
  105. board[i][column] = piece
  106. return
  107.  
  108. def make_move(board, column, piece):
  109. ''' drops `piece` in `column`, forming a new `board` '''
  110. b2 = _copy_board(board)
  111. _make_move_mut(b2, column, piece)
  112. return b2
  113.  
  114. def has_won(board, piece):
  115. ''' returns whether `piece` has won the `board` '''
  116. # Check column wins
  117. for c in xrange(COLUMNS):
  118. for r in xrange(ROWS - STREAK + 1):
  119. if all(board[r+i][c] == piece for i in xrange(STREAK)):
  120. return True
  121. # Check row wins
  122. for r in xrange(ROWS):
  123. for c in xrange(COLUMNS - STREAK + 1):
  124. if all(board[r][c+i] == piece for i in xrange(STREAK)):
  125. return True
  126. # Check for back-diagonal wins
  127. for r in xrange(ROWS - STREAK + 1):
  128. for c in xrange(COLUMNS - STREAK + 1):
  129. if all(board[r+i][c+i] == piece for i in xrange(STREAK)):
  130. return True
  131. # Check for forward-diagonal wins
  132. for r in xrange(STREAK - 1, ROWS):
  133. for c in xrange(COLUMNS - STREAK + 1):
  134. if all(board[r-i][c+i] == piece for i in xrange(STREAK)):
  135. return True
  136. return False
  137.  
  138. def _empty_board():
  139. ''' returns an empty board '''
  140. return [ [ ' ' for i in xrange(COLUMNS) ] for i in xrange(ROWS) ]
  141.  
  142. def next_piece(piece):
  143. ''' returns the piece that comes after `piece` '''
  144. if piece == 'X': return 'O'
  145. if piece == 'O': return 'X'
  146.  
  147. def human_v_human():
  148. ''' Plays a human v. human game of connect-4 '''
  149. board = _empty_board()
  150. piece = 'X'
  151. for move_number in xrange(COLUMNS * ROWS):
  152. print_board(board)
  153. print('')
  154. column = _column_from_user(board, piece)
  155. _make_move_mut(board, column, piece)
  156. if has_won(board, piece):
  157. print_board(board)
  158. print('\n%s won!\n' % piece)
  159. return
  160. piece = next_piece(piece)
  161. print_board(board)
  162. print('\nIt was a draw')
  163.  
  164. def human_v_ai(ai, ply=3):
  165. ''' Plays a human v. computer game of connect 4 where
  166. `ai` is the AI and it can think
  167. `ply` moves ahead
  168. '''
  169. board = _empty_board()
  170. piece = 'X'
  171. print('The %s AI will be playing \'O\'' % ai.__doc__.split('\n')[0].strip())
  172. for move_number in xrange(COLUMNS * ROWS):
  173. print_board(board)
  174. print('')
  175. if piece == 'X':
  176. column = _column_from_user(board, piece)
  177. else:
  178. column = _column_from_ai(board, piece, ai, ply)
  179. _make_move_mut(board, column, piece)
  180. if has_won(board, piece):
  181. print_board(board)
  182. print('\n%s won!\n' % piece)
  183. return
  184. piece = next_piece(piece)
  185. print_board(board)
  186. print('\nIt was a draw')
  187.  
  188. def ai_v_ai(ai1, ai2, ply=3):
  189. ''' Plays a computer v. computer game of connect 4 where they think
  190. `ply` moves ahead.
  191.  
  192. `ai1` is first to move, as 'X'
  193. '''
  194. board = _empty_board()
  195. piece = 'X'
  196. print('The %s AI will be playing \'X\'' % ai1.__doc__.split('\n')[0].strip())
  197. print('The %s AI will be playing \'O\'' % ai2.__doc__.split('\n')[0].strip())
  198. for move_number in xrange(COLUMNS * ROWS):
  199. print_board(board)
  200. print('')
  201. if piece == 'X':
  202. column = _column_from_ai(board, piece, ai1, ply)
  203. else:
  204. column = _column_from_ai(board, piece, ai2, ply)
  205. time.sleep(1)
  206. _make_move_mut(board, column, piece)
  207. if has_won(board, piece):
  208. print_board(board)
  209. print('\n%s won!\n' % piece)
  210. return
  211. piece = next_piece(piece)
  212. print_board(board)
  213. print('\nIt was a draw')
  214.  
  215.  
  216.  
  217. BOARD_X_THREAT = _copy_board([' ',
  218. ' ',
  219. ' ',
  220. ' X ',
  221. ' XO ',
  222. ' XOO '])
  223. BOARD_O_THREAT = _copy_board([' ',
  224. ' ',
  225. ' ',
  226. ' ',
  227. ' XX ',
  228. ' X OOO'])
  229. BOARD_BOTH_THREAT = _copy_board([' ',
  230. ' ',
  231. ' ',
  232. ' X ',
  233. ' X ',
  234. ' X OOO'])
  235. BOARD_X_WILL_WIN = _copy_board([' ',
  236. ' ',
  237. ' ',
  238. ' ',
  239. ' OOO ',
  240. ' XXX '])
  241. BOARD_EMPTY = _copy_board([' ',
  242. ' ',
  243. ' ',
  244. ' ',
  245. ' ',
  246. ' '])
  247. BOARD_X_BLOCKS_THEN_WINS = _copy_board([reversed(' OOOXX '),
  248. reversed('XOXOOO '),
  249. reversed('OXOXXX '),
  250. reversed('OXOXXX '),
  251. reversed('OOXXOO '),
  252. reversed('XOOOXOO')])
  253.  
  254. PIECES = ['X', 'O']
Add Comment
Please, Sign In to add comment