217 lines
6.6 KiB
Text
217 lines
6.6 KiB
Text
Rebol [
|
|
title: "Rosetta code: Go Fish"
|
|
file: %Go_fish.r3
|
|
url: https://rosettacode.org/wiki/Go_Fish
|
|
]
|
|
|
|
go-fish-game: function/with [
|
|
"Play a game of Go Fish"
|
|
][
|
|
deck: fisher-yates-shuffle copy ordered-deck
|
|
clear ai-hand clear ai-book-list clear ai-guess
|
|
clear my-hand clear my-book-list
|
|
ai-books: my-books: 0
|
|
deal-cards/ai 9 ai-hand
|
|
deal-cards 9 my-hand
|
|
message: clear ""
|
|
draw-screen
|
|
while [ai-books + my-books < 13][
|
|
computer-turn
|
|
if ai-books + my-books < 13 [player-turn]
|
|
]
|
|
clear-screen
|
|
draw-screen
|
|
print ""
|
|
print as-yellow "GAME OVER"
|
|
print ["^/Computer books:" as-red pad ai-books -3
|
|
"^/Player books:" as-green pad my-books -3]
|
|
][
|
|
;; Build deck
|
|
ordered-deck: []
|
|
foreach r ranks: "A23456789TJQK" [
|
|
foreach s "♣♦♥♠" [
|
|
append ordered-deck ajoin [r s]
|
|
]
|
|
]
|
|
;; Charsets used to filter key inputs
|
|
player-card-keys: charset join ranks "x"
|
|
player-yes-no: charset "ynx"
|
|
|
|
;; Game states
|
|
ai-hand: [] ai-book-list: [] ai-guess: []
|
|
my-hand: [] my-book-list: []
|
|
deck: []
|
|
ai-books: my-books: 0
|
|
|
|
|
|
message: ""
|
|
|
|
;; Shuffle function
|
|
fisher-yates-shuffle: func [list [block!] /local len j] [
|
|
len: length? list
|
|
repeat i len [
|
|
j: i + random (len - i)
|
|
swap at list i at list j
|
|
]
|
|
list
|
|
]
|
|
;; Cards sorting
|
|
rank-modifiers: #[
|
|
#"A" 130 #"K" 120 #"Q" 110 #"J" 100 #"T" 90
|
|
#"9" 80 #"8" 70 #"7" 60 #"6" 50 #"5" 40
|
|
#"4" 30 #"3" 20 #"2" 10
|
|
]
|
|
card-rank: func [card] [rank-modifiers/(card/1)]
|
|
sort-hand: func [hand] [
|
|
sort/compare hand func [a b] [
|
|
(card-rank a) < (card-rank b)
|
|
]
|
|
]
|
|
;; Screen output
|
|
clear-screen: does [prin "^[[2J^[[H"]
|
|
draw-screen: does [
|
|
clear-screen
|
|
;; title bar
|
|
print as-yellow "=================================="
|
|
print as-yellow " G O F I S H "
|
|
print as-yellow "=================================="
|
|
print ""
|
|
;; deck count
|
|
print ajoin [as-cyan " Deck: " length? deck " cards remaining"]
|
|
print ""
|
|
;; books lines
|
|
print ajoin [as-red " Computer books: " pad ai-books -2 " [ " ai-book-list " ]"]
|
|
print ajoin [as-green " Your books: " pad my-books -2 " [ " my-book-list " ]"]
|
|
print as-yellow "----------------------------------"
|
|
print ""
|
|
;; my hand
|
|
print [as-cyan "Your hand:" as-yellow sort-hand my-hand]
|
|
print ""
|
|
;; last message
|
|
unless empty? message [ print message ]
|
|
print as-yellow "----------------------------------"
|
|
]
|
|
status: func[txt][
|
|
if block? txt [txt: ajoin txt]
|
|
append append message txt LF
|
|
]
|
|
;; Game functions
|
|
deal-cards: function [num hand /ai] [
|
|
new: take/part deck num
|
|
unless ai [
|
|
status ["You draw new card" if num > 1 ["s"] ": " new]
|
|
]
|
|
append hand new
|
|
]
|
|
find-in: func [hand kind [char!]] [
|
|
forall hand [
|
|
if hand/1/1 = kind [return kind]
|
|
]
|
|
none
|
|
]
|
|
guess-from: function [hand guessed] [
|
|
kind: first random/only exclude hand guessed
|
|
append guessed kind
|
|
kind
|
|
]
|
|
check-for-books: func [hand /ai /local kind n count] [
|
|
if empty? hand [exit]
|
|
sort hand
|
|
kind: hand/1/1 n: count: 0
|
|
while [not tail? hand][
|
|
either kind = hand/1/1 [
|
|
n: n + 1
|
|
if n = 4 [
|
|
remove/part next hand -4
|
|
++ count
|
|
append either ai [ai-book-list][my-book-list] kind
|
|
if tail? hand [break]
|
|
kind: hand/1/1 n: 0
|
|
continue
|
|
]
|
|
][
|
|
kind: hand/1/1
|
|
n: 1
|
|
]
|
|
++ hand
|
|
]
|
|
either ai [
|
|
ai-books: ai-books + count
|
|
][ my-books: my-books + count]
|
|
if count > 0 [
|
|
status ["New " as-green count " book" if count > 1 "s" " collected!"]
|
|
]
|
|
count
|
|
]
|
|
transfer-cards: func [
|
|
;; Move all cards of a given rank from src to trg
|
|
src [block!] trg [block!] kind [char!]
|
|
][
|
|
while [not tail? src] [
|
|
either kind = src/1/1 [append trg take src][++ src]
|
|
]
|
|
]
|
|
computer-turn: func [/local kind a] [
|
|
forever [
|
|
if empty? ai-hand [
|
|
if empty? deck [exit]
|
|
deal-cards/ai 3 ai-hand
|
|
]
|
|
ai-guess: unique ai-guess
|
|
kind: guess-from ai-hand ai-guess
|
|
draw-screen
|
|
print as-red { -------------------^/ - COMPUTER TURN -^/ -------------------}
|
|
clear message
|
|
prin ajoin [" Do you have any " as-green kind "s? "]
|
|
a: wait-for-key/only player-yes-no
|
|
if any [none? a a = #"x"][ halt ]
|
|
either a = #"y" [
|
|
transfer-cards my-hand ai-hand kind
|
|
status ["Computer took your " as-green kind "s!"]
|
|
check-for-books/ai ai-hand
|
|
draw-screen
|
|
][
|
|
status ["Go Fish! Computer draws a card."]
|
|
deal-cards/ai 1 ai-hand
|
|
check-for-books/ai ai-hand
|
|
draw-screen
|
|
exit
|
|
]
|
|
]
|
|
]
|
|
|
|
player-turn: func [/local kind n] [
|
|
forever [
|
|
if empty? my-hand [
|
|
if empty? deck [exit]
|
|
deal-cards 3 my-hand
|
|
]
|
|
draw-screen
|
|
print as-green { -------------------^/ - PLAYER TURN -^/ -------------------}
|
|
clear message
|
|
prin " Your guess: "
|
|
kind: wait-for-key/only player-card-keys
|
|
if any [none? kind kind = #"x"][ halt ]
|
|
kind: uppercase kind
|
|
unless find-in my-hand kind [
|
|
status as-red "You must hold that rank to ask for it!"
|
|
draw-screen
|
|
exit
|
|
]
|
|
either find-in ai-hand kind [
|
|
transfer-cards ai-hand my-hand kind
|
|
status ["You took the computer's " as-green kind "s!"]
|
|
check-for-books my-hand
|
|
draw-screen
|
|
][
|
|
status ["Computer don't have any " as-green kind "s!"]
|
|
deal-cards 1 my-hand
|
|
check-for-books my-hand
|
|
draw-screen
|
|
exit
|
|
]
|
|
]
|
|
]
|
|
]
|
|
;--- Main ---
|
|
go-fish-game
|