mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-12 15:50:20 -08:00
Added go version of Batnum
This commit is contained in:
248
00_Alternate_Languages/08_Batnum/go/main.go
Normal file
248
00_Alternate_Languages/08_Batnum/go/main.go
Normal file
@@ -0,0 +1,248 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type StartOption int8
|
||||
|
||||
const (
|
||||
StartUndefined StartOption = iota
|
||||
ComputerFirst
|
||||
PlayerFirst
|
||||
)
|
||||
|
||||
type WinOption int8
|
||||
|
||||
const (
|
||||
WinUndefined WinOption = iota
|
||||
TakeLast
|
||||
AvoidLast
|
||||
)
|
||||
|
||||
type GameOptions struct {
|
||||
pileSize int
|
||||
winOption WinOption
|
||||
startOption StartOption
|
||||
minSelect int
|
||||
maxSelect int
|
||||
}
|
||||
|
||||
func NewOptions() *GameOptions {
|
||||
g := GameOptions{}
|
||||
|
||||
g.pileSize = getPileSize()
|
||||
if g.pileSize < 0 {
|
||||
return &g
|
||||
}
|
||||
|
||||
g.winOption = getWinOption()
|
||||
g.minSelect, g.maxSelect = getMinMax()
|
||||
g.startOption = getStartOption()
|
||||
|
||||
return &g
|
||||
}
|
||||
|
||||
func getPileSize() int {
|
||||
ps := 0
|
||||
var err error
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Println("Enter Pile Size ")
|
||||
scanner.Scan()
|
||||
ps, err = strconv.Atoi(scanner.Text())
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
func getWinOption() WinOption {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Println("ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST:")
|
||||
scanner.Scan()
|
||||
w, err := strconv.Atoi(scanner.Text())
|
||||
if err == nil && (w == 1 || w == 2) {
|
||||
return WinOption(w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getStartOption() StartOption {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Println("ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ")
|
||||
scanner.Scan()
|
||||
s, err := strconv.Atoi(scanner.Text())
|
||||
if err == nil && (s == 1 || s == 2) {
|
||||
return StartOption(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getMinMax() (int, int) {
|
||||
minSelect := 0
|
||||
maxSelect := 0
|
||||
var minErr error
|
||||
var maxErr error
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Println("ENTER MIN AND MAX ")
|
||||
scanner.Scan()
|
||||
enteredValues := scanner.Text()
|
||||
vals := strings.Split(enteredValues, " ")
|
||||
minSelect, minErr = strconv.Atoi(vals[0])
|
||||
maxSelect, maxErr = strconv.Atoi(vals[1])
|
||||
if (minErr == nil) && (maxErr == nil) && (minSelect > 0) && (maxSelect > 0) && (maxSelect > minSelect) {
|
||||
return minSelect, maxSelect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This handles the player's turn - asking the player how many objects
|
||||
// to take and doing some basic validation around that input. Then it
|
||||
// checks for any win conditions.
|
||||
// Returns a boolean indicating whether the game is over and the new pile_size.
|
||||
func playerMove(pile, min, max int, win WinOption) (bool, int) {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
done := false
|
||||
for !done {
|
||||
fmt.Println("YOUR MOVE")
|
||||
scanner.Scan()
|
||||
m, err := strconv.Atoi(scanner.Text())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if m == 0 {
|
||||
fmt.Println("I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.")
|
||||
return true, pile
|
||||
}
|
||||
|
||||
if m > max || m < min {
|
||||
fmt.Println("ILLEGAL MOVE, REENTER IT")
|
||||
continue
|
||||
}
|
||||
|
||||
pile -= m
|
||||
done = true
|
||||
|
||||
if pile <= 0 {
|
||||
if win == AvoidLast {
|
||||
fmt.Println("TOUGH LUCK, YOU LOSE.")
|
||||
} else {
|
||||
fmt.Println("CONGRATULATIONS, YOU WIN.")
|
||||
}
|
||||
return true, pile
|
||||
}
|
||||
}
|
||||
return false, pile
|
||||
}
|
||||
|
||||
// This handles the logic to determine how many objects the computer
|
||||
// will select on its turn.
|
||||
func computerPick(pile, min, max int, win WinOption) int {
|
||||
var q int
|
||||
if win == AvoidLast {
|
||||
q = pile - 1
|
||||
} else {
|
||||
q = pile
|
||||
}
|
||||
c := min + max
|
||||
|
||||
pick := q - (c * int(q/c))
|
||||
|
||||
if pick < min {
|
||||
pick = min
|
||||
} else if pick > max {
|
||||
pick = max
|
||||
}
|
||||
|
||||
return pick
|
||||
}
|
||||
|
||||
// This handles the computer's turn - first checking for the various
|
||||
// win/lose conditions and then calculating how many objects
|
||||
// the computer will take.
|
||||
// Returns a boolean indicating whether the game is over and the new pile_size.
|
||||
func computerMove(pile, min, max int, win WinOption) (bool, int) {
|
||||
// first check for end-game conditions
|
||||
if win == TakeLast && pile <= max {
|
||||
fmt.Printf("COMPUTER TAKES %d AND WINS\n", pile)
|
||||
return true, pile
|
||||
}
|
||||
|
||||
if win == AvoidLast && pile <= min {
|
||||
fmt.Printf("COMPUTER TAKES %d AND LOSES\n", pile)
|
||||
return true, pile
|
||||
}
|
||||
|
||||
// otherwise determine the computer's selection
|
||||
selection := computerPick(pile, min, max, win)
|
||||
pile -= selection
|
||||
fmt.Printf("COMPUTER TAKES %d AND LEAVES %d\n", selection, pile)
|
||||
return false, pile
|
||||
}
|
||||
|
||||
// This is the main game loop - repeating each turn until one
|
||||
// of the win/lose conditions is met.
|
||||
func play(pile, min, max int, start StartOption, win WinOption) {
|
||||
gameOver := false
|
||||
playersTurn := (start == PlayerFirst)
|
||||
|
||||
for !gameOver {
|
||||
if playersTurn {
|
||||
gameOver, pile = playerMove(pile, min, max, win)
|
||||
playersTurn = false
|
||||
if gameOver {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !playersTurn {
|
||||
gameOver, pile = computerMove(pile, min, max, win)
|
||||
playersTurn = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print out the introduction and rules of the game
|
||||
func printIntro() {
|
||||
fmt.Printf("%33s%s\n", " ", "BATNUM")
|
||||
fmt.Printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY")
|
||||
fmt.Printf("\n\n\n")
|
||||
fmt.Println("THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE")
|
||||
fmt.Println("COMPUTER IS YOUR OPPONENT.")
|
||||
fmt.Println()
|
||||
fmt.Println("THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU")
|
||||
fmt.Println("AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.")
|
||||
fmt.Println("WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR")
|
||||
fmt.Println("NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.")
|
||||
fmt.Println("DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.")
|
||||
fmt.Println("ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.")
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func main() {
|
||||
for {
|
||||
printIntro()
|
||||
|
||||
g := NewOptions()
|
||||
|
||||
if g.pileSize < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
play(g.pileSize, g.minSelect, g.maxSelect, g.startOption, g.winOption)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user