Go Fish/V (Vlang)
< Go Fish
AI selects card randomly
import rand
import rand.seed
import os
const cards = ["2", "3", "4", "5", "6", "7", "8", "9",
"10", "J", "Q", "K", "A"]
//GoFishGame Stores the game state.
struct GoFishGame {
mut:
hands [][]string
deck []string
turn int
scores []int
}
// check_for_books looks for fours of a kind
// and scores them if we have them.
// If we run out of cards, we draw more.
fn (mut gm GoFishGame) check_for_books() {
gm.hands[gm.turn].sort()
mut prev := ""
mut count := 1
for card in gm.hands[gm.turn] {
if card == prev {
count++
if count == 4 {
println("Book of ${card}.")
gm.steal_cards(card, gm.turn)
gm.scores[gm.turn]++
if gm.is_hand_empty() {
gm.draw_card()
}
}
} else {
count = 1
}
prev = card
}
}
// draw_card takes a card from the deck
// adding it to the current player's hand.
fn (mut gm GoFishGame) draw_card() {
if !gm.is_deck_empty() {
card := gm.deck[0]
gm.deck = gm.deck[1..]
if gm.is_player_turn() {
println("You drew a ${card}.")
}
gm.hands[gm.turn] << card
//Check for books
gm.check_for_books()
}
}
// get_pick_computer handles the computer's card choices.
// We do the moderately smart thing of pick a random
// card from our hand
fn get_pick_computer(gm GoFishGame) string {
hand := gm.hands[1]
mut choice := "A"
if hand.len > 0 {
choice = hand[rand.intn(hand.len) or {0}]
}
println("Computer picks ${choice}.")
return choice
}
// get_pick_user gets the user's move.
// If it's not valid, then the user just wastes
// their turn.
fn get_pick_user(gm GoFishGame) string {
card := os.input("What card do you want?")
return card
}
// is_deck_empty returns if the deck is empty.
fn (gm GoFishGame) is_deck_empty() bool {
return gm.deck.len == 0
}
// is_hand_empty returns if the current player's hand is empty.
fn (gm GoFishGame) is_hand_empty() bool {
return gm.hands[gm.turn].len == 0
}
// is_game_over returns if the game is over.
// This happens when all 13 pips have been made into sets.
fn (gm GoFishGame) is_game_over() bool {
return gm.scores[0]+gm.scores[1] == 13
}
// is_player_turn returns if its the player's turn to move.
fn (gm GoFishGame) is_player_turn() bool {
return gm.turn == 0
}
// make_deck makes a deck.
// The deck is 52 cards with 4 of each pip.
fn make_deck() []string {
rand.seed(seed.time_seed_array(2))
mut deck := []string{len: 52}
mut perm := []int{len:52, init:it}//rand.Perm(52)
rand.shuffle<int>(mut perm) or {panic('ERROR shuffling')}
for indx in perm {
t_val := perm[indx]
card := cards[t_val/4]
deck[indx] = card
}
return deck
}
// opponent_has returns if the opponent's hand has a card.
fn (gm GoFishGame) opponent_has(find string) bool {
for card in gm.hands[(gm.turn+1)%2] {
if card == find {
return true
}
}
return false
}
// player_turn handles the major game logic.
// It's used for both the player's and computer's turns,
// with the different behavior handled by the get_pick param.
fn (mut gm GoFishGame) player_turn(get_pick fn(GoFishGame) string) {
opponent := (gm.turn + 1) % 2
gm.check_for_books()
if opponent == 1 {
gm.print_hand()
}
if gm.is_hand_empty() {
gm.draw_card()
}
game_over := gm.is_game_over()
if !game_over {
card := get_pick(gm)
if gm.opponent_has(card) {
count := gm.steal_cards(card, opponent)
for _ in 0..count {
gm.hands[gm.turn] << card
}
gm.check_for_books()
} else {
println("GO FISH!")
gm.draw_card()
gm.turn = opponent
}
}
}
// print_game_over_message prints the appropriate end message.
fn (gm GoFishGame) print_game_over_message() {
println("Final score is ${gm.scores[0]} to ${gm.scores[1]}.")
if gm.scores[0] > gm.scores[1] {
println("Player wins!")
} else if gm.scores[0] == gm.scores[1] {
println("It's a tie.")
} else {
println("Computer wins!")
}
}
// print_hand print's the player's hand and current score.
fn (mut gm GoFishGame) print_hand() {
gm.hands[0].sort()
println("You have: ${gm.hands[0]}.")
println("Score is ${gm.scores[0]} to ${gm.scores[1]}.")
}
// steal_cards removes all instances of a card from side's hand.
fn (mut gm GoFishGame) steal_cards(purge string, side int) int {
mut count := 0
mut filtered := []string{}
for card in gm.hands[side] {
if purge == card {
count++
} else {
filtered << card
}
}
gm.hands[side] = filtered
return count
}
// main creates the deck and initial hands.
fn main() {
mut deck := make_deck()
player_hand := deck[0..9]
comp_hand := deck[9..18]
deck = deck[18..]
mut hands := [][]string{len: 2, cap:2}
hands[0] = player_hand
hands[1] = comp_hand
mut scores := []int{len: 2, cap:2}
scores[0] = 0
scores[1] = 0
mut game := GoFishGame{hands, deck, 0, scores}
for {
if game.is_player_turn() {
game.player_turn(get_pick_user)
} else {
game.player_turn(get_pick_computer)
}
if game.is_game_over() {
break
}
}
game.print_game_over_message()
}