How to build a world-class rock-paper-scissors bot
@notthepoint
@notthepoint
@notthepoint
@notthepoint
@notthepoint
@notthepoint
@notthepoint

@notthepoint
@notthepoint
@notthepoint
imperfect information
@notthepoint
zero sum
@notthepoint
Crystal ball
@notthepoint
Difficulty:
tattoo play
@notthepoint
Difficulty:
@notthepoint
19
99
# random bot
my_move_history = []
their_move_history = []
def next_turn(their_last_move)
['r','p','s'].sample
end
@notthepoint
# always rock bot
my_move_history = []
their_move_history = []
def next_turn(their_last_move)
'r'
end
@notthepoint
# frequency counting bot
their_move_history = {
'r' => 0,
'p' => 0,
's' => 0
}
counter_moves = { 'r' => 'p', 'p' => 's', 's' => 'r' }
def next_turn(their_last_move)
their_move_history[their_last_move] += 1
their_move = their_move_history.max_by{ |_,v| v }[0]
counter_moves[their_move]
end
@notthepoint
# Fixed string bot
string = 'rrpspprss'
current_position = -1
def next_move(opp_prev_move)
current_position =
(current_position + 1) % string.length
string[current_position]
end
@notthepoint
De Bruijn
a de Bruijn sequence of order n on a size-k alphabet A is a cyclic sequence in which every possible length-n string on A occurs exactly once as a substring
@notthepoint
rrpspprss
@notthepoint

r | r | r | p | s | p | p | r | s | s |
---|
Count: 1
s | s | p | p | s | p | r | s | s | r |
---|
s | r | r | r | r | p | s | p | p | r |
---|
first move
latest move
@notthepoint
Count: 1
first move
latest move
s | r | r | r | r | p | s | p | p | r |
---|
s | s | p | p | s | p | r | s | s | r |
---|
r | r | r | p | s | p | p | r | s | s |
---|
@notthepoint
Count: 2
first move
latest move
s | r | r | r | r | p | s | p | p | r |
---|
s | s | p | p | s | p | r | s | s | r |
---|
r | r | r | p | s | p | p | r | s | s |
---|
@notthepoint
Count: 2
first move
latest move
s | r | r | r | r | p | s | p | p | r |
---|
s | s | p | p | s | p | r | s | s | r |
---|
r | r | r | p | s | p | p | r | s | s |
---|
@notthepoint
WINDOW SIZE | COUNT | FOLLOWING MOVES |
---|---|---|
10 | 1 | p |
9 | 1 | p |
8 | 1 | p |
7 | 1 | p |
6 | 1 | p |
5 | 1 | p |
4 | 2 | p, r |
3 | 2 | p, r |
2 | 2 | p, r |
@notthepoint
# direct history bot
their_move_history = ""
counter_moves = { 'r' => 'p', 'p' => 's', 's' => 'r' }
def next_turn(their_last_move)
their_move_history << their_last_move
regexp = /([rps]{3})([rps])[rps]*\1$/
matches = regexp.match(their_move_str)
their_move = matches.captures[1]
counter_moves[their_move]
end
@notthepoint
end of the line
get first capture
spsrrrspssssrrr
([rps]{3})([rps])[rps]*\1$
@notthepoint
([rps]{3})([rps])[rps]*\1$
exactly 3
spsrrrspssssrrr
@notthepoint
spsrrrspssssrrr
([rps]{3})([rps])[rps]*\1$
@notthepoint
0 or more
([rps]{3})([rps])[rps]*\1$
spsrrrspssssrrr
@notthepoint
STRATEGIES |
---|
Random |
Frequency counting |
Direct history - fixed 'window' size |
Direct history - highest frequency of matches |
Direct history - highest frequency of following move |
Direct history - longest repeating pattern |
@notthepoint
@notthepoint
@notthepoint
A
B

@notthepoint
@notthepoint
A
B
A'


@notthepoint
@notthepoint
A
B
A'
B'



@notthepoint
@notthepoint
A'
B'


@notthepoint
@notthepoint
A
B
A'
B'
A''




@notthepoint
A
B
A'
B'
A''
B''





