Added go for Battle

This commit is contained in:
Troy Campbell
2022-10-20 12:13:27 +10:00
parent 7a882ea317
commit b8aa3daaa0

View 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
}
}