Last active
May 20, 2017 22:13
-
-
Save dltacube/15e29f3d60d0fe66d1a1577a65e13c8b to your computer and use it in GitHub Desktop.
Revisions
-
heyoni revised this gist
May 20, 2017 . 1 changed file with 44 additions and 30 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,20 +1,24 @@ from itertools import groupby import os from copy import deepcopy, copy default_pos = [['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']] class Board: score = [] cpu = None def __init__(self, positions=default_pos, row_move='', col_move=''): self.pos = positions self.row_move = row_move self.col_move = col_move self.getavailablemoves() if row_move != '' and col_move != '': self.update_pos(self.row_move, self.col_move) o_plays, x_plays = 0, 0 # determine whose turn it is anytime a new board is created for row in self.pos: for col in row: if col == 'O': @@ -35,32 +39,34 @@ def draw_board(self): os.system('cls' if os.name == 'nt' else 'clear') # line numbers print('player ' + self.turn + "'s turn") print(' ' * 3 + '0' + ' ' * 7 + '1' + ' ' * 7 + '2') # board print(' ' * 7 + '|' + ' ' * 7 + '|' + ' ' * 7) print('0' + ' ' * 2 + self.pos[0][0] + ' ' * 3 + '|' + ' ' * 3 + self.pos[0][1] + ' ' * 3 + '|' + ' ' * 3 + self.pos[0][2] + ' ' * 3) print('_' * 7 + '|' + '_' * 7 + '|' + '_' * 7) print(' ' * 7 + '|' + ' ' * 7 + '|' + ' ' * 7) print('1' + ' ' * 2 + self.pos[1][0] + ' ' * 3 + '|' + ' ' * 3 + self.pos[1][1] + ' ' * 3 + '|' + ' ' * 3 + self.pos[1][ 2] + ' ' * 3) print('_' * 7 + '|' + '_' * 7 + '|' + '_' * 7) print(' ' * 7 + '|' + ' ' * 7 + '|' + ' ' * 7) print('2' + ' ' * 2 + self.pos[2][0] + ' ' * 3 + '|' + ' ' * 3 + self.pos[2][1] + ' ' * 3 + '|' + ' ' * 3 + self.pos[2][ 2] + ' ' * 3) print(' ' * 7 + '|' + ' ' * 7 + '|' + ' ' * 7) print('') # make sure that a move is legal def update_pos(self, x, y): if self.pos[x][y] == '-': self.pos[x][y] = self.turn self.turn = 'O' if self.turn == 'X' else 'X' else: print('invalid position. try again') # look for a winner. assign winner to self.winner def check_for_winner(self): for y in range(0, 3): tmp_hor = [] @@ -69,15 +75,18 @@ def check_for_winner(self): for x in range(0, 3): tmp_hor.append(self.pos[x][y]) tmp_ver.append(self.pos[y][x]) if len(tmp_ver) == 3: self.check_groups(tmp_ver) if len(tmp_hor) == 3: self.check_groups(tmp_hor) # hardcoding in diagonal sequences self.check_groups([self.pos[0][0], self.pos[1][1], self.pos[2][2]]) self.check_groups([self.pos[2][0], self.pos[1][1], self.pos[0][2]]) def check_groups(self, seq): '''we group together all recurring characters then check if there is more than one group. One group in a sequence means that there are 3 of the same character in a row. If there are 2 groups or more, there is no winner yet''' groups = [] for k, g in groupby(seq): groups.append(list(g)) @@ -97,28 +106,32 @@ def validate_input(self, move): self.getavailablemoves() xmove, ymove = map(int, move.split(',')) return xmove, ymove # generate a list of all possible moves, and assign a score to each end # state. def find_next_move(self, allmoves, moves=[], levl=0): for i in range(len(allmoves)): # initialize a new Board() instance with potential move newboard = Board(deepcopy(self.pos), self.turn) newboard.update_pos(allmoves[i][0], allmoves[i][1]) newboard.check_for_winner() newboard.getavailablemoves() moves.append(allmoves[i]) if newboard.winner: if self.turn == self.cpu: self.score.append([10 - levl, levl, copy(moves)]) else: self.score.append([levl - 10, levl, copy(moves)]) moves.pop() elif len(newboard.valid_moves) < 1: # this means no winner - store this list too for stalemates self.score.append([0, levl, copy(moves)]) moves.pop() else: newboard.find_next_move(newboard.valid_moves, levl=levl + 1) moves.pop() # from the list of all moves, with their scores, find the path that leads # to the highest score def find_best_move(self): levels = set([l[0] for l in groupby(self.score, key=lambda x: x[1])]) @@ -155,6 +168,7 @@ def find_best_move(self): return move return move def start_game(): match = Board() print("Would you like to play first? y/n") -
heyoni created this gist
May 20, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,196 @@ from itertools import groupby import os from copy import deepcopy, copy # Made for Python3.5 default_pos = [['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']] class Board: score = [] cpu = None def __init__(self, positions = default_pos, row_move = '', col_move = ''): self.pos = positions self.row_move = row_move self.col_move = col_move self.getavailablemoves() if row_move != '' and col_move != '': self.update_pos(self.row_move, self.col_move) o_plays, x_plays = 0,0 for row in self.pos: for col in row: if col == 'O': o_plays += 1 if col == 'X': x_plays += 1 if x_plays > o_plays: self.turn = 'O' else: self.turn = 'X' self.winner = False self.valid_moves = [] self.getavailablemoves() self.check_for_winner() def draw_board(self): # clears the terminal os.system('cls' if os.name == 'nt' else 'clear') # line numbers print('player ' + self.turn + "'s turn") print(' ' * 3 + '1' + ' ' * 7 + '2' + ' ' * 7 + '3') # board print(' ' * 7 + '|' + ' ' * 7 + '|' + ' ' * 7) print('1' + ' ' * 2 + self.pos[0][0] + ' ' * 3 + '|' + ' ' * 3 + self.pos[0][1] + ' ' * 3 + '|' + ' ' * 3 + self.pos[0][2] + ' ' * 3) print('_' * 7 + '|' + '_' * 7 + '|' + '_' * 7) print(' ' * 7 + '|' + ' ' * 7 + '|' + ' ' * 7) print('2' + ' ' * 2 + self.pos[1][0] + ' ' * 3 + '|' + ' ' * 3 + self.pos[1][1] + ' ' * 3 + '|' + ' ' * 3 + self.pos[1][ 2] + ' ' * 3) print('_' * 7 + '|' + '_' * 7 + '|' + '_' * 7) print(' ' * 7 + '|' + ' ' * 7 + '|' + ' ' * 7) print('3' + ' ' * 2 + self.pos[2][0] + ' ' * 3 + '|' + ' ' * 3 + self.pos[2][1] + ' ' * 3 + '|' + ' ' * 3 + self.pos[2][ 2] + ' ' * 3) print(' ' * 7 + '|' + ' ' * 7 + '|' + ' ' * 7) print('') def update_pos(self, x, y): if self.pos[x][y] == '-': self.pos[x][y] = self.turn self.turn = 'O' if self.turn == 'X' else 'X' else: print('invalid position. try again') def check_for_winner(self): for y in range(0, 3): tmp_hor = [] tmp_ver = [] # checks all horizontal and vertical sequences for x in range(0, 3): tmp_hor.append(self.pos[x][y]) tmp_ver.append(self.pos[y][x]) if len(tmp_ver) == 3: self.check_groups(tmp_ver) if len(tmp_hor) == 3: self.check_groups(tmp_hor) # hardcoding in diagonal sequences self.check_groups([self.pos[0][0], self.pos[1][1], self.pos[2][2]]) self.check_groups([self.pos[2][0], self.pos[1][1], self.pos[0][2]]) def check_groups(self, seq): '''we group together all recurring characters then check if there is more than one group. If there are 2 groups or more, the sequence does not have 3 consecutives of any particular key''' groups = [] for k, g in groupby(seq): groups.append(list(g)) if len(groups) == 1 and k != '-': self.winner = k def getavailablemoves(self): self.valid_moves = [] for row in enumerate(self.pos): for col in enumerate(row[1]): if col[1] == '-': self.valid_moves.append([row[0], col[0]]) def validate_input(self, move): print("validating input...") self.getavailablemoves() xmove, ymove = map(int, move.split(',')) return xmove, ymove def find_next_move(self, allmoves, moves=[], levl=0): for i in range(len(allmoves)): newboard = Board(deepcopy(self.pos), self.turn) newboard.update_pos(allmoves[i][0], allmoves[i][1]) newboard.check_for_winner() newboard.getavailablemoves() moves.append(allmoves[i]) if newboard.winner: if self.turn == self.cpu: self.score.append([10 - levl, levl, copy(moves)]) else: self.score.append([levl - 10, levl, copy(moves)]) # long term storage for movelist goes here moves.pop() elif len(newboard.valid_moves) < 1: #this means no winner - store this list too for stalemates self.score.append([0, levl, copy(moves)]) moves.pop() else: newboard.find_next_move(newboard.valid_moves, levl=levl+1) moves.pop() def find_best_move(self): levels = set([l[0] for l in groupby(self.score, key=lambda x: x[1])]) total = {} for move in self.score: firstmv = str(move[2][0]) if firstmv not in total.keys(): total.update({firstmv: {move[1]: move[0]}}) else: if move[1] not in total[firstmv].keys(): total[firstmv].update({move[1]: move[0]}) else: total[firstmv][move[1]] += move[0] for k, v in total.items(): print(k + ' ' + str(v)) for level in levels: prev_value = None tmp = 0 move = 0 for k, v in total.items(): if not level in v.keys(): v[level] = 0 if prev_value is not None: if v[level] > prev_value: move = k tmp = v[level] prev_value = v[level] else: prev_value = v[level] tmp = v[level] move = k if [v[level] for k, v in total.items()].count(tmp) == 1: return move return move def start_game(): match = Board() print("Would you like to play first? y/n") firstplayer = input() if firstplayer == 'y': Board.cpu = 'O' else: Board.cpu = 'X' match.draw_board() print("make your move, i.e. '2,0' marks the third tile down in the first column.") while True: if match.turn == match.cpu: Board.score = [] match.getavailablemoves() match.find_next_move(match.valid_moves) print('best move:') bestmove = match.find_best_move() move = str(bestmove[1]) + ', ' + str(bestmove[4]) else: move = input() xmove, ymove = match.validate_input(move) result = match.update_pos(xmove, ymove) match.draw_board() match.check_for_winner() if match.winner: print("Player " + match.winner + " wins!") playagain = input("play again? y/n: ") break return playagain while True: # Start a new game. response = start_game() # After the game has ended, check if the player wants to play another round if response == 'y' or response == 'Y': continue else: break