Rebol3 Code Examplex


Go Fish

Implement the card game rules for Go Fish.

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