HW 6: Problems 2 & 3 Simulating Connect 4 HW 6: Overview • Connect 4: Variation of Tic-Tac-Toe – Board: Vertical 7x6 – Two players take alternating move • Move = Placing checkers on the board • Winning = 4 checkers in a row (vert., horz., diag.) – Move constraints: • On top of each other, or • Start a new column • Problems: Board class (p2), Player class (p3) Problem 2: Connect 4 Board Variables • Board Representation: – Two-dimensional List – Width & height vary (i.e. not just 7x6) • Board Class variables – Variable data storing the 2D list – Variable height storing the number of rows – Variable width storing the number of columns Problem 2: Connect 4 Board Method: Constructor • The Constructor __init__: – Return nothing – Take in the board dimension – Set board height, width, & initialize data elements def __init__( self, width, height ): self.width = width self.height = height self.data = [] for row in range( self.height ): boardRow = [] for col in range( self.width ): boardRow += [' '] self.data += [boardRow] Problem 2: Connect 4 Board Method: Representation • Method __repr__: Print out the board | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | --------------0 1 2 3 4 5 6 def __repr__(self): s = '' for row in range(self.height): s += '|' for col in range(self.width): s += self.data[row][col]+'|' s += '\n' #print out separator ... (your code here) #print out column numbers ... (your code here) return s Problem 2: Connect 4 Board Method: addMove • Method addMove: take in column & symbol >>> b = Board(7,5) >>> b.addMove(0, 'X') >>> b.addMove(1, 'O') >>> b.addMove(1, 'X') >>> b.addMove(3, 'O') | | | | | | | | | | | | | | | | | | | | | | | | | |X| | | | | | |X|O| |O| | | | --------------0 1 2 3 4 5 6 def addMove(self, col, ox ): if allowMove(col): # find the first row in # col without a checker ... (your code here) # put ox in this position ... (your code here) Problem 2: Connect 4 Board Methods: clear, delMove, allowMove, isFull • Method clear(self): Clear all data to ' ' • Method delMove(self, col): – Opposite of addMove – Delete the top checker of column col – Do nothing if column is empty • Method allowMove(self, col): – False if col is an invalid column number, or full – True otherwise • Method isFull(self) checks if the board is full Problem 2: Connect 4 Board Method: setBoard • Method setBoard: take in the string of moves >>> b = Board(7,5) def setBoard(self,moveStr): >>> b.setBoard('02353') ch = 'O' | | | | | | | | for colStr in moveStr: | | | | | | | | col = int(colStr) | | | | | | | | if 0<=col<=self.width: | | | |O| | | | self.addMove(col,ch) |O| |X|O| |X| | if ch == 'X': --------------ch = 'O' 0 1 2 3 4 5 6 else: ch = 'X' Problem 2: Connect 4 Board Methods: winFor • Method winFor(self, ox): – Check if there are 4 ox ’s in a run – Horizontal, vertical, and diagonal – Possible direction: • Anchor checkers = checks that may start run • Check each of these anchor checkers in 8 directions Problem 2: Connect 4 Board Methods: hostGame • Method hostGame(self): – Runs until the game ends: • A player wins • The board is full (draw) – – – – – Alternatively ask player 'O' and 'X' to move Print out the board before asking to move Invalid move = ask the same player to move again Valid move = place checker & check for win At game end report the winner (or tie) EC Problem 3: Connect 4 Player Overview • Goal: Creating an automated player • Player class: – Examine the board – Find appropriate move – May look for several moves ahead • The variables: At least the following – Character ox – Tie breaking type tbt (either 'LEFT', 'RIGHT' or 'RANDOM', more detail later) – Number of moves ahead ply EC Problem 3: Connect 4 Player The Essential Methods • Construction __init__(self,ox,tbt,ply) • Representation __repr__(self) def __init__( self, ox, tbt, ply ): self.ox = ox self.tbt = tbt self.ply = ply def __repr__( self ): s = 'Player for ' + self.ox + '\n' s += 'with tiebreak type: ' + self.tbt + '\n' s += 'and ply == ' + str(self.ply) + '\n\n' return s EC Problem 3: Connect 4 Player The Required Methods • Opposite character oppCh(self): – Returns 'X' if own character is 'O', vice versa • Evaluating Board scoreBoard(self, b): – Given a board b, return 100.0, 50.0 and 0.0 respectively for win, tie, and lose situation • Tie-breaking: tiebreakMove(self, scores): – Score = list of floating point – Returns the column with the highest score – Multiple highest score: select one based on tbt – Example: tiebreakMove([0,50,0,50]) returns 1 if self.tbt == ‘LEFT’ EC Problem 3: Connect 4 Player The Brain: scoreFor • Returns a list of scores: – The cth score = goodness after a move to column c – Goodness = what happens after self.ply moves • Using recursion: – Base case 1: A full column = score of -1.0 – Base case 2: 0-ply = state of the game right now (hence, all non-full columns have the same score) – Base case 3: Game-over = state of the game right now – Recursive case: Make a move into a corresponding column, change the (local) board, evaluate recursively b EC Problem 3: Connect 4 Player 0-ply scores for O: 1-ply scores for O: 2-ply scores for O: 3-ply scores for O: ‘X’ ‘O’ col 0 col 1 col 2 col 3 col 4 col 5 col 6 -1 50 50 50 50 50 50 col 0 col 1 col 2 col 3 col 4 col 5 col 6 -1 50 50 100 50 50 50 col 0 col 1 col 2 col 3 col 4 col 5 col 6 -1 0 0 100 0 0 50 col 0 col 1 col 2 col 3 col 4 col 5 col 6 -1 0 0 100 0 0 100 EC Problem 3: Connect 4 Player Put them all together • Choose the next move: nextMove(self,b): – Return the best column to move to – Wrapper method (heavy lifting is already done) • Play the game playGame(self,px,po): – Modify hostGame from the Board class – Instead of getting user input, it use moves getting from px and po alternatively – Additional twist: if one of px and po is a string human, then get the input from the user instead