⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{trans|Ruby}} {{collection|Go Fish}}
constant show_non_human_hands = false
sequence players
enum NAME, HAND, BOOKS, KNOWN, SINCE, PLAYER=$
function new_player(string name)
if name="" then
name = prompt_string("What is your name?:")
-- puts(1,"What is your name?:pete\n")
-- name = "pete"
-- name = "computer" -- plays itself
if name!="" then
name = lower(name)
name[1] = upper(name[1])
else
name = "Computer"
end if
end if
sequence player = repeat(0,PLAYER)
player[NAME] = name
player[HAND] = {}
player[BOOKS] = ""
player[KNOWN] = repeat(' ',13)
player[SINCE] = repeat('2',13) -- (cards picked up since you last asked)
-- aside: arguably, SINCE should be "999..99", but it would not make any
-- difference, however 9 messes up debug info almost immediately,
-- whereas 2s remain visually meaningful for 7 or so more rounds.
return player
end function
constant ranks = "123456789EJQX", -- ("1EX"->"ATK" in output)
fish = "A23456789TJQK", -- (input version of above)
suits = "CDHS",
cards = {"Ace","Two","Three","Four","Five","Six","Seven",
"Eight","Nine","Ten","Jack","Queen","King"}
function map_card(integer card)
-- (input -> internal)
integer k = find(card,"ATK")
if k then card = "1EX"[k] end if
return card
end function
function unmap_cards(string cards)
-- (internal -> display)
return substitute_all(cards,"1EX","ATK")
end function
procedure show_cards(sequence cards)
printf(1,"%s\n",{unmap_cards(join(cards))})
end procedure
sequence deck
function deal()
string res = deck[$]
deck = deck[1..-2]
return res
end function
procedure check_empty_hand(integer player)
if players[player][HAND]={}
and deck!={} then
sequence one = {deal()}
string name = players[player][NAME]
if show_non_human_hands
or name!="Computer" then
printf(1,"%s's hand is empty. Picks up the ",{name})
show_cards(one)
end if
players[player][HAND] = one
end if
end procedure
procedure check_for_books(integer player)
sequence hand = sort(players[player][HAND])
string books = players[player][BOOKS]
integer i = length(hand)-3
while i>=1 do
if hand[i][1]=hand[i+3][1] then
books &= hand[i][1]
hand[i..i+3] = {}
i -= 4
else
i -= 1
end if
end while
players[player][HAND] = hand
players[player][BOOKS] = books
end procedure
procedure take_cards(integer player, sequence cards, bool bDeal=true)
players[player][HAND] &= cards
check_for_books(player)
if bDeal then
check_empty_hand(player)
end if
end procedure
function has_card(integer player, rank)
sequence hand = players[player][HAND]
for i=1 to length(hand) do
if hand[i][1]=rank then return true end if
end for
return false
end function
function hand_over(integer player, rank)
sequence cards = players[player][HAND]
integer l = length(cards)
for i=1 to l do
if cards[i][1]=rank then
for j=i+1 to l+1 do
if j=l+1 or cards[j][1]!=rank then
cards = cards[i..j-1]
players[player][HAND][i..j-1] = {}
printf(1,"%s hands over ",{players[player][NAME]})
show_cards(cards)
check_empty_hand(player)
return cards
end if
end for
end if
end for
return 9/0 -- should never trigger
end function
constant ESC=#1B
function wanted_card(integer player)
integer wanted,
opponent = 3-player
string name = players[player][NAME],
books = players[player][BOOKS],
known = players[player][KNOWN],
since = players[player][SINCE]
sequence hand = players[player][HAND]
if show_non_human_hands
or name!="Computer" then
printf(1,"%s's hand: ",{name})
show_cards(hand)
-- printf(1," books: %s\n",{unmap_cards(books)})
printf(1," opponent is known to have: %s\n",{unmap_cards(known)})
-- aside: this is not very clear: should probably space out any
-- entries for known!=' ', and do better than ..789:;<=>?@..
printf(1," and not have since: %s\n",{since})
end if
if name="Computer" then
-- strategy: if known then take,
-- otherwise pick largest since
-- (or try something else here)
integer hs = 0, hw -- highest; hs==since[hw]
for i=1 to length(hand) do
integer wdx = find(hand[i][1],ranks)
wanted = known[wdx]
if wanted!=' ' then exit end if
integer sw = since[wdx]
if sw>hs then {hs,hw} = {sw,wdx} end if
end for
if wanted=' ' then wanted = ranks[hw] end if
else
printf(1,"\n")
while 1 do
printf(1,"What rank to ask for?:")
while 1 do
wanted = wait_key()
if wanted=ESC then
abort(0)
elsif wanted<#FF then -- ignore ctrl/shift etc
wanted = upper(wanted)
printf(1,"%c",wanted)
exit
end if
end while
if not find(wanted,fish) then
printf(1," not a valid rank -- try again.\n")
else
wanted = map_card(wanted)
if has_card(player,wanted) then exit end if
printf(1," you don't have any of those -- try again\n")
end if
end while
printf(1,"\n")
end if
return wanted
end function
function query(integer player)
integer wanted = wanted_card(player),
wdx = find(wanted,ranks),
opponent = 3-player
string name = players[player][NAME],
card = substitute(cards[wdx],"x","xe") -- (Sixs -> Sixes)
-- we now (or soon will) know opponent no longer has that card
players[player][SINCE][wdx] = '0'
players[player][KNOWN][wdx] = ' '
-- opponent now knows we have one or more of that card:
players[opponent][KNOWN][wdx] = wanted
players[opponent][SINCE][wdx] = '0'
printf(1,"%s: Do you have any %ss?\n",{name,card})
if not has_card(opponent,wanted) then
printf(1,"%s: Go fish!\n",{players[opponent][NAME]})
players[player][SINCE] = sq_add(players[player][SINCE],1)
if deck!={} then
sequence one = {deal()}
if show_non_human_hands
or name!="Computer" then
printf(1,"%s picks up ",{name})
show_cards(one)
end if
take_cards(player,one)
end if
return false
end if
sequence cards = hand_over(opponent,wanted)
take_cards(player,cards)
return true -- another go
end function
function gameover()
return length(players[1][BOOKS])+length(players[2][BOOKS])=13
end function
procedure GoFishGame()
deck = {}
for rank=1 to length(ranks) do
for suit=1 to length(suits) do
string card = ""&ranks[rank]&suits[suit]
deck = append(deck,card)
end for
end for
deck = shuffle(deck)
players = {new_player("Computer"),
new_player("")}
for i=1 to 9 do
for p=1 to 2 do
take_cards(p,{deal()},false)
end for
end for
integer player = rand(2)
while not gameover() do
if not query(player) then
player = 3-player
puts(1,"--------------------------------------\n")
end if
end while
puts(1,"Game over\n")
for p=1 to 2 do
integer l = length(players[p][BOOKS])
string name = players[p][NAME],
s = iff(l=1?"":"s")
printf(1,"%s has %d book%s\n",{name,l,s})
end for
end procedure
GoFishGame()