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
Style Pointers
def tomorrow(self): """Changes the calling object so that it represents one calendar day after the date it originally represented. "”” self.day += 1 if self.isLeapYear() == True: DIM = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] if self.day > DIM[self.month]: self.day = 1 self.month += 1 if self.month > 12: self.month = 1 self.year += 1 else:
DIM = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] if self.day > DIM[self.month]: self.day = 1 self.month += 1 if self.month > 12: self.month = 1 self.year += 1
Style Pointers
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
A More Elegant Solution
Style Pointers
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
A More 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)
Style Pointers
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
CS 121 Today
Connect Four
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
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!
Designing classes
1) What data? (Data Members)
2) What are objects' crucial capabilities? (Methods)
Not limited to 7x6!
Designing classes
1) What data? (Data Members)
- height, width
- Where the chips are
- Whose turn it is
- Winning condition
- End condition (number of chips played)2) What are objects' crucial capabilities? (Methods)
Not limited to 7x6!
Designing classes
1) What data? (Data Members)
- height, width
- Where the chips are
- Whose turn it is
- Winning condition
- End condition (number of chips played)2) What are objects' crucial capabilities? (Methods)
- create a new object
- check for win
- get the next move/switch turn
-check for full board
Not limited to 7x6!
Connect Four: the object b
Boardb
intwidthstr str str
str str str
str str str
datalist str
str
str
data
intheight
What is the name of the method that will construct this data?
Connect Four: the object b
Boardb
intwidthstr str str
str str str
str str str
datalist str
str
str
data
intheight
What is the name of the method that will construct this data?
__init__(…)
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( height ): # 6 boardRow = [] for col in range( width ): # 7 boardRow += [' '] # add a space to this row self.data += [boardRow]
Connect Four: the object b
Boardb
intwidthstr str str
str str str
str str str
datalist str
str
str
intheight
| | | | | | | || | | | | | | || | | | | | | || | | |X| | | || |X| |X|O| | ||X|O|O|O|X| |O|--------------- 0 1 2 3 4 5 6
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( self.height ): s += '|' for col in range( self.width ): s += self.data[row][col] + '|' s += '\n'
return s
Connect Four: __repr__
To remove?
To add?
which row is row 0, row 1, and so on?
def __repr__(self): """ this method returns a string representation for an object of type Board """ s = '' for row in range( self.height ): s += '|' for col in range( self.width ): s += self.data[row][col] + '|' s += '\n‘
s += '--'*self.width + '-\n‘ for col in range( self.width ):
s += ' ' + str(col % 10) s += '\n'
return s
Connect Four: __repr__
which row is row 0, row 1, and so on?
class Board
def mystery(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
def allowsMove(self, col):
Step through this mystery method.
What is each line doing?
What's going wrong?
a C4 board col # 'X' or 'O'
Write allowsMove to return True if col is a valid move;
False otherwise.
class Board{
def mystery(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
# Adds ox at the top of a column # But at the same time overwrites the existing # elements in the column… # Does not check if it is possible to write in a column… def allowsMove(self, col):
}
Step through this mystery method.
What is each line doing?
What's going wrong?
a C4 board col # 'X' or 'O'
Write allowsMove to return True if col is a valid move;
False otherwise.
class Board
def mystery1(self, col, ox): if allowsMove(col): for row in range( self.height ): if self.data[row][col] != ' ': self.data[row-1][col] = ox return self.data[self.height-1][col] = ox
def allowsMove(self, col):
Step through this mystery method.
What is each line doing?
What's going wrong?
a C4 board col # 'X' or 'O'
Write allowsMove to return True if col is a valid move;
False otherwise.
class Board
def mystery1(self, col, ox): if allowsMove(col): for row in range( self.height ): if self.data[row][col] != ' ': self.data[row-1][col] = ox return self.data[self.height-1][col] = ox
def allowsMove(self, col): if 0 <= col < self.width: return self.data[0][col] == ' '
Step through this mystery method.
What is each line doing?
What's going wrong?
a C4 board col # 'X' or 'O'
Write allowsMove to return True if col is a valid move;
False otherwise.
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!
delMove( self, col )removes a checker
Which of these will require the most thought?
winsFor( self, ox )
Thoughts?
X O
bb.winsFor( 'X' )or 'O'
winsFor( self, ox )
Thoughts?
X O
bdef winsFor(self, ox): # check for horizontal wins for row in range(0,self.height): for col in range(0,self.width-3): if self.data[row][col] == ox and \ self.data[row][col+1] == ox and \ self.data[row][col+2] == ox and \ self.data[row][col+3] == ox: return True
# check for vertical wins
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.
humanscomputers
good at evaluating the strength of a board for a player
Particularly good at recognizing patterns
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…
The Player class
PlayerpForX
Details(data and methods)
What data and methods are needed to construct and implement a Player object?
stringox
Picture of a Player object
Player
PlayerpForX
__init__(self, ox, tbt, ply)
stringtbt
__repr__(self)
scoreBoard(self, b)
scoresFor(self, b)
tiebreakMove(self, scores)
nextMove(self, b)
oppCh(self)
'X' 'LEFT'intply
3
DATA
METHODS
tiebreakTypechecker, O or X
scoreBoard ‘X’‘O’
Assigns a score to any board, b
100.0 50.0 0.0A simple system:for a win for a lossfor anything else
Score for Score for
Score for Score for
scoreBoard ‘X’‘O’
Assigns a score to any board, b
100.0 50.0 0.0A simple system:for a win for a lossfor anything else
Score for Score for
Score for Score for 0.0
100.0
scoreBoard ‘X’‘O’
Assigns a score to any board, b
100.0 50.0 0.0A simple system:for a win for a lossfor anything else
Score for Score for
Score for Score for 0.0
100.0 50.0 50.0
scoreBoard
Assigns a score to any board, b
100.0 50.0 0.0A simple system:for a win for a lossfor 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?
Looking further ahead…
scoreBoard looks ahead 0 moves
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…
score
Looking further ahead…
scoreBoard looks ahead 0 moves
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…
score -1 50 50 50100 50 50
Looking further ahead…
scoreBoard looks ahead 0 moves
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…
2-ply score -1 0 0 0 50 0 0
Looking further ahead…
scoreBoard looks ahead 0 moves
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|--------------- 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?
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
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?
Example 1-ply and 2-ply lookahead scores
-1 100
50 100
50 50100
|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
Example 1-ply and 2-ply lookahead scores
-1 100
50 50 100
50 50
col 0 col 1 col 2 col 3 col 4 col 5 col 6
-1 100
0 100
0
1-ply
2-ply50100
| | | | | | |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?
col 0 col 1 col 2 col 3 col 4 col 5 col 6
Example 1-ply and 2-ply lookahead scores
| | | | | | |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?
col 0 col 1 col 2 col 3 col 4 col 5 col 6
Example 1-ply and 2-ply lookahead scores
100
0 0 0 50 0 -1
b
0-ply scores for O:col 0 col 1 col 2 col 3 col 4 col 5 col 6
1-ply scores for O:col 0 col 1 col 2 col 3 col 4 col 5 col 6
2-ply scores for O:col 0 col 1 col 2 col 3 col 4 col 5 col 6
3-ply scores for O:col 0 col 1 col 2 col 3 col 4 col 5 col 6
Practice ‘X’‘O’
0-ply scores for O:col 0 col 1 col 2 col 3 col 4 col 5 col 6
1-ply scores for O:col 0 col 1 col 2 col 3 col 4 col 5 col 6
2-ply scores for O:col 0 col 1 col 2 col 3 col 4 col 5 col 6
3-ply scores for O:col 0 col 1 col 2 col 3 col 4 col 5 col 6
Solutions
-1
-1
-1
-1
50 50 50 50 50 50
50 50 100
50 50 50
0
0
100
100
0
0
0 0 50
100
00
b ‘X’‘O’
‘X’‘O’new‘X’
Col 6
Col 5
Col 4Col 3Col 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 4Col 3Col 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?
0.0
50.0
50.0
0.00.0
50.0
0.0
scoresFor each column
‘X’‘O’new‘X’
Col 6
Col 5
Col 4Col 3Col 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
0.0
50.0
0.00.0
50.0
0.0
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?
500
1200
2000
2800
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/secDeep Fritz: 2002X3D Fritz: 2003 Hydra: 2006
200,000,000 moves/sec
first paper: 1950
What is Hydra's chess rating?
Games’ Branching Factors
Branching Factor Estimatesfor 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 Estimatesfor different two-player games
Tic-tac-toe 4
Connect Four 7
Checkers 10
Othello 30
Chess 40
Go 300
1 Ply
2 Ply
Boundaries for qualitatively
different games…
0 Ply
Games’ Branching Factors
Branching Factor Estimatesfor 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
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| |--------------- 0 1 2 3 4 5 6
| | | | | | | || | | | | | | || | | | |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’s move X‘s move
1 ply:
| | | | | | | || | | | | | | || | | | | | | || | | | | | | || |O|X| | | | ||O|X|X|X| |O|O|--------------- 0 1 2 3 4 5 6
X’s move
‘X’‘O’new‘X’
Col 6
Col 5
Col 4Col 3Col 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
100.0
50.0
50.0
100.0100.0
50.0
100.0
‘X’‘O’new‘X’
Col 6
Col 5
Col 4Col 3Col 2
Col 1
Col 0
b
Choosing the best move
100.0
50.0
50.0
100.0100.0
50.0
100.0
(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!