Go Fish/Go: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
(Less idiosyncratic and gofmt'ed.)
Line 5: Line 5:
package main
package main


import "fmt"
import (
"fmt"
import "math/rand"
"math/rand"
import "sort"
"sort"
import "time"
"time"
)


var kCards = [13]string{"2", "3", "4", "5", "6", "7", "8", "9",
var cards = [13]string{"2", "3", "4", "5", "6", "7", "8", "9",
"10", "J", "Q", "K", "A"}
"10", "J", "Q", "K", "A"}


//GoFishGame Stores the game state.
type GoFishGame struct {
type GoFishGame struct {
_Hands [][]string
hands [][]string
_Deck []string
deck []string
_Turn int
turn int
_Scores []int
scores []int
}
}


// checkForBooks looks for fours of a kind
/*
* We score a point if we have four
// and scores them if we have them.
* of a kind. So, we sort our hand
// If we run out of cards, we draw more.
func (gm *GoFishGame) checkForBooks() {
* and if we have four in a row of
sort.Strings(gm.hands[gm.turn])
* the same pip, we take them out
prev := ""
* of our hand and get a point.
count := 1
*/
for _, card := range gm.hands[gm.turn] {
func (self *GoFishGame) checkForBooks() {
if card == prev {
sort.Strings(self._Hands[0])
count++
sort.Strings(self._Hands[1])
if count == 4 {
tPrev := ""
fmt.Printf("Book of %s.\n", card)
tCount := 1
gm.stealCards(card, gm.turn)
for _, tChar := range self._Hands[self._Turn] {
gm.scores[gm.turn]++
if tChar == tPrev {
if gm.isHandEmpty() {
tCount++
gm.drawCard()
if tCount == 4 {
fmt.Println("Book of", tChar)
self.removeOccurences(tChar, self._Turn)
self._Scores[self._Turn]++
if self.isHandEmpty() {
self.drawCard()
}
}
}
}
} else {
} else {
tCount = 1
count = 1
}
}
tPrev = tChar
prev = card
}
}
}
}


// drawCard takes a card from the deck
/*
* Safely draw a card and put it in your hand.
// adding it to the current player's hand.
func (gm *GoFishGame) drawCard() {
*/
if !gm.isDeckEmpty() {
func (self *GoFishGame) drawCard() {
card := gm.deck[0]
if !self.isDeckEmpty() {
tCard := self._Deck[0]
gm.deck = gm.deck[1:]
if gm.turn == 0 {
self._Deck = self._Deck[1:]
fmt.Printf("You drew a %s.\n", card)
if self._Turn == 0 {
fmt.Println("Drew", tCard)
}
}
self._Hands[self._Turn] = append(self._Hands[self._Turn], tCard)
gm.hands[gm.turn] = append(gm.hands[gm.turn], card)
//Check for books
//Check for books
self.checkForBooks()
gm.checkForBooks()
}
}
}
}


// endPly ends the current person's turn.
/*
// It then either calls the next person's
* See if the game has ended.
// turn or prints a game over message.
* Else, let the next person go.
func (gm *GoFishGame) endPly() {
*/
gameOver := gm.isGameOver()
func (self *GoFishGame) endPly() {
if gameOver {
tGameOver := self.isGameOver()
gm.printGameOverMessage()
if tGameOver {
} else if gm.turn == 1 {
self.printGameOverMessage()
gm.playerTurn(getPickComputer)
} else if self._Turn == 1 {
self.playerTurn(getPickComputer)
} else {
} else {
self.playerTurn(getPickUser)
gm.playerTurn(getPickUser)
}
}
}
}


// getPickComputer handles the computer's card choices.
/*
// We do the moderately smart thing of pick a random
* Pick a card that the computer has
// card from our hand
* randomly.
func getPickComputer(gm *GoFishGame) string {
*/
hand := gm.hands[1]
func getPickComputer(self *GoFishGame) string {
choice := "A"
tHand := self._Hands[1]
if len(hand) > 0 {
tChoice := "A"
choice = hand[rand.Intn(len(hand))]
if len(tHand) > 0 {
tChoice = tHand[rand.Intn(len(tHand))]
}
}
fmt.Println("Computer picks", tChoice)
fmt.Printf("Computer picks %s.\n", choice)
return tChoice
return choice
}
}


