From b8aa3daaa03498f7cd4721c639e0ca4e49cb0f2f Mon Sep 17 00:00:00 2001 From: Troy Campbell Date: Thu, 20 Oct 2022 12:13:27 +1000 Subject: [PATCH] Added go for Battle --- 00_Alternate_Languages/09_Battle/go/main.go | 266 ++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 00_Alternate_Languages/09_Battle/go/main.go diff --git a/00_Alternate_Languages/09_Battle/go/main.go b/00_Alternate_Languages/09_Battle/go/main.go new file mode 100644 index 00000000..c0f911f4 --- /dev/null +++ b/00_Alternate_Languages/09_Battle/go/main.go @@ -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 + } +}