EXAM 2 Mon/Tue "Intelligent" CS 5 Hw 10 due 11/15 An object is structured data that is alive, responsible, and intelligent. Sound too friendly? This week’s objects and classes will be just the opposite ... X to move. Is there a way to win? | | | | | | | | | | | | | | | | | | | | | | | | | | | |X| | | | | |X| |X|O| | | |X|O|O|O|X|O| | --------------0 1 2 3 4 5 6 Coding Style def tomorrow(self): """Changes the calling object so that it represents one calendar day after the date it originally represented. """ if self.month in [1,3,5,7,8,10] and self.day == 31: self.day = 0 self.month += 1 elif self.month in [4,6,9,11] and self.day == 30: self.day = 0 self.month += 1 elif self.month == 2: if self.isLeapYear() and self.day == 29: self.day = 0 self.month += 1 elif (self.isLeapYear() == False) and self.day == 28: self.day = 0 self.month += 1 elif self.month == 12 and self.day == 31: self.day = 0 self.month = 1 self.year += 1 self.day += 1 Better Style, But... def tomorrow(self): """Changes the calling object so that it represents one calendar day after the date it originally represented. """ DIM = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] if self.isLeapYear() == True: DIM = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] self.day += 1 if self.day > DIM[self.month]: self.day = 1 self.month += 1 if self.month > 12: self.month = 1 self.year += 1 else: self.day += 1 if self.day > DIM[self.month]: self.day = 1 self.month += 1 if self.month > 12: self.month = 1 self.year += 1 An Elegant Solution def tomorrow(self): """Changes the calling object so that it represents one calendar day after the date it originally represented. """ DIM = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] if self.isLeapYear(): DIM[2] = 29 self.day += 1 if self.day > DIM[self.month]: self.day = 1 self.month += 1 if self.month > 12: self.month = 1 self.year += 1 isBefore/isAfter def isBefore(self, d2): """ Returns true if self is before d2 """ if self.year < d2.year: return True if self.month < d2.month and self.year == d2.year: return True if self.day < d2.day and d2.month == self.month and \ self.year == d2.year: return True return False def isAfter(self, d2): """ Returns true if self is after d2 """ if self.year > d2.year: return True if self.month > d2.month and self.year == d2.year: return True if self.day > d2.day and d2.month == self.month and \ self.year == d2.year: return True return False An Elegant Solution def isBefore(self, d2): """ Returns true if self is before d2 """ if self.year < d2.year: return True if self.month < d2.month and self.year == d2.year: return True if self.day < d2.day and d2.month == self.month and \ self.year == d2.year: return True return False def isAfter(self, d2): """ Returns true if self is after d2 """ return d2.isBefore(self) Another Elegant Solution def isBefore(self, d2): """ Returns true if self is before d2 """ return ([self.year, self.month, self.day] < [d2.year, d2.month, d2.day]) def isAfter(self, d2): """ Returns true if self is after d2 """ return d2.isBefore(self) diff def diff( self, d2 ): """ Returns the number of days between self and d2 """ dcopy = self.copy() difference = 0 if dcopy.isBefore(d2) == True: while dcopy.isBefore(d2) == True: dcopy.tomorrow() difference -= 1 else: while dcopy.isAfter(d2): dcopy.yesterday() difference += 1 return difference An Elegant Solution def diff( self, d2 ): """ Returns the number of days between self and d2 """ dcopy = self.copy() difference = 0 while dcopy.isBefore(d2): dcopy.tomorrow() difference -= 1 while dcopy.isAfter(d2): dcopy.yesterday() difference += 1 return difference Aargh! Python has no Connect-four datatype… | | | | | | | | | | | | | | | | | | | | | | | | | | | |X| | | | | |X| |X|O| | | |X|O|O|O|X| |O| --------------0 1 2 3 4 5 6 … but we can correct that! Can I see a demo? Designing classes 1) What data? (Data Members) Not limited to 7x6! 2) What are objects' crucial capabilities? (Methods) Connect Four: Board b list data the object b str str str str str str str str str str str str int width int height data What is the name of the method that will construct this data? Connect Four: constructor class Board: """ a datatype representing a C4 board with an arbitrary number of rows and cols """ def __init__( self, width, height ): """ the constructor for objects of type Board """ self.width = width self.height = height self.data = [] # this will be the board for row in range( 6 ): boardRow = [] for col in range( 7 ): boardRow += [' '] # add a space to this row self.data += [boardRow] Bad magic? Connect Four: Board b list data str str str str str str str str str What is the name of the method that will print this data? the object b str str str | | | | | | | | | | | | | | | | | | | | | | | | | | | |X| | | | | |X| |X|O| | | |X|O|O|O|X| |O| --------------0 1 2 3 4 5 6 int width int height Connect Four: __repr__ def __repr__(self): """ this method returns a string representation for an object of type Board """ s = '' which row is row 0, for row in range( 6 ): row 1, and so on? s += '|' for col in range( 7 ): s += self.data[row][col] + '|' s += '\n' To change? To add? return s NAME: class Board: def allowsMove(self, col): "Quiz" Write allowsMove to return True if col is a valid move; False otherwise. a C4 board col # 'X' or 'O' def addMove(self, col, ox): for row in range( self.height ): if self.data[row][col] != ' ': self.data[row-1][col] = ox self.data[self.height-1][col] = ox Step through this addMove method. What is each line doing? How many problems are there? C4 Board class: methods the “constructor” __init__( self, width, height ) checks if allowed allowsMove( self, col ) places a checker removes a checker outputs a string checks if any space is left checks if a player has won play (person vs. person)! addMove( self, col, ox ) delMove( self, col ) __repr__( self ) isFull( self ) winsFor( self, ox ) hostGame( self ) Which of these will require the most thought? winsFor( self, ox ) b.winsFor( 'X' ) b or 'O' X O Thoughts? corner cases? ? Strategic thinking == intelligence Two-player games have been a key focus of AI as long as computers have been around… In 1945, Alan Turing predicted that computers would be better chess players than people in ~ 50 years… and thus would have achieved intelligence. Alan Turing memorial Manchester, England ? Strategic thinking == intelligence Two-player games have been a key focus of AI as long as computers have been around… computers good at looking ahead in the game to find winning combinations of moves humans good at evaluating the strength of a board for a player … humans and computers have different relative strengths in these games. How humans play games… An experiment (by A. deGroot) was performed in which chess positions were shown to novice and expert players… - experts could reconstruct these perfectly - novice players did far worse… How humans play games… An experiment (by A. deGroot) was performed in which chess positions were shown to novice and expert players… - experts could reconstruct these perfectly - novice players did far worse… Random chess positions (not legal ones) were then shown to the two groups - experts and novices did equally well (badly) at reconstructing them! ? Strategic thinking == intelligence Two-player games have been a key focus of AI as long as computers have been around… computers good at looking ahead in the game to find winning combinations of moves building an AI chess player humans good at evaluating the strength of a board for a player emulating a human by evaluating a board position … humans and computers have different relative strengths in these games. The Player class Details Player pForX (data and methods) What data and methods are needed to construct and implement a Player object? Let's see a demo! Player Picture of a Player object DATA Player pForX 3 'LEFT' 'X' string ox string tbt checker, O or X tiebreakType int ply __init__(self, ox, tbt, ply) __repr__(self) oppCh(self) scoreBoard(self, b) scoresFor(self, b) tiebreakMove(self, scores) nextMove(self, b) METHODS scoreBoard ‘X’ ‘O’ Assigns a score to any board, b A simple system: Score for Score for 100.0 50.0 0.0 for a win for anything else for a loss Score for Score for scoreBoard Assigns a score to any board, b A simple system: 100.0 50.0 0.0 for a win for anything else for a loss -1.0 illegal board Implementation ideas… scoreBoard(self, b) How can there be no 'X' or 'O' input? What class is this method in? What methods that already exist will come in handy? This doesn't seem to be looking very far ahead ! Looking further ahead… scoreBoard looks ahead 0 moves The "Zen" approach -we are excellent at this! 0-ply If you look one move ahead, how many possibilities are there to consider? A 1-ply lookahead player will "see" an impending victory. to move… 1-ply score A score for each column…? Looking further ahead… scoreBoard looks ahead 0 moves The "Zen" approach -we are excellent at this! 0-ply If you look one move ahead, how many possibilities are there to consider? A 2-ply lookahead player will also "see" an opponent's impending victory. to move… 1-ply score What about 3-ply? 2-ply score Looking further ahead… scoreBoard looks ahead 0 moves If you look one move ahead, how many possibilities are there to consider? The "Zen" approach -we are excellent at this! 0-ply 1-ply 2-ply scoresFor( self, b ) returns a LIST of scores, one for each column you can choose to move next… Example 1-ply and 2-ply lookahead scores |O| | | | | | | |X| | | |O| |X| |O| | | |X|O|X| |X| | | |O|O|X| |X| |X| |X|O|O| |X| |O|O|O|X|X| --------------0 1 2 3 4 5 6 | | | | | | |O| | | | | | | |O| | | | | | | |X| |X| |X|O| | |O| |X|O|O|X| |X|X| |X|O|O|O| |O|X| --------------0 1 2 3 4 5 6 It is O’s move. What scores does a 1-ply lookahead for O assign to each move? col 0 col 1 col 2 col 3 col 4 col 5 col 6 Which change at 2-ply? It is X’s move. What scores does a 2-ply lookahead for X assign to each move? col 0 col 1 col 2 col 3 col 4 col 5 col 6 Which change at 3-ply? Practice b ‘X’ ‘O’ col 0 col 1 col 2 col 3 col 4 col 5 col 6 col 0 col 1 col 2 col 3 col 4 col 5 col 6 col 0 col 1 col 2 col 3 col 4 col 5 col 6 col 0 col 1 col 2 col 3 col 4 col 5 col 6 0-ply scores for O: 1-ply scores for O: 2-ply scores for O: 3-ply scores for O: Solutions 0-ply scores for O: 1-ply scores for O: 2-ply scores for O: 3-ply scores for O: b ‘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 Computer Chess Computers cut their teeth playing chess… first paper: 1950 Ranking beginner 500 early programs ~ 1960’s 100’s of moves/sec amateur 1200 MacHack (1100) ~ 1967 MIT 10,000’s of moves/sec 1,000,000’s moves/sec world ranked 2000 Slate (2070) ~ 1970’s Northwestern Deep Thought ~ 1989 Carnegie Mellon Deep Blue ~ 1996 2800 IBM world champion Deep Blue rematch ~ 1997 IBM 3,500,000 moves/sec Deep Fritz: 2002 X3D Fritz: 2003 Hydra: 2006 What is Hydra's chess rating? 200,000,000 moves/sec Games’ Branching Factors • On average, there are fewer than 40 possible moves that a chess player can make from any board configuration… 0 Ply 1 Ply 2 Ply Branching Factor Estimates for different two-player games Hydra at home in the United Arab Emirates… Hydra looks ahead 18 ply ! Tic-tac-toe 4 Connect Four 7 Checkers 10 Othello 30 Chess 40 Go 300 Games’ Branching Factors 0 Ply 1 Ply 2 Ply Branching Factor Estimates for different two-player games Boundaries for qualitatively different games… Tic-tac-toe 4 Connect Four 7 Checkers 10 Othello 30 Chess 40 Go 300 Games’ Branching Factors 0 Ply 1 Ply 2 Ply Branching Factor Estimates for different two-player games Progress “solved” games computer-dominated human-dominated Tic-tac-toe 4 Connect Four 7 Checkers 10 Othello 30 Chess 40 Go 300 ‘X’ ‘O’ new‘X’ scoresFor each column b (1) For each possible move (2) Add it to the board Col 6 Col 0 Col 5 Col 1 Col 2 Col 3 Col 4 ‘X’ ‘O’ new‘X’ scoresFor each column b (1) For each possible move (2) Add it to the board (3) Ask OPPONENT to score each board At what ply? 0.0 50.0 Col 6 Col 0 Col 5 Col 1 Col 2 Col 3 Col 4 50.0 50.0 0.0 0.0 0.0 ‘X’ ‘O’ new‘X’ scoresFor each column b (1) For each possible move (2) Add it to the board What to assign for a score? (3) Ask OPPONENT to score each board (4) Take the opponent's MAX 0.0 50.0 Col 6 Col 0 Col 5 Col 1 Col 2 Col 3 Col 4 50.0 50.0 0.0 0.0 0.0 scoresFor def scoresFor(self, b): (1) For each possible move (2) Add it to the board (3) Ask OPPONENT to score each board - at ? ply (4) the score is 100-max def tiebreakMove(self, scores): Write tiebreakMove to return the leftmost best score inside the list scores if self.tbt == 'LEFT': How would 'RANDOM' and 'RIGHT' work differently? hw11 this week http://www.stanford.edu/~ccecka/research/C4.html • Problem 2: A Connect Four Board… • Problem 3: A Connect Four Player… • Extra: scoreBoard4Tourney and a CS 5 C4 round-robin Using more scores than 0, 50, and 100 ! don't give this board a 50.0 ! “Quiz” Names: |O| | | | | | | |X| | | |O| |X| |O| | | |X|O|X| |X| | | |O|O|X| |X| |X| |X|O|O| |X| |O|O|O|X|X| --------------0 1 2 3 4 5 6 It is O’s move. What scores does a 1-ply lookahead for O assign to each move? col 0 col 1 col 2 col 3 col 4 col 5 col 6 -1 100 50 100 50 100 50 Which change at 2-ply? 0 0 | | | | | | |O| | | | | | | |O| | | | | | | |X| |X| |X|O| | |O| |X|O|O|X| |X|X| |X|O|O|O| |O|X| --------------0 1 2 3 4 5 6 It is X’s move. What scores does a 2-ply lookahead for X assign to each move? be careful! col 0 col 1 col 2 col 3 col 4 col 5 col 6 100 0 0 0 50 0 -1 0 Which change at 3-ply? |O| | | | | | | |X| | | |O| |X| |O| | | |X|O|X| |X| | | |O|O|X| |X| |X| |X|O|O| |X| |O|O|O|X|X| --------------0 1 2 3 4 5 6 It is O’s move. What scores does a 1-ply lookahead for O assign to each move? col 0 col 1 col 2 col 3 col 4 col 5 col 6 Which change at 2-ply? Looking further ahead … 0 ply: Zen choice of move: here and now 1 ply: 2 ply: 3 ply: X’s move | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |O|X| | | | | |O|X|X|X| |O|O| --------------0 1 2 3 4 5 6 X’s move | | | | | | | | | | | | | | | | |O| | | | | | | |X| | | | | | | |X|O|O| | |X| | |O|X|X|O|X|O| | --------------0 1 2 3 4 5 6 X‘s move | | | | | | | | | | | | | | | | | | | | |X| | | | | | | |O|O| | | |X|X| |X|O| | |O|X|O| |O|X| | --------------0 1 2 3 4 5 6 (1) Player will win (2) Player will avoid losing (3) Player will set up a win by forcing the opponent to avoid losing ‘X’ ‘O’ new‘X’ Choosing the best move b (1) For each possible move (2) Add it to the board (3) Ask OPPONENT to score each board - ply? (4) Reverse the scores 100.0 50.0 Col 6 Col 0 Col 5 Col 1 Col 2 Col 3 Col 4 50.0 50.0 100.0 100.0 100.0 ‘X’ ‘O’ new‘X’ Choosing the best move b (1) For each possible move (2) Add it to the board (3) Ask OPPONENT to score each board - ply? (4) Reverse the scores (5) Find one max - that's it! 100.0 50.0 Col 6 Col 0 Col 5 Col 1 Col 2 Col 3 Col 4 50.0 50.0 100.0 100.0 100.0 Connect Four For your convenience, the creators of Python’s library have included a Board class that can represent any size of Connect Four board... ! | | | | | | | | | | | | | | | | | | | | | | | | | | | |X| | | | | |X| |X|O| | | |X|O|O|O|X| |O| --------------0 1 2 3 4 5 6 Suppose our Board class's 2d list of lists is named self.data. What is the name of this single spot? Connect Four: the object b This is true for sufficiently broad definitions of “the creators of Python’s library” ... data members int NROWS Board b What is player ? int NCOLS list data char char char char char char char char char char char char def addMove(self, col, player) def allowsMove(self, col) def winsFor(self, player) methods Connect Four: the object b This is true for sufficiently broad definitions of “the creators of Python’s library” ... data members int NROWS Board b Which methods will alter b? Which leave it alone? int NCOLS list data char char char char char char char char char char char char def addMove(self, col, player) def allowsMove(self, col) def winsFor(self, player) methods Connect Four: Board class Board: def __init__( self, numRows, numCols ): """ our Board's constructor """ self.NROWS = numRows self.NCOLS = numCols self.data = [] for r in range(self.NROWS): look familiar? onerow = [' ']*self.NCOLS self.data += [onerow] def __repr__(self): """ thoughts? """ Starting code for the Board class Connect Four: Board class Board: def __init__( self, numRows, numCols ): """ our Board's constructor """ self.NROWS = numRows self.NCOLS = numCols self.data = [] for r in range(self.NR): look familiar? onerow = [' ']*self.NC self.data += [onerow] def __repr__(self): """ thoughts? """ s = '\n' for r in range(self.NROWS): s += '|' for c in range(self.NCOLS): s += self.data[r][c] + '|' a bit more to go ! return s Problem 2 Hw11 Pr2: Connect Four Board class Board __init__ the “constructor” allowsMove checks if allowed addMove places a checker __repr__ outputs to screen isFull winsFor hostGame checks if space left checks if a player has won play! What's trickiest here? Problem 2 Hw11 Pr2: Connect Four Board class Board __init__ the “constructor” allowsMove checks if allowed addMove places a checker __repr__ outputs to screen isFull winsFor hostGame checks if space left checks if a player has won play! What's trickiest here? What's wrong here? def winsForHoriz(self, player): inarow = 0 for r in range(self.NROWS): for c in range(self.NCOLS): if self.data[r][c] == player: inarow += 1 else: inarow = 0 if inarow == 4: return True return False | | | | | | | | | | | | | | | | | | | | | | | | | | | |O|O| | | |X|X| |O|X|X|X| |X|O|O|O|O|X|X| --------------0 1 2 3 4 5 6 Strategies? horizontals verticals diagonals ?? | | | | | | | | | | | | | | | | | | | | | | | | | | | |O|O| | | |X|X| |O|X|X|X| |X|O|O|O|O|X|X| --------------0 1 2 3 4 5 6 class { # # # # # “Quiz” Board __init__ and __repr__ methods here… 3 data members: self.NR == number of rows self.NC == number of cols self.data == the 2d list of lists of chars Briefly, what is each line of the mysteryMethod doing? Which method is it? 1 def mysteryMethod(self, col, ox): r = 0 while r < self.NR and self.data[r][col] == ' ': r += 1 self.data[r-1][col] = ox 2 3 Could it go wrong? def allowsMove(self, col): Write allowsMove to return whether the input col is a valid column to move. (True or False) } Problem 2 Hw11 Pr2: Connect Four Board class Board __init__ the “constructor” allowsMove checks if allowed addMove places a checker __repr__ outputs to screen isFull winsFor hostGame checks if space left checks if a player has won play! What's trickiest here? Problem 2 Hw11 Pr2: Connect Four Board class Board __init__ the “constructor” allowsMove checks if allowed addMove places a checker __repr__ outputs to screen isFull winsFor hostGame checks if space left checks if a player has won play! What's trickiest here? Strategies? horizontals verticals diagonals ?? | | | | | | | | | | | | | | | | | | | | | | | | | | | |X| | | | | |X| |X|O| | | |X|O|O|O|O| |O| --------------0 1 2 3 4 5 6