// getPickUser gets the user's move.
/*
// If it's not valid, then the user just wastes
* Ask the user what they want to pick.
// their turn.
*/
func getPickUser(self *GoFishGame) string {
func getPickUser(gm *GoFishGame) string {
fmt.Println("What card do you want?")
fmt.Println("What card do you want?")
var tCard string
var card string
fmt.Scanf("%s\n", &tCard)
fmt.Scanf("%s\n", &card)
return tCard
return card
}
}


// isDeckEmpty returns if the deck is empty.
/*
func (gm *GoFishGame) isDeckEmpty() bool {
* Convenience function.
return len(gm.deck) == 0
*/
func (self *GoFishGame) isDeckEmpty() bool {
return len(self._Deck) == 0
}
}


// isHandEmpty returns if the current player's hand is empty.
/*
func (gm *GoFishGame) isHandEmpty() bool {
* Convenience function.
return len(gm.hands[gm.turn]) == 0
*/
func (self *GoFishGame) isHandEmpty() bool {
return len(self._Hands[self._Turn]) == 0
}
}


// isGameOver returns if the game is over.
/*
* The game is over when all 13 pips have
// This happens when all 13 pips have been made into sets.
func (gm *GoFishGame) isGameOver() bool {
* been made into sets.
return gm.scores[0]+gm.scores[1] == 13
*/
func (self *GoFishGame) isGameOver() bool {
return self._Scores[0]+self._Scores[1] == 13
}
}


// makeDeck makes a deck.
/*
* Make a deck contains 4 copies of each
// The deck is 52 cards with 4 of each pip.
* card and shuffle it.
*/
func makeDeck() []string {
func makeDeck() []string {
rand.Seed(time.Now().UTC().UnixNano())
rand.Seed(time.Now().UTC().UnixNano())
tDeck := make([]string, 52)
deck := make([]string, 52)
tPerm := rand.Perm(52)
perm := rand.Perm(52)
for tIndex := range tPerm {
for indx := range perm {
tVal := tPerm[tIndex]
tVal := perm[indx]
tCard := kCards[tVal/4]
card := cards[tVal/4]
tDeck[tIndex] = tCard
deck[indx] = card
}
}
return tDeck
return deck
}
}


// opponentHas returns if the opponent's hand has a card.
/*
func (gm *GoFishGame) opponentHas(find string) bool {
* returns true if the opponent's hand contains an aCard.
for _, card := range gm.hands[(gm.turn+1)%2] {
*/
if card == find {
func (self *GoFishGame) opponentHas(aCard string) bool {
for _, tCard := range self._Hands[(self._Turn+1)%2] {
if tCard == aCard {
return true
return true
}
}
Line 155: Line 140:
}
}


// playerTurn handles the major game logic.
/*
* Handle both the players and computers turns.
// It's used for both the player's and computer's turns,
* Differences between them are handled by checking
// with the different behavior handled by the getPick param.
func (gm *GoFishGame) playerTurn(getPick func(*GoFishGame) string) {
* whose turn it is manually and through the getPick
opponent := (gm.turn + 1) % 2
* parameter.
gm.checkForBooks()
*/
if opponent == 1 {
func (self *GoFishGame) playerTurn(getPick func(*GoFishGame) string) {
gm.printHand()
tOpponent := (self._Turn + 1) % 2
self.checkForBooks()
if tOpponent == 1 {
self.printHand()
}
}
if self.isHandEmpty() {
if gm.isHandEmpty() {
self.drawCard()
gm.drawCard()
}
}
tGameOver := self.isGameOver()
gameOver := gm.isGameOver()
if !tGameOver {
if !gameOver {
tCard := getPick(self)
card := getPick(gm)
if self.opponentHas(tCard) {
if gm.opponentHas(card) {
tCount := self.removeOccurences(tCard, tOpponent)
count := gm.stealCards(card, opponent)
for tIndex := 0; tIndex < tCount; tIndex++ {
for indx := 0; indx < count; indx++ {
self._Hands[self._Turn] = append(self._Hands[self._Turn], tCard)
gm.hands[gm.turn] = append(gm.hands[gm.turn], card)
}
}
self.checkForBooks()
gm.checkForBooks()
} else {
} else {
self.drawCard()
fmt.Println("GO FISH!")
gm.drawCard()
self._Turn = tOpponent
gm.turn = opponent
}
}
}
}
self.endPly()
gm.endPly()
}
}