@notthepoint
No bluff | Bluff | Double bluff | |
---|---|---|---|
Random |
|||
Frequency counter |
|||
Direct history - fixed window size | |||
Direct history - highest frequency of matches | |||
Direct history - highest frequency of following move | |||
Direct history - longest repeating pattern |
@notthepoint
No bluff | Bluff | Double bluff | |
---|---|---|---|
Random |
0 | 0 | 0 |
Frequency counter |
0 | 0 | 0 |
Direct history - fixed window size | 0 | 0 | 0 |
Direct history - highest frequency of matches | 0 | 0 | 0 |
Direct history - highest frequency of following move | 0 | 0 | 0 |
Direct history - longest repeating pattern | 0 | 0 | 0 |
@notthepoint
No bluff | Bluff | Double bluff | |
---|---|---|---|
Random |
0 | 0 | 0 |
Frequency counter |
0 | 0 | 0 |
Direct history - fixed window size | 1 | 0 | 0 |
Direct history - highest frequency of matches | 0 | 0 | 0 |
Direct history - highest frequency of following move | 0 | 0 | 0 |
Direct history - longest repeating pattern | 0 | 0 | 0 |
@notthepoint
No bluff | Bluff | Double bluff | |
---|---|---|---|
Random |
0 | 0 | 0 |
Frequency counter |
0 | 0 | 0 |
Direct history - fixed window size | 1 | 0 | 0 |
Direct history - highest frequency of matches | 0 | 0 | -1 |
Direct history - highest frequency of following move | 0 | 0 | 0 |
Direct history - longest repeating pattern | 0 | 0 | 0 |
@notthepoint
No bluff | Bluff | Double bluff | |
---|---|---|---|
Random, over last 10 rounds |
0 | 0 | 0 |
Frequency counter, last 10 rounds |
0 | 0 | 0 |
Direct history - fixed window size, over last 10 rounds | 0 | 0 | 0 |
Direct history - highest frequency of matches, over last 10 rounds | 0 | 0 | 0 |
Direct history - highest frequency of following move, over last 10 rounds | 0 | 0 | 0 |
Direct history - longest repeating pattern, over last 10 rounds | 0 | 0 | 0 |
Random, over last 100 rounds | 0 | 0 | 0 |
Frequency counter, last 100 rounds | 0 | 0 | 0 |
Direct history - fixed window size, over last 100 rounds | 0 | 0 | 0 |
Direct history - highest frequency of matches, over last 100 rounds | 0 | 0 | 0 |
Direct history - highest frequency of following move, over last 100 rounds | 0 | 0 | 0 |
Direct history - longest repeating pattern, over last 100 rounds | 0 | 0 | 0 |
@notthepoint
No bluff | Bluff | Double bluff | |
---|---|---|---|
Random, over last 10 rounds |
0 | 0 | 0 |
Frequency counter, last 10 rounds |
0 | 0 | 0 |
Direct history - fixed window size, over last 10 rounds | 0 | 0 | 0 |
Direct history - highest frequency of matches, over last 10 rounds | 0 | 0 | 0 |
Direct history - highest frequency of following move, over last 10 rounds | 0 | 0 | 0 |
Direct history - longest repeating pattern, over last 10 rounds | 0 | 0 | 0 |
Random, over last 100 rounds | 0 | 0 | 0 |
Frequency counter, last 100 rounds | 0 | 0 | 0 |
Direct history - fixed window size, over last 100 rounds | 0 | 0 | 0 |
Direct history - highest frequency of matches, over last 100 rounds | 0 | 0 | 0 |
Direct history - highest frequency of following move, over last 100 rounds | 0 | 0 | 0 |
Direct history - longest repeating pattern, over last 100 rounds | 0 | 0 | 0 |
No bluff | Bluff | Double bluff | |
---|---|---|---|
Random, over last 10 rounds |
0 | 0 | 0 |
Frequency counter, last 10 rounds |
0 | 0 | 0 |
Direct history - fixed window size, over last 10 rounds | 0 | 0 | 0 |
Direct history - highest frequency of matches, over last 10 rounds | 0 | 0 | 0 |
Direct history - highest frequency of following move, over last 10 rounds | 0 | 0 | 0 |
Direct history - longest repeating pattern, over last 10 rounds | 0 | 0 | 0 |
Random, over last 100 rounds | 0 | 0 | 0 |
Frequency counter, last 100 rounds | 0 | 0 | 0 |
Direct history - fixed window size, over last 100 rounds | 0 | 0 | 0 |
Direct history - highest frequency of matches, over last 100 rounds | 0 | 0 | 0 |
Direct history - highest frequency of following move, over last 100 rounds | 0 | 0 | 0 |
Direct history - longest repeating pattern, over last 100 rounds | 0 | 0 | 0 |
Over the past 10
Over the past 100
Iocaine powder
@notthepoint
thank you
@notthepoint
https://webdocs.cs.ualberta.ca/~darse/rsbpc1.html
http://web.archive.org/web/20061202004212/http://www.ofb.net/~egnor/iocaine.html
https://pdfs.semanticscholar.org/5bae/79f4eb6fab8c8106736cf94a255d1535bf34.pdf
http://www.ijiris.com/volumes/volume1/issue5/11.NVIS10093.pdf
http://www.samkass.com/theories/RPSSL.html
https://cs.stanford.edu/people/eroberts/courses/soco/projects/1998-99/game-theory/psr.html
https://en.wikipedia.org/wiki/Side-blotched_lizard
Darse Billings (2000). Thoughts on RoShamBo. ICGA Journal Vol. 23, No. 1
Ruby Paper Scissors
By dorothyjane
Ruby Paper Scissors
- 1,208