A minesweeper game

A minesweeper game

This code is organized as a package with a main function and several supporting functions. The main function sets up the game board. The supporting functions handle user input and various aspects of the game, such as generating the minefield, checking for win conditions, making moves and displaying the game board.

Here is the Code for the app. If you want to try it:

1. Copy the project into main.go

2. Run "go run main.go" in the terminal

package main

import (
   "bufio"
   "fmt"
   "log"
   "math/rand"
   "os"
   "strconv"
   "strings"
)

// Game

const (
   CELL_EMPTY    = 0
   CELL_HAS_MINE = 1
   CELL_HAS_FLAG = 2
   CELL_OPEN     = 3
)

func main() {
   x := 5
   y := 5
   mines := 5
   field := generateField(x, y)
   generateMines(field, mines)
   for !isGameEnded(field) {
      printField(field)
      command, x, y, err := readInput()
      if err != nil {
         log.Fatal(err)
      }
      if command == "o" {
         field = openCell(field, x, y)
      } else if command == "f" {
         field = flagCell(field, x, y)
      } else {
         fmt.Println("Unknown command")
      }
   }
   printResult(field)
   fmt.Println("You won!")
}

//readInput reads input from the user in format "o 1 2" or "f 1 2"
func readInput() (string, int, int, error) {
   println("--------------------")
   fmt.Println("Enter o x y to open a cell or f x y to flag a cell")
   in := bufio.NewReader(os.Stdin)
   line, err := in.ReadString('\n')
   if err != nil {
      return "", 0, 0, err
   }
   strs := strings.Split(line[0:len(line)-1], " ")
   command := strs[0]
   x, err := strconv.Atoi(strs[1])
   if err != nil {
      return "", 0, 0, err
   }
   y, err := strconv.Atoi(strs[2])
   if err != nil {
      log.Fatal(err)
   }
   println("--------------------")

   // convert to zero-based coordinates
   return command, x - 1, y - 1, nil
}

//generateField generates a field
func generateField(x, y int) [][]int {
   field := make([][]int, y)
   for i := range field {
      field[i] = make([]int, x)
   }
   return field
}

//generateMines generates mines
func generateMines(field [][]int, mines int) [][]int {
   for i := 0; i < mines; i++ {
      x := rand.Intn(len(field))
      y := rand.Intn(len(field[0]))
      if field[x][y] == 1 {
         mines++
      }
      field[x][y] = 1
   }
   return field
}

//printField prints the masked field
func printField(field [][]int) {
   for i := range field {
      for j := range field[i] {
         if field[i][j] == CELL_EMPTY || field[i][j] == CELL_HAS_MINE {
            fmt.Print("? ")
         } else if field[i][j] == CELL_HAS_FLAG {
            fmt.Print("F ")
         } else if field[i][j] == CELL_OPEN {
            minesAround := countMinesAround(field, i, j)
            fmt.Print(minesAround, " ")
         } else {
            fmt.Print(" ")
         }
      }
      fmt.Println()
   }
}

//printResult prints the unmasked field
func printResult(field [][]int) {
   for i := range field {
      for j := range field[i] {
         if field[i][j] == CELL_EMPTY {
            fmt.Print("o ")
         } else if field[i][j] == CELL_HAS_MINE {
            fmt.Print("* ")
         } else if field[i][j] == CELL_HAS_FLAG {
            fmt.Print("F ")
         } else if field[i][j] == CELL_OPEN {
            fmt.Print(". ")
         } else {
            fmt.Print(" ")
         }
      }
      fmt.Println()
   }
}

//openCell opens a cell
func openCell(field [][]int, x, y int) [][]int {
   if !cellExists(field, x, y) {
      fmt.Println("Cell does not exist")
      return field
   }
   if field[x][y] == CELL_HAS_MINE {
      printResult(field)
      log.Fatal("You lost!")
   } else if field[x][y] == CELL_EMPTY {
      openCellWithAdjacent(field, x, y)
   } else if field[x][y] == CELL_HAS_FLAG {
      fmt.Println("You can't open a flagged cell")
   } else if field[x][y] == CELL_OPEN {
      fmt.Println("This cell is already open")
   } else {
      fmt.Println("Unknown state of cell")
   }
   return field
}

//flagCell flags a cell
func flagCell(field [][]int, x, y int) [][]int {
   if field[x][y] == CELL_HAS_MINE {
      field[x][y] = CELL_HAS_FLAG
   } else if field[x][y] == CELL_EMPTY {
      field[x][y] = CELL_HAS_FLAG
   } else if field[x][y] == CELL_HAS_FLAG {
      fmt.Println("This cell is already flagged")
   } else if field[x][y] == CELL_OPEN {
      fmt.Println("You can't flag an open cell")
   } else {
      fmt.Println("Unknown state of cell")
   }
   return field
}

//isGameEnded checks if all mines are flagged and there are no empty cells
func isGameEnded(field [][]int) bool {
   for i := range field {
      for j := range field[i] {
         if field[i][j] == CELL_EMPTY {
            return false
         }
      }
   }
   return true
}

//countMinesAround checks counts mines around
func countMinesAround(field [][]int, x, y int) int {
   count := 0
   for i := -1; i <= 1; i++ {
      for j := -1; j <= 1; j++ {
         // check if index is out of bounds
         if !cellExists(field, x+i, y+j) {
            continue
         }
         // check if cell is a mine
         if field[x+i][y+j] == CELL_HAS_MINE {
            count++
         }
      }
   }
   return count
}

//openCellWithAdjacent opens adjacent cells
func openCellWithAdjacent(field [][]int, x, y int) [][]int {
   for i := -1; i <= 1; i++ {
      for j := -1; j <= 1; j++ {
         // check if index is out of bounds
         if !cellExists(field, x+i, y+j) {
            continue
         }
         // if cell is empty and has a mine around
         if field[x+i][y+j] == CELL_EMPTY && countMinesAround(field, x+i, y+j) > 0 {
            // simply open cell
            field[x+i][y+j] = CELL_OPEN
            // if cell is empty and has no mines around
         } else if field[x+i][y+j] == CELL_EMPTY && countMinesAround(field, x+i, y+j) == 0 {
            // open cell and open adjacent cells
            field[x+i][y+j] = CELL_OPEN
            field = openCellWithAdjacent(field, x+i, y+j)
         }

      }
   }
   return field
}

//cellExists checks if a cell exists ( slice index not out of range )
func cellExists(field [][]int, x, y int) bool {
   if x < 0 || y < 0 || x >= len(field) || y >= len(field[0]) {
      return false
   }
   return true
}        

要查看或添加评论,请登录

社区洞察

其他会员也浏览了