Go Fish/Go: Difference between revisions
No edit summary |
(Less idiosyncratic and gofmt'ed.) |
||
Line 5: | Line 5: | ||
package main |
package main |
||
import |
import ( |
||
"fmt" |
|||
import "math/rand" |
|||
"math/rand" |
|||
import "sort" |
|||
"sort" |
|||
import "time" |
|||
"time" |
|||
) |
|||
var |
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 |
|||
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() { |
|||
* 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 { |
||
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() { |
|||
func (self *GoFishGame) drawCard() { |
|||
card := gm.deck[0] |
|||
if !self.isDeckEmpty() { |
|||
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) |
|||
} |
} |
||
gm.hands[gm.turn] = append(gm.hands[gm.turn], card) |
|||
//Check for books |
//Check for books |
||
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 { |
||
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. |
fmt.Printf("Computer picks %s.\n", choice) |
||
return |
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( |
func getPickUser(gm *GoFishGame) string { |
||
fmt.Println("What card do you want?") |
fmt.Println("What card do you want?") |
||
var |
var card string |
||
fmt.Scanf("%s\n", & |
fmt.Scanf("%s\n", &card) |
||
return |
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. |
|||
/* |
|||
// 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. |
|||
/* |
|||
// 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()) |
||
deck := make([]string, 52) |
|||
perm := rand.Perm(52) |
|||
for |
for indx := range perm { |
||
tVal := |
tVal := perm[indx] |
||
card := cards[tVal/4] |
|||
deck[indx] = card |
|||
} |
} |
||
return |
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. |
|||
/* |
|||
// 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) { |
|||
* 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 |
if gm.isHandEmpty() { |
||
gm.drawCard() |
|||
} |
} |
||
gameOver := gm.isGameOver() |
|||
if ! |
if !gameOver { |
||
card := getPick(gm) |
|||
if |
if gm.opponentHas(card) { |
||
count := gm.stealCards(card, opponent) |
|||
for |
for indx := 0; indx < count; indx++ { |
||
gm.hands[gm.turn] = append(gm.hands[gm.turn], card) |
|||
} |
} |
||
gm.checkForBooks() |
|||
} else { |
} else { |
||
fmt.Println("GO FISH!") |
|||
gm.drawCard() |
|||
self._Turn = tOpponent |
|||
gm.turn = opponent |
|||
} |
} |
||
} |
} |
||
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 |
} 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 { |
||
filtered = append(filtered, card) |
|||
} |
} |
||
} |
} |
||
gm.hands[side] = filtered |
|||
return |
return count |
||
} |
} |
||
// main creates the deck and initial hands. |
|||
/* |
|||
* Set up and begin the game. |
|||
*/ |
|||
func main() { |
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> |
</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>