Go Fish/J
The essential portion of the program is a gerund of verbs action0`action1`...`actionn, one for each state of the game. Agenda @. drives the action. This iterates ^:f^:_ until reaching the termination state. Function f returns a Boolean value and is 0 when it identifies the terminal. The states by number are represented in base 0 as 0b[0-z] for easy identification. The actions return the next state. Thus verb go's guts are
setup
g`e`r`u`n`d @. extract_state ^: non_terminal ^: _ choose_1st_player
cleanup
Instruct
go fish
to play.
The code uses the cards as recommended and fulfills the AI requirement
in a minimal fashion. If J hands over its last card to the opponent J
chooses to not draw a card.
The state transitions follow. The code combines some of these states.
Since J assumes undefined names are verbs we don't need to define the
unused verbs of the gerund.
J CAPITAL, opponent lower.
book: remove books from hand and update score.
fill: optionally draw a card into empty hand.
end: no more fish in pond.
book -> fill ->
end
draw -> BOOK Chose to not draw a card into an empty hand before asking; silly but valid.
ask -> RESPOND ->
FISH -> draw -> BOOK
SUPPLY -> book
BOOK -> FILL ->
end
ASK -> respond ->
fish -> DRAW -> book
supply -> dumb -> BOOK
state
number name transition to
0b0 book 0b1
0b1 fill 0b2 0b3 0b5
0b2 end
0b3 draw 0b4
0b4 BOOK 0b9
0b5 ask 0b6
0b6 RESPOND 0b7 0b8
0b7 FISH 0b3
0b8 SUPPLY 0b0
0b9 FILL 0b2 0ba
0ba ASK 0bb
0bb respond 0bc 0be
0bc fish 0bd
0bd DRAW 0b0
0be supply 0bf
0bf dumb 0b4
Here is fish.ijs which includes some test code to demonstrate and of course test some of its verbs.
load'~user/playingcards.ijs'
coinsert'rcpc'
show =: [: , ' ' ,. sayCards@:/:~ NB. show hand generates a linear display
instructions =: 0 : 0
Go Fish!
Request a card using a single character: 23456789tjqka
Start the game with
go fish
)
write =: ": 1!:2 2:
read =: 1!:1@1:
lc =:(] i.~ 'AKQJT' , ]) { 'akqjt' , ] NB. lower case
fish =: 'fish'
rnks =: ,@:(_ 1&{.)
counts =: 3 : 0 NB. return the values of the cards y having x members
4 counts y
:
(~. #~ x = [: +/"1 =)rnks y
)
score =: 4 : 0 NB. player score J
victor =. x *@- y
if. 0 = victor do. 'Tie'
else.
if. 0 < victor do. a =. 'You win'
else. a =. 'J wins'
end.
a =. a,' by '
margin =. |x-y
if. 1 = margin do. a,'a book.'
else. a,(":margin),' books.'
end.
end.
)
HAND=:hand=:0 2$BOOKS=:books=:DEBUG =: 0
debug =: 3 : 0
if. DEBUG do.
write y
write(":BOOKS),' HAND ',show HAND
write(":books),' hand ',show hand
end.
)
book =: 3 : 0
debug'book'
r =. counts hand
books =: books+#r
hand =: (#~ [: -. r e.~ rnks)hand
0b1
)
BOOK =: 3 : 0
debug'BOOK'
r =. counts HAND
BOOKS =: BOOKS+#r
HAND =: (#~ [: -. r e.~ rnks)HAND
0b9
)
fill =: 3 : 0
debug'fill'
NB. hand has cards, proceed.
if. #hand do. 0b5 return. end.
NB. no cards in deck, none in hand, done.
if. 0 = # TheDeck__pc do. 0b2 return. end.
write 'Draw a card into your empty hand? (y/n)'
NB. (must draw a card) Skipped the proposed "draw" verb.
hand =: hand,dealCards__pc 1
NB. failure to choose to draw ends turn.
0b4 0b5{~'1tTyY'e.~{.read''
)
FILL =: 3 : 0
debug'FILL'
if. #HAND do. 0ba return. end.
if. 0 = # TheDeck__pc do. 0b2 return. end.
HAND =: HAND,dealCards__pc 1
0ba NB. This is the AI.
)
R =: 'a23456789tjqk'
ask =: 3 : 0
debug'ask'
write 'You hold ',show hand
write 'Your request please? ',R
while. -.(rnks hand)e.~v=.(i.14){~R i. lc read'' do. write '?' end.
if. v e. rnks HAND do.
a =. (#~ v e.~ rnks) HAND
write'You took ',' of them.',~":#a
hand =: hand,a
HAND =: HAND -. a
0b0
else.
write 'Nope. Go fish!'
0b3
end.
)
ASK =: 3 : 0
debug'ASK'
a =. {.({~ ?@#)HAND
if. a e. rnks hand do.
write 'J took "','"s.',~":a{R
a =. (#~ a = rnks) hand
HAND =: HAND,a
hand =: hand-.a
0b4
else.
write 'J requested ','. You said "fish".',~":a{R
0bd
end.
)
draw =: 3 : 0
debug'draw'
hand =: hand,c =. dealCards__pc 1
write 'You caught ','.',~show c
0b4
)
DRAW =: 3 : 0
debug'DRAW'
HAND =: HAND,dealCards__pc 1
0b0
)
NB. condensed
NB.0b6 RESPOND 0b7 0b8
NB.0b7 FISH 0b3
NB.0b8 SUPPLY 0b0
NB.0bb respond 0bc 0be
NB.0bc Fish 0bd
NB.0be supply 0bf
NB.0bf dumb 0b4
test =: 3 : 0
pc =. newDeck''
shuffle__pc''
card1 =. dealCards__pc 1
card51 =. dealCards__pc 51
NB. linear display
assert. 1 -: #$ show card51
NB. some assurance that it counts right
assert. 1 -: # 1 counts card1
assert. 0 -: # counts card1
assert. 0 -: # 1 counts card51
assert. 1 -: # 3 counts card51
assert. 12 -: # counts card51
NB. demonstrate the main loop state machine with data passing
state0 =. 0b1"_ ; 'state 0'"_
state1 =. 0b2"_ ; ' state 1'"_ ,~ >@{:
eval =. state0`state1@.(>@{.)^:(0b2&~:@>@{.)^:_]0
expect =. 2 ; 'state 0 state 1'
assert. expect -: eval
NB. lower case
assert. 'aXq98a' -: lc 'AXQ98a'
NB. score
assert. 'J wins by a book.' -: 3 score 4
assert. 'You win by a book.' -: 3 score~ 4
assert. 'Tie' -: score~3
assert. 'You win by 30 books.' -: 3 score~ 33
assert. 'J wins by 30 books.' -: 3 score 33
NB. book
hand =: card51
books =: 0
book''
assert. 3 = # hand
assert. 12 = books
)
test''
write instructions
go =: 3 : 0 NB. go fish starts the game.
write instructions
0 go y
:
DEBUG =: x
pc=:newDeck''
shuffle__pc''
'HAND hand'=: 2 dealCards__pc 9 NB. deal two hands of nine cards
'BOOKS books' =: 0 NB. initialize the score
book`fill`end`draw`BOOK`ask`RESPOND`FISH`SUPPLY`FILL`ASK`respond`Fish`DRAW`supply`dumb@.]^:(0b2&~:)^:_(?2){0b0 0b4
BOOK book''
if. fail =. books 13&~:@+ BOOKS do.
write'uh oh, books add to ',":books+BOOKS
end.
if. fail +. HAND 0&~:@+&# hand do.
write 'OH NO! found cards left in hands.'
write 'HAND ',show HAND
write 'hand ',show hand
end.
write books score BOOKS
)
Sample
go load'~user/fish.ijs'
Go Fish!
Request a card using a single character: 23456789tjqka
Start the game with
go fish
Go Fish!
Request a card using a single character: 23456789tjqka
Start the game with
go fish
J requested 9. You said "fish".
You hold A♦ 4♣ 5♥ 5♠ 6♠ 7♣ 10♣ J♣ J♥
Your request please? a23456789tjqk
t
Nope. Go fish!
You caught K♦.
J requested 9. You said "fish".
You hold A♦ 4♣ 5♥ 5♠ 6♠ 7♣ 10♣ J♣ J♥ K♦
Your request please? a23456789tjqk