6.1K
I’ve decided to play with the Go or Golang language and what better way to learn than to give yourself a small task and see if you can make it. So, I’ve made a small variant of the Battleship game. It’s my first project in Go and it can be much better optimized, but hey, it’s my first try. Save the source as battleship.go and start with go run battleship.go. Looks like this in a Linux terminal.
//-------------------------------- // Battleship - K.Andreev 20182907 // BSD 2.0 License // https://blog.andreev.it //-------------------------------- package main import ( "bufio" "fmt" "math/rand" "os" "strings" "time" ) //Size of the board 10 x 10 var intBoardSize = 10 //Total number of ships on each side var intTotalShips = 15 //Player's name var sYourName = "" //Holder for "press any key" var sAnyKey = "" //Number of player's turns var intPlayerTurns = 0 //Number of computer's turns var intComputerTurns = 0 //Who plays first var bPlayerFirst = true //How many ships left for the player var intPlayerShipsLeft = 15 //How many ships left for the computer var intComputerShipsLeft = 15 //Define a two dimensional array for the player var arrPlayerBoard [10][10]int //Define a two dimension array for the computer var arrComputerBoard [10][10]int //Define Unicode elements for on-screen presentation //If there are any issues with the display, change them here //const emptyElement = "\u25a2" //replace with " " //const shipElement = "\u25a3" //replace with "X" //const shipWreckElement = "\u25a4" //replace with "+" //const missedElement = "\u25a9" //replace with "o" const emptyElement = " " const shipElement = "X" const shipWreckElement = "+" const missedElement = "o" func main() { //Initialize the random generator rand.Seed(time.Now().UnixNano()) //Print the initial greetings and instructions printInstructions() //Initialize the boards initBoard() //Get player's name inputYourName() //Print the boards printBoard() //Get the player's ships (coordinates) inputFleet() //Generate computer's fleet generateComputerFleet() //Print the boards printBoard() //Who plays first decideFirstPlayer() //MAIN GAME LOOP for { if bPlayerFirst { playerMove() computerMove() } else { computerMove() playerMove() } } } //Print's game instructions func printInstructions() { fmt.Println(" ==========") fmt.Println(" Battleship") fmt.Println(" ==========") fmt.Println("") fmt.Println("The goal of this game is to sink all of the enemy's ships on the", intBoardSize, "X", intBoardSize, "board.") fmt.Println("You do that by guessing ship's location using coordinates (e.g. LAUNCH AT> C3).") fmt.Println("If you or the computer hit a ship, another chance is given until you miss again.") fmt.Println("The game is over when you or the opponent sinks all", intTotalShips, "ships.") fmt.Println("") fmt.Println("To make the game more difficult, you won't see where you missed on the computer board") fmt.Println("...and the computer won't hit the same place twice. HAVE FUN!!!") fmt.Println("") fmt.Println("K.Andreev - 20180729 - BSD Simplified License") } //Initialized both boards with zero values //Sets the number of ships func initBoard() { i := 0 j := 0 intPlayerShipsLeft = 15 intComputerShipsLeft = 15 intPlayerTurns = 0 intComputerTurns = 0 for i = 0; i < intBoardSize; i++ { for j = 0; j < intBoardSize; j++ { arrPlayerBoard[i][j] = 0 arrComputerBoard[i][j] = 0 } } } //Gets player's name func inputYourName() { fmt.Println("") fmt.Print("Enter your name: ") fmt.Scanln(&sYourName) fmt.Println("") fmt.Println("Hello,", sYourName, "!") fmt.Println("") fmt.Println("Please place your fleet using coordinates (e.g. D5)") fmt.Println("If you make a mistake, re-enter the same coordinate.") fmt.Println("") pressAnyKey() } //Ask the player to enter the coordinates of the fleet func inputFleet() { intShipCounter := 0 intXCoord := 0 intYCoord := 0 sPosition := "" fmt.Println("") for { enter: fmt.Print("SHIP AT> ") fmt.Scan(&sPosition) //If the length is different than two, coordinate is wrong if len(sPosition) != 2 { fmt.Println("INVALID POSITION.") goto enter } //Convert the coordiantes in array position, e.g. A0 is (0,0), J9 is (9,9) sPosition = strings.ToUpper(sPosition) intXCoord = int(sPosition[0] - 65) intYCoord = int(sPosition[1] - 48) //If the array coordinate is not in [(0,0)..(9,9)] range, coordinate is wrong if intXCoord < 0 || intXCoord > 9 { fmt.Println("INVALID POSITION.") goto enter } //If the player already entered a ship at a coordinate, toggle it, make it empty if arrPlayerBoard[intXCoord][intYCoord] == 1 { arrPlayerBoard[intXCoord][intYCoord] = 0 } else { arrPlayerBoard[intXCoord][intYCoord] = 1 intShipCounter = intShipCounter + 1 } printBoard() //Exit when all 15 ships are placed if intShipCounter == 15 { break } } } //Prints the boards on the screen func printBoard() { fmt.Println(sYourName) i := 0 j := 0 intPlayerShipCounter := 0 intComputerShipCounter := 0 sChar := 'A' fmt.Println(" 0123456789") //Prints player's board for i = 0; i < intBoardSize; i++ { fmt.Print(string(sChar)) sChar = sChar + 1 for j = 0; j < intBoardSize; j++ { switch arrPlayerBoard[i][j] { case 0: fmt.Print(emptyElement) case 1: fmt.Print(shipElement) intPlayerShipCounter = intPlayerShipCounter + 1 case 2: fmt.Print(shipWreckElement) case 3: fmt.Print(missedElement) } } fmt.Println("") } //Prints player's ships left and the total fmt.Println("SHIPS", intPlayerShipCounter, "/", intTotalShips) fmt.Println("") //Prints computer's board fmt.Println("COMPUTER") i = 0 j = 0 sChar = 'A' fmt.Println(" 0123456789") for i = 0; i < intBoardSize; i++ { fmt.Print(string(sChar)) sChar = sChar + 1 for j = 0; j < intBoardSize; j++ { switch arrComputerBoard[i][j] { case 0: fmt.Print(emptyElement) case 1: //Uncomment the line below to see computer's ships (cheat) //fmt.Print(shipElement) intComputerShipCounter = intComputerShipCounter + 1 case 2: fmt.Print(shipWreckElement) case 3: fmt.Print(missedElement) } } fmt.Println("") } //Prints computer's ships left and the total fmt.Println("SHIPS", intComputerShipCounter, "/", intTotalShips) } //Places computer's fleet using random generator func generateComputerFleet() { intShipCounter := 0 intRandomShipatX := 0 intRandomShipatY := 0 for { intRandomShipatX = rand.Intn(10) intRandomShipatY = rand.Intn(10) if arrComputerBoard[intRandomShipatX][intRandomShipatY] == 0 { arrComputerBoard[intRandomShipatX][intRandomShipatY] = 1 intShipCounter = intShipCounter + 1 } if intShipCounter == 15 { break } } } //Who plays first. A number between 0 and 99 is drawn for both players. //The bigger number plays first. func decideFirstPlayer() { intPlayerFirst := 0 intComputerFirst := 0 fmt.Println("") fmt.Println("Prepare for the battle...") intPlayerFirst = rand.Intn(100) intComputerFirst = rand.Intn(100) if intPlayerFirst >= intComputerFirst { bPlayerFirst = true fmt.Println("You play first. Random numbers say", intPlayerFirst, "vs.", intComputerFirst) fmt.Scanln(&sAnyKey) pressAnyKey() } else { bPlayerFirst = false fmt.Println("Computer plays first. Random numbers say", intComputerFirst, "vs.", intPlayerFirst) fmt.Scanln(&sAnyKey) pressAnyKey() } } //Get the player to input a coordinate func playerMove() { intXCoord := 0 intYCoord := 0 sPosition := "" fmt.Println("") enter: for { fmt.Print("LAUNCH AT> ") fmt.Scan(&sPosition) //Same checks for invalid position if len(sPosition) != 2 { fmt.Println("INVALID POSITION.") goto enter } sPosition = strings.ToUpper(sPosition) intXCoord = int(sPosition[0] - 65) intYCoord = int(sPosition[1] - 48) if intXCoord < 0 || intXCoord > 9 { fmt.Println("INVALID POSITION.") goto enter } //Increase the turns number intPlayerTurns = intPlayerTurns + 1 //This is a miss if the board has 0 value at the coordinate if arrComputerBoard[intXCoord][intYCoord] == 0 { fmt.Print("You missed at ", sPosition, ".") fmt.Scanln(&sAnyKey) pressAnyKey() } else { //This is a hit arrComputerBoard[intXCoord][intYCoord] = 2 fmt.Print("YOU HIT A SHIP AT ", sPosition, ".") fmt.Scanln(&sAnyKey) pressAnyKey() printBoard() intComputerShipsLeft = intComputerShipsLeft - 1 //Game over if all ships are hit if intComputerShipsLeft == 0 { fmt.Println("================") fmt.Println("[ YOU WON ]") fmt.Println("================") fmt.Println(intPlayerTurns, "turns to complete the game...") os.Exit(0) } goto enter } printBoard() break } } //Computer logic for the play func computerMove() { intRandomShipatX := 0 intRandomShipatY := 0 enter: for { //Get a random coordinate intRandomShipatX = rand.Intn(10) intRandomShipatY = rand.Intn(10) //Increase the number of turns intComputerTurns = intComputerTurns + 1 //If it's a miss, remember that position by placing "3" and never hit that position again if arrPlayerBoard[intRandomShipatX][intRandomShipatY] == 0 { arrPlayerBoard[intRandomShipatX][intRandomShipatY] = 3 fmt.Println("Computer missed at", string(intRandomShipatX+65), string(intRandomShipatY+48)) pressAnyKey() printBoard() break } //If it's a hit, mark the ship as hit by placing "2" if arrPlayerBoard[intRandomShipatX][intRandomShipatY] == 1 { arrPlayerBoard[intRandomShipatX][intRandomShipatY] = 2 fmt.Println("COMPUTER HIT A SHIP at", string(intRandomShipatX+65), string(intRandomShipatY+48)) pressAnyKey() printBoard() intPlayerShipsLeft = intPlayerShipsLeft - 1 if intPlayerShipsLeft == 0 { fmt.Println("================") fmt.Println("[ COMPUTER WON ]") fmt.Println("================") fmt.Println(intComputerTurns, "turns to complete the game...") os.Exit(0) } else { goto enter } } //If the random coordinate is where the ship was already hit, go guess again if arrPlayerBoard[intRandomShipatX][intRandomShipatY] == 2 { goto enter } //If the random coordinate is where we missed, go guess again if arrPlayerBoard[intRandomShipatX][intRandomShipatY] == 3 { goto enter } } } //Wait for any key to be pressed func pressAnyKey() { in := bufio.NewReader(os.Stdin) line, _ := in.ReadString('\n') _ = line }