"Intelligent" CS 5 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| | Hw 10 due 11/15 EXAM 2 Mon/Tue
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 Coding Style
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 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(): 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 An Elegant Solution
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| Can I see a demo? … but we can correct that!
Designing classes 1) What data? (Data Members) 2) What are objects' crucial capabilities? (Methods) Not limited to 7x6!
Connect Four: the object b Board b int width str data list str data int height 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: the object b Board b int width str data list str int height | | | | | | | |X| | | | | |X| |X|O| | | |X|O|O|O|X| |O| What is the name of the method that will print this data?
def __repr__(self): """ this method returns a string representation for an object of type Board """ s = '' for row in range( 6 ): s += '|' for col in range( 7 ): s += self.data[row][col] + '|' s += '\n' return s Connect Four: __repr__ To change? To add? which row is row 0, row 1, and so on?
"Quiz" class Board: def allowsMove(self, col): 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? a C4 board col # 'X' or 'O' Write allowsMove to return True if col is a valid move; False otherwise. NAME:
C4 Board class: methods __init__( self, width, height ) allowsMove( self, col ) __repr__( self ) addMove( self, col, ox ) isFull( self ) winsFor( self, ox ) the “constructor” checks if allowed places a checker outputs a string checks if any space is left checks if a player has won hostGame( self ) play (person vs. person)! delMove( self, col ) removes a checker Which of these will require the most thought?
winsFor( self, ox ) Thoughts? X O b b.winsFor( 'X' ) or 'O' corner cases?
Two-player games have been a key focus of AI as long as computers have been around… Strategic thinking == intelligence ? 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
Two-player games have been a key focus of AI as long as computers have been around… Strategic thinking == intelligence ? … humans and computers have different relative strengths in these games. humans computers good at evaluating the strength of a board for a player good at looking ahead in the game to find winning combinations of moves
How humans play games… - experts could reconstruct these perfectly - novice players did far worse… An experiment (by A. deGroot) was performed in which chess positions were shown to novice and expert players…
How humans play games… - 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! An experiment (by A. deGroot) was performed in which chess positions were shown to novice and expert players…
Two-player games have been a key focus of AI as long as computers have been around… Strategic thinking == intelligence ? humans computers good at evaluating the strength of a board for a player good at looking ahead in the game to find winning combinations of moves … humans and computers have different relative strengths in these games. building an AI chess player emulating a human by evaluating a board position
The Player class Player pForX Details (data and methods) What data and methods are needed to construct and implement a Player object? Let's see a demo!
string ox Picture of a Player object Player pForX __init__(self, ox, tbt, ply) string tbt __repr__(self) scoreBoard(self, b) scoresFor(self, b) tiebreakMove(self, scores) nextMove(self, b) oppCh(self) 'X' 'LEFT' int ply 3 DATA METHODS tiebreakType checker, O or X
scoreBoard ‘X’ ‘O’ Assigns a score to any board, b A simple system: for a win for a lossfor anything else Score for
scoreBoard Assigns a score to any board, b A simple system: for a winillegal board for anything else scoreBoard(self, b) Implementation ideas… What methods that already exist will come in handy? This doesn't seem to be looking very far ahead ! How can there be no 'X' or 'O' input? What class is this method in? 0.0 for a loss
Looking further ahead… scoreBoard looks ahead 0 moves The "Zen" approach -- we are excellent at this! If you look one move ahead, how many possibilities are there to consider? 0-ply 1-ply A 1-ply lookahead player will "see" an impending victory. to move… A score for each column…? score
Looking further ahead… scoreBoard looks ahead 0 moves The "Zen" approach -- we are excellent at this! If you look one move ahead, how many possibilities are there to consider? 0-ply A 2-ply lookahead player will also "see" an opponent's impending victory. to move… What about 3-ply? 2-ply 1-ply score
Looking further ahead… scoreBoard looks ahead 0 moves The "Zen" approach -- we are excellent at this! If you look one move ahead, how many possibilities are there to consider? 0-ply 1-ply scoresFor( self, b ) returns a LIST of scores, one for each column you can choose to move next… 2-ply
|O| | | | | | | |X| | | |O| |X| |O| | | |X|O|X| |X| | | |O|O|X| |X| |X| |X|O|O| |X| |O|O|O|X|X| | | | | | | |O| | | | | | | |X| |X| |X|O| | |O| |X|O|O|X| |X|X| |X|O|O|O| |O|X| It is O’s move. What scores does a 1-ply lookahead for O assign to each move? col 0col 1col 2col 3col 4col 5col 6 It is X’s move. What scores does a 2-ply lookahead for X assign to each move? col 0col 1col 2col 3col 4col 5col 6 Which change at 3-ply? Which change at 2-ply? Example 1-ply and 2-ply lookahead scores
b 0-ply scores for O: col 0col 1col 2col 3col 4col 5col 6 1-ply scores for O: col 0col 1col 2col 3col 4col 5col 6 2-ply scores for O: col 0col 1col 2col 3col 4col 5col 6 3-ply scores for O: col 0col 1col 2col 3col 4col 5col 6 Practice ‘X’ ‘O’
0-ply scores for O: col 0col 1col 2col 3col 4col 5col 6 1-ply scores for O: col 0col 1col 2col 3col 4col 5col 6 2-ply scores for O: col 0col 1col 2col 3col 4col 5col 6 3-ply scores for O: col 0col 1col 2col 3col 4col 5col 6 Solutions b ‘X’ ‘O’
Computer Chess early programs ~ 1960’s Computers cut their teeth playing chess… Ranking beginner amateur world ranked world champion MacHack ( 1100 ) ~ 1967 MIT Deep Thought ~ 1989 Carnegie Mellon Slate ( 2070 ) ~ 1970’s Northwestern Deep Blue ~ 1996 IBM Deep Blue rematch ~ 1997 IBM 100’s of moves/sec 10,000’s of moves/sec 1,000,000’s moves/sec 3,500,000 moves/sec Deep Fritz: 2002 X3D Fritz: 2003 Hydra: ,000,000 moves/sec first paper: 1950 What is Hydra's chess rating?
Games’ Branching Factors Branching Factor Estimates for different two-player games Tic-tac-toe 4 Connect Four 7 Checkers 10 Othello 30 Chess 40 Go 300 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 Hydra at home in the United Arab Emirates… Hydra looks ahead 18 ply !
Games’ Branching Factors Branching Factor Estimates for different two-player games Tic-tac-toe 4 Connect Four 7 Checkers 10 Othello 30 Chess 40 Go Ply 2 Ply Boundaries for qualitatively different games… 0 Ply
Games’ Branching Factors Branching Factor Estimates for different two-player games Tic-tac-toe 4 Connect Four 7 Checkers 10 Othello 30 Chess 40 Go 300 “solved” games computer-dominated human-dominated 1 Ply 2 Ply 0 Ply Progress
‘X’ ‘O’ new‘X’ Col 6 Col 5 Col 4 Col 3 Col 2 Col 1 Col 0 b scoresFor each column (1) For each possible move (2) Add it to the board
‘X’ ‘O’ new‘X’ Col 6 Col 5 Col 4 Col 3 Col 2 Col 1 Col 0 b (1) For each possible move (2) Add it to the board (3) Ask OPPONENT to score each board At what ply? scoresFor each column
‘X’ ‘O’ new‘X’ Col 6 Col 5 Col 4 Col 3 Col 2 Col 1 Col 0 b (1) For each possible move (2) Add it to the board (3) Ask OPPONENT to score each board (4) Take the opponent's MAX What to assign for a score? scoresFor each column 50.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
Write tiebreakMove to return the leftmost best score inside the list scores def tiebreakMove(self, scores): if self.tbt == 'LEFT': How would 'RANDOM' and 'RIGHT' work differently?
hw11 this week Problem 3: A Connect Four Player … Extra: scoreBoard4Tourney and a CS 5 C4 round-robin Using more scores than 0, 50, and 100 ! Problem 2: A Connect Four Board … 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| | | | | | | |O| | | | | | | |X| |X| |X|O| | |O| |X|O|O|X| |X|X| |X|O|O|O| |O|X| It is O’s move. What scores does a 1-ply lookahead for O assign to each move? col 0col 1col 2col 3col 4col 5col 6 It is X’s move. What scores does a 2-ply lookahead for X assign to each move? col 0col 1col 2col 3col 4col 5col 6 be careful! Which change at 2-ply? 00 Which change at 3-ply? 0
|O| | | | | | | |X| | | |O| |X| |O| | | |X|O|X| |X| | | |O|O|X| |X| |X| |X|O|O| |X| |O|O|O|X|X| It is O’s move. What scores does a 1-ply lookahead for O assign to each move? col 0col 1col 2col 3col 4col 5col 6 Which change at 2-ply?
Looking further ahead … 0 ply: 2 ply:3 ply: Zen choice of move: here and now | | | | |O| | | | | | | |X| | | | | | | |X|O|O| | |X| | |O|X|X|O|X|O| | | | | | | | | | |X| | | | | | | |O|O| | | |X|X| |X|O| | |O|X|O| |O|X| | (1) Player will win (2) Player will avoid losing (3) Player will set up a win by forcing the opponent to avoid losing X ’s move X ‘s move 1 ply: | | | | | |O|X| | | | | |O|X|X|X| |O|O| X ’s move
‘X’ ‘O’ new‘X’ Col 6 Col 5 Col 4 Col 3 Col 2 Col 1 Col 0 b Choosing the best move (1) For each possible move (2) Add it to the board (3) Ask OPPONENT to score each board - ply? (4) Reverse the scores
‘X’ ‘O’ new‘X’ Col 6 Col 5 Col 4 Col 3 Col 2 Col 1 Col 0 b Choosing the best move (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!
Connect Four | | | | | | | |X| | | | | |X| |X|O| | | |X|O|O|O|X| |O| Suppose our Board class's 2d list of lists is named self.data. What is the name of this single spot? For your convenience, the creators of Python’s library have included a Board class that can represent any size of Connect Four board... !
Connect Four: the object b This is true for sufficiently broad definitions of “the creators of Python’s library”... Board b def addMove(self, col, player) int NROWS int NCOLS def allowsMove(self, col) char data list char def winsFor(self, player) data members methods What is player ?
Connect Four: the object b This is true for sufficiently broad definitions of “the creators of Python’s library”... Board b def addMove(self, col, player) int NROWS int NCOLS def allowsMove(self, col) char data list char def winsFor(self, player) data members methods Which methods will alter b ? Which leave it alone?
Connect Four: Board Starting code for the Board class 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): onerow = [' ']*self.NCOLS self.data += [onerow] def __repr__(self): """ thoughts? """ look familiar?
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): 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] + '|' return s look familiar? a bit more to go !
Problem 2 class Board __init__ allowsMove __repr__ addMove isFull winsFor the “constructor” checks if allowed places a checker outputs to screen checks if space left checks if a player has won Hw11 Pr2: Connect Four Board hostGame play! What's trickiest here?
Problem 2 class Board __init__ allowsMove __repr__ addMove isFull winsFor the “constructor” checks if allowed places a checker outputs to screen checks if space left checks if a player has won Hw11 Pr2: Connect Four Board hostGame play! What's trickiest here?
What's wrong here? | | | | | | | |O|O| | | |X|X| |O|X|X|X| |X|O|O|O|O|X|X| 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
Strategies? horizontals verticals diagonals ?? | | | | | | | |O|O| | | |X|X| |O|X|X|X| |X|O|O|O|O|X|X|
“Quiz” class 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 def mysteryMethod(self, col, ox): r = 0 while r < self.NR and self.data[r][col] == ' ': r += 1 self.data[r-1][col] = ox def allowsMove(self, col): } Briefly, what is each line of the mysteryMethod doing? Which method is it? Write allowsMove to return whether the input col is a valid column to move. ( True or False ) Could it go wrong?
Problem 2 class Board __init__ allowsMove __repr__ addMove isFull winsFor the “constructor” checks if allowed places a checker outputs to screen checks if space left checks if a player has won Hw11 Pr2: Connect Four Board hostGame play! What's trickiest here?
Problem 2 class Board __init__ allowsMove __repr__ addMove isFull winsFor the “constructor” checks if allowed places a checker outputs to screen checks if space left checks if a player has won Hw11 Pr2: Connect Four Board hostGame play! What's trickiest here?
Strategies? horizontals verticals diagonals ?? | | | | | | | |X| | | | | |X| |X|O| | | |X|O|O|O|O| |O|