// printGameOverMessage prints the appropriate end message.
/*
func (gm *GoFishGame) printGameOverMessage() {
* Determine and say who won.
fmt.Printf("Final score is %d to %d.\n", gm.scores[0], gm.scores[1])
*/
if gm.scores[0] > gm.scores[1] {
func (self *GoFishGame) printGameOverMessage() {
fmt.Println("Final score is", self._Scores[0], "to", self._Scores[1])
if self._Scores[0] > self._Scores[1] {
fmt.Println("Player wins!")
fmt.Println("Player wins!")
} else if self._Scores[0] == self._Scores[1] {
} else if gm.scores[0] == gm.scores[1] {
fmt.Println("It's a tie.")
fmt.Println("It's a tie.")
} else {
} else {
Line 201: Line 182:
}
}


// printHand print's the player's hand and current score.
/*
func (gm *GoFishGame) printHand() {
* Print player's hand and current score.
sort.Strings(gm.hands[0])
*/
fmt.Printf("You have: %s.\n", gm.hands[0])
func (self *GoFishGame) printHand() {
fmt.Printf("Score is %d to %d.\n", gm.scores[0], gm.scores[1])
sort.Strings(self._Hands[0])
sort.Strings(self._Hands[1])
fmt.Println("You have:", self._Hands[0])
fmt.Println("Score is", self._Scores[0], "to", self._Scores[1])
}
}


// stealCards removes all instances of a card from side's hand.
/*
func (gm *GoFishGame) stealCards(purge string, side int) int {
* Remove all occurences of aElem from the hand
count := 0
* represented by aSide.
tList := gm.hands[side]
*/
var filtered []string
func (self *GoFishGame) removeOccurences(aElem string, aSide int) int {
for _, card := range tList {
tCount := 0
if purge == card {
tList := self._Hands[aSide]
count++
var tFiltered []string
for _, tCard := range tList {
if tCard == aElem {
tCount++
} else {
} else {
tFiltered = append(tFiltered, tCard)
filtered = append(filtered, card)
}
}
}
}
self._Hands[aSide] = tFiltered
gm.hands[side] = filtered
return tCount
return count
}
}


// main creates the deck and initial hands.
/*
* Set up and begin the game.
*/
func main() {
func main() {
tDeck := makeDeck()
deck := makeDeck()
tPlayerHand := tDeck[0:9]
playerHand := deck[0:9]
tCompHand := tDeck[9:18]
compHand := deck[9:18]
tDeck = tDeck[18:]
deck = deck[18:]
tHands := make([][]string, 2, 2)
hands := make([][]string, 2, 2)
tHands[0] = tPlayerHand
hands[0] = playerHand
tHands[1] = tCompHand
hands[1] = compHand
tScores := make([]int, 2, 2)
scores := make([]int, 2, 2)
tScores[0] = 0
scores[0] = 0
tScores[1] = 0
scores[1] = 0
tGame := GoFishGame{tHands, tDeck, 0, tScores}
game := GoFishGame{hands, deck, 0, scores}
tGame.playerTurn(getPickUser)
game.playerTurn(getPickUser)
}
}
</lang>
</lang>

Revision as of 00:45, 1 June 2015

The AI selects cards randomly from its hand.


<lang go> package main

import ( "fmt" "math/rand" "sort" "time" )

var cards = [13]string{"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}

//GoFishGame Stores the game state. type GoFishGame struct { hands [][]string deck []string turn int scores []int }

// checkForBooks looks for fours of a kind // and scores them if we have them. // If we run out of cards, we draw more. func (gm *GoFishGame) checkForBooks() { sort.Strings(gm.hands[gm.turn]) prev := "" count := 1 for _, card := range gm.hands[gm.turn] { if card == prev { count++ if count == 4 { fmt.Printf("Book of %s.\n", card) gm.stealCards(card, gm.turn) gm.scores[gm.turn]++ if gm.isHandEmpty() { gm.drawCard() } } } else { count = 1 } prev = card } }

// drawCard takes a card from the deck // adding it to the current player's hand. func (gm *GoFishGame) drawCard() { if !gm.isDeckEmpty() { card := gm.deck[0] gm.deck = gm.deck[1:] if gm.turn == 0 { fmt.Printf("You drew a %s.\n", card) } gm.hands[gm.turn] = append(gm.hands[gm.turn], card) //Check for books gm.checkForBooks() } }

// endPly ends the current person's turn. // It then either calls the next person's // turn or prints a game over message. func (gm *GoFishGame) endPly() { gameOver := gm.isGameOver() if gameOver { gm.printGameOverMessage() } else if gm.turn == 1 { gm.playerTurn(getPickComputer) } else { gm.playerTurn(getPickUser) } }

// getPickComputer handles the computer's card choices. // We do the moderately smart thing of pick a random // card from our hand func getPickComputer(gm *GoFishGame) string { hand := gm.hands[1] choice := "A" if len(hand) > 0 { choice = hand[rand.Intn(len(hand))] } fmt.Printf("Computer picks %s.\n", choice) return choice }

// getPickUser gets the user's move. // If it's not valid, then the user just wastes // their turn. func getPickUser(gm *GoFishGame) string { fmt.Println("What card do you want?") var card string fmt.Scanf("%s\n", &card) return card }

// isDeckEmpty returns if the deck is empty. func (gm *GoFishGame) isDeckEmpty() bool { return len(gm.deck) == 0 }

// isHandEmpty returns if the current player's hand is empty. func (gm *GoFishGame) isHandEmpty() bool { return len(gm.hands[gm.turn]) == 0 }

// isGameOver returns if the game is over. // This happens when all 13 pips have been made into sets. func (gm *GoFishGame) isGameOver() bool { return gm.scores[0]+gm.scores[1] == 13 }

// makeDeck makes a deck. // The deck is 52 cards with 4 of each pip. func makeDeck() []string { rand.Seed(time.Now().UTC().UnixNano()) deck := make([]string, 52) perm := rand.Perm(52) for indx := range perm { tVal := perm[indx] card := cards[tVal/4] deck[indx] = card } return deck }

// opponentHas returns if the opponent's hand has a card. func (gm *GoFishGame) opponentHas(find string) bool { for _, card := range gm.hands[(gm.turn+1)%2] { if card == find { return true } } return false }

// playerTurn handles the major game logic. // It's used for both the player's and computer's turns, // with the different behavior handled by the getPick param. func (gm *GoFishGame) playerTurn(getPick func(*GoFishGame) string) { opponent := (gm.turn + 1) % 2 gm.checkForBooks() if opponent == 1 { gm.printHand() } if gm.isHandEmpty() { gm.drawCard() } gameOver := gm.isGameOver() if !gameOver { card := getPick(gm) if gm.opponentHas(card) { count := gm.stealCards(card, opponent) for indx := 0; indx < count; indx++ { gm.hands[gm.turn] = append(gm.hands[gm.turn], card) } gm.checkForBooks() } else { fmt.Println("GO FISH!") gm.drawCard() gm.turn = opponent } } gm.endPly() }

// printGameOverMessage prints the appropriate end message. func (gm *GoFishGame) printGameOverMessage() { fmt.Printf("Final score is %d to %d.\n", gm.scores[0], gm.scores[1]) if gm.scores[0] > gm.scores[1] { fmt.Println("Player wins!") } else if gm.scores[0] == gm.scores[1] { fmt.Println("It's a tie.") } else { fmt.Println("Computer wins!") } }

// printHand print's the player's hand and current score. func (gm *GoFishGame) printHand() { sort.Strings(gm.hands[0]) fmt.Printf("You have: %s.\n", gm.hands[0]) fmt.Printf("Score is %d to %d.\n", gm.scores[0], gm.scores[1]) }

// stealCards removes all instances of a card from side's hand. func (gm *GoFishGame) stealCards(purge string, side int) int { count := 0 tList := gm.hands[side] var filtered []string for _, card := range tList { if purge == card { count++ } else { filtered = append(filtered, card) } } gm.hands[side] = filtered return count }

// main creates the deck and initial hands. func main() { deck := makeDeck() playerHand := deck[0:9] compHand := deck[9:18] deck = deck[18:] hands := make([][]string, 2, 2) hands[0] = playerHand hands[1] = compHand scores := make([]int, 2, 2) scores[0] = 0 scores[1] = 0 game := GoFishGame{hands, deck, 0, scores} game.playerTurn(getPickUser) } </lang>