mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-12 07:40:50 -08:00
Added go for Battle
This commit is contained in:
266
00_Alternate_Languages/09_Battle/go/main.go
Normal file
266
00_Alternate_Languages/09_Battle/go/main.go
Normal file
@@ -0,0 +1,266 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
SEA_WIDTH = 6
|
||||
DESTROYER_LENGTH = 2
|
||||
CRUISER_LENGTH = 3
|
||||
CARRIER_LENGTH = 4
|
||||
)
|
||||
|
||||
type Point [2]int
|
||||
type Vector Point
|
||||
type Sea [][]int
|
||||
|
||||
func NewSea() Sea {
|
||||
s := make(Sea, 6)
|
||||
for r := 0; r < SEA_WIDTH; r++ {
|
||||
c := make([]int, 6)
|
||||
s[r] = c
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func getRandomVector() Vector {
|
||||
v := Vector{}
|
||||
|
||||
for {
|
||||
v[0] = rand.Intn(3) - 1
|
||||
v[1] = rand.Intn(3) - 1
|
||||
|
||||
if !(v[0] == 0 && v[1] == 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func addVector(p Point, v Vector) Point {
|
||||
newPoint := Point{}
|
||||
|
||||
newPoint[0] = p[0] + v[0]
|
||||
newPoint[1] = p[1] + v[1]
|
||||
|
||||
return newPoint
|
||||
}
|
||||
|
||||
func isWithinSea(p Point, s Sea) bool {
|
||||
return (1 <= p[0] && p[0] <= len(s)) && (1 <= p[1] && p[1] <= len(s))
|
||||
}
|
||||
|
||||
func valueAt(p Point, s Sea) int {
|
||||
return s[p[1]-1][p[0]-1]
|
||||
}
|
||||
|
||||
func reportInputError() {
|
||||
fmt.Printf("INVALID. SPECIFY TWO NUMBERS FROM 1 TO %d, SEPARATED BY A COMMA.\n", SEA_WIDTH)
|
||||
}
|
||||
|
||||
func getNextTarget(s Sea) Point {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Println("\n?")
|
||||
scanner.Scan()
|
||||
|
||||
vals := strings.Split(scanner.Text(), ",")
|
||||
|
||||
if len(vals) != 2 {
|
||||
reportInputError()
|
||||
continue
|
||||
}
|
||||
|
||||
x, xErr := strconv.Atoi(strings.TrimSpace(vals[0]))
|
||||
y, yErr := strconv.Atoi(strings.TrimSpace(vals[1]))
|
||||
|
||||
if (len(vals) != 2) || (xErr != nil) || (yErr != nil) {
|
||||
reportInputError()
|
||||
continue
|
||||
}
|
||||
|
||||
p := Point{}
|
||||
p[0] = x
|
||||
p[1] = y
|
||||
if isWithinSea(p, s) {
|
||||
return p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setValueAt(value int, p Point, s Sea) {
|
||||
s[p[1]-1][p[0]-1] = value
|
||||
}
|
||||
|
||||
func hasShip(s Sea, code int) bool {
|
||||
hasShip := false
|
||||
for r := 0; r < SEA_WIDTH; r++ {
|
||||
for c := 0; c < SEA_WIDTH; c++ {
|
||||
if s[r][c] == code {
|
||||
hasShip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasShip
|
||||
}
|
||||
|
||||
func countSunk(s Sea, codes []int) int {
|
||||
sunk := 0
|
||||
|
||||
for _, c := range codes {
|
||||
if !hasShip(s, c) {
|
||||
sunk += 1
|
||||
}
|
||||
}
|
||||
|
||||
return sunk
|
||||
}
|
||||
|
||||
func placeShip(s Sea, size, code int) {
|
||||
for {
|
||||
start := Point{}
|
||||
start[0] = rand.Intn(SEA_WIDTH) + 1
|
||||
start[1] = rand.Intn(SEA_WIDTH) + 1
|
||||
vector := getRandomVector()
|
||||
|
||||
point := start
|
||||
points := []Point{}
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
point = addVector(point, vector)
|
||||
points = append(points, point)
|
||||
}
|
||||
|
||||
clearPosition := true
|
||||
for _, p := range points {
|
||||
if !isWithinSea(p, s) {
|
||||
clearPosition = false
|
||||
break
|
||||
}
|
||||
if valueAt(p, s) > 0 {
|
||||
clearPosition = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !clearPosition {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, p := range points {
|
||||
setValueAt(code, p, s)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func setupShips(s Sea) {
|
||||
placeShip(s, DESTROYER_LENGTH, 1)
|
||||
placeShip(s, DESTROYER_LENGTH, 2)
|
||||
placeShip(s, CRUISER_LENGTH, 3)
|
||||
placeShip(s, CRUISER_LENGTH, 4)
|
||||
placeShip(s, CARRIER_LENGTH, 5)
|
||||
placeShip(s, CARRIER_LENGTH, 6)
|
||||
}
|
||||
|
||||
func printIntro() {
|
||||
fmt.Println(" BATTLE")
|
||||
fmt.Println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
fmt.Println()
|
||||
fmt.Println("THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION")
|
||||
fmt.Println("HAS BEEN CAPTURED BUT NOT DECODED: ")
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func printInstructions() {
|
||||
fmt.Println()
|
||||
fmt.Println()
|
||||
fmt.Println("DE-CODE IT AND USE IT IF YOU CAN")
|
||||
fmt.Println("BUT KEEP THE DE-CODING METHOD A SECRET.")
|
||||
fmt.Println()
|
||||
fmt.Println("START GAME")
|
||||
}
|
||||
|
||||
func printEncodedSea(s Sea) {
|
||||
for x := 0; x < SEA_WIDTH; x++ {
|
||||
fmt.Println()
|
||||
for y := SEA_WIDTH - 1; y > -1; y-- {
|
||||
fmt.Printf(" %d", s[y][x])
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func wipeout(s Sea) bool {
|
||||
for c := 1; c <= 7; c++ {
|
||||
if hasShip(s, c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
s := NewSea()
|
||||
|
||||
setupShips(s)
|
||||
|
||||
printIntro()
|
||||
|
||||
printEncodedSea(s)
|
||||
|
||||
printInstructions()
|
||||
|
||||
splashes := 0
|
||||
hits := 0
|
||||
|
||||
for {
|
||||
target := getNextTarget(s)
|
||||
targetValue := valueAt(target, s)
|
||||
|
||||
if targetValue < 0 {
|
||||
fmt.Printf("YOU ALREADY PUT A HOLE IN SHIP NUMBER %d AT THAT POINT.\n", targetValue)
|
||||
}
|
||||
|
||||
if targetValue <= 0 {
|
||||
fmt.Println("SPLASH! TRY AGAIN.")
|
||||
splashes += 1
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("A DIRECT HIT ON SHIP NUMBER %d\n", targetValue)
|
||||
hits += 1
|
||||
setValueAt(targetValue*-1, target, s)
|
||||
|
||||
if !hasShip(s, targetValue) {
|
||||
fmt.Println("AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS.")
|
||||
fmt.Println("SO FAR, THE BAD GUYS HAVE LOST")
|
||||
fmt.Printf("%d DESTROYER(S), %d CRUISER(S), AND %d AIRCRAFT CARRIER(S).\n", countSunk(s, []int{1, 2}), countSunk(s, []int{3, 4}), countSunk(s, []int{5, 6}))
|
||||
}
|
||||
|
||||
if !wipeout(s) {
|
||||
fmt.Printf("YOUR CURRENT SPLASH/HIT RATIO IS %2f\n", float32(splashes)/float32(hits))
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET WITH A FINAL SPLASH/HIT RATIO OF %2f\n", float32(splashes)/float32(hits))
|
||||
|
||||
if splashes == 0 {
|
||||
fmt.Println("CONGRATULATIONS -- A DIRECT HIT EVERY TIME.")
|
||||
}
|
||||
|
||||
fmt.Println("\n****************************")
|
||||
break
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user