Make the game minesweeper working!! Horray!!

This commit is contained in:
Syed Daanish
2024-12-27 21:25:26 +03:00
parent fdb11e1e4d
commit 4d5cb45c75

340
main.go
View File

@@ -1,7 +1,12 @@
package main package main
import ( import (
"errors"
"fmt"
"log" "log"
"math/rand"
"strings"
"time"
"unicode/utf8" "unicode/utf8"
"github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2"
@@ -10,27 +15,49 @@ import (
var start int var start int
var pline int var pline int
var screen tcell.Screen
var symbols []rune var symbols []rune
var numbers []rune
var mousey bool
var mouseThing string
var gameOver bool
type cell struct {
err bool
mines int
flag bool
reveal bool
isMine bool
color string
}
func main() { func main() {
symbols = []rune("󰞔󰪸󰸞") symbols = []rune("󰸞󰷚󰉀")
// Initialize a new screen numbers = []rune("🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹")
screen, err := tcell.NewScreen() start = 0
pline = 30
screen_tmp, err := tcell.NewScreen()
if err != nil { if err != nil {
log.Fatalf("Failed to create screen: %v", err) log.Fatalf("Failed to create screen: %v", err)
} }
defer screen.Fini() defer screen_tmp.Fini()
if err := screen_tmp.Init(); err != nil {
if err := screen.Init(); err != nil {
log.Fatalf("Failed to initialize screen: %v", err) log.Fatalf("Failed to initialize screen: %v", err)
} }
screen = screen_tmp
// Clear the screen screen.EnableMouse()
screen.Clear() screen.Clear()
// Show the screen
screen.Show() screen.Show()
// Wait for an event var fx, fy int
board, _ := gen_board(10, 10, 15, fx, fy)
print_it(fmt.Sprintf("Welcome to go-mines! %c %c", symbols[4], symbols[5]))
refresh(board)
for { for {
ev := screen.PollEvent() ev := screen.PollEvent()
switch ev := ev.(type) { switch ev := ev.(type) {
@@ -41,35 +68,262 @@ func main() {
if ev.Key() == tcell.KeyCtrlC { if ev.Key() == tcell.KeyCtrlC {
return return
} }
case *tcell.EventResize: case *tcell.EventMouse:
screen.Sync() x, y := ev.Position()
screen.Clear() button := buttonify(ev.Buttons())
refresh(screen) boardX := x / 5
boardY := y / 3
if fx == 0 && fy == 0 {
fx = boardX
fx = boardY
board, _ = gen_board(10, 10, 15, fx, fy)
}
if !gameOver {
if (button == "L" || button == "R") && !mousey {
mouseThing = button
if mouseThing == "L" {
_ = reveal(board, boardX, boardY, len(board[0]), len(board))
} else if mouseThing == "R" {
_ = flag(board, boardX, boardY, len(board[0]), len(board))
}
mousey = true
mouseThing = ""
} else if button != "L" && button != "R" {
mousey = false
}
}
screen.Show() screen.Show()
case *tcell.EventResize:
// screen.Sync()
// screen.Clear()
// refresh(board)
// screen.Show()
} }
} }
} }
func refresh(screen tcell.Screen) { func refresh(board [][]cell) {
start = 0 solved := true
pline = 25 for i := 0; i < len(board); i++ {
// width, height := screen.Size() for j := 0; j < len(board[0]); j++ {
// Draw some text if board[i][j].isMine && board[i][j].reveal {
// style := tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorBlack) solved = false
print_it(screen, "Welcome to go-mines!") break
draw_box(screen, 7, 24, 47, pline, tcell.StyleDefault.Background(tcell.GetColor("#00000000")).Foreground(tcell.GetColor("#FFFF00")), "") } else if !board[i][j].isMine && !board[i][j].reveal {
solved = false
break
}
}
}
if solved {
print_it("You won!")
gameOver = true
}
print_board(board)
} }
func print_it(s tcell.Screen, str string) { func reveal(board [][]cell, x, y, width, height int) error {
s.SetContent(9, pline, symbols[7], nil, tcell.StyleDefault.Background(tcell.GetColor("#00000000")).Foreground(tcell.GetColor("#FFFF00"))) if x < 0 || x >= width || y < 0 || y >= height {
s.SetContent(10, pline, ' ', nil, tcell.StyleDefault.Background(tcell.GetColor("#00000000")).Foreground(tcell.GetColor("#FFFFFF"))) return nil
}
if board[y][x].reveal {
return nil
}
board[y][x].flag = false
board[y][x].reveal = true
if board[y][x].isMine {
board[y][x].err = true
print_it("Game Over! You hit a mine!")
gameOver = true
for i := 0; i < height; i++ {
for j := 0; j < width; j++ {
if board[i][j].isMine {
board[i][j].reveal = true
} else if board[i][j].flag && !board[i][j].isMine {
board[i][j].err = true
}
}
}
refresh(board)
return nil
}
if board[y][x].mines == 0 {
directions := []struct{ dx, dy int }{
{-1, -1}, {0, -1}, {1, -1},
{-1, 0}, {1, 0},
{-1, 1}, {0, 1}, {1, 1},
}
for _, dir := range directions {
nx, ny := x+dir.dx, y+dir.dy
if nx >= 0 && nx < width && ny >= 0 && ny < height {
if !board[ny][nx].reveal {
reveal(board, nx, ny, width, height)
}
}
}
}
refresh(board)
return nil
}
func flag(board [][]cell, x, y, width, height int) error {
if x < 0 || x >= width || y < 0 || y >= height {
return nil
}
if board[y][x].reveal {
return nil
}
board[y][x].flag = !board[y][x].flag
refresh(board)
return nil
}
func gen_board(width, height, mines, fx, fy int) ([][]cell, error) {
board := make([][]cell, height)
for i := range board {
board[i] = make([]cell, width)
}
if mines >= width*height {
return board, errors.New("too many mines")
}
source := rand.NewSource(time.Now().UnixNano())
rand := rand.New(source)
mineCount := 0
for mineCount < mines {
x := rand.Intn(width)
y := rand.Intn(height)
if (x == fx && y == fy) || board[y][x].isMine {
continue
}
if !board[y][x].isMine {
board[y][x].isMine = true
mineCount++
}
}
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
if board[y][x].isMine {
continue
}
board[y][x].mines = count_mines(board, x, y, width, height)
colors := map[int]string{
0: "#41e8b0",
1: "#7cc7ff",
2: "#66c266",
3: "#ff7788",
4: "#ee88ff",
5: "#ddaa22",
6: "#66cccc",
7: "#999999",
8: "#d0d8e0",
}
board[y][x].color = colors[board[y][x].mines]
}
}
return board, nil
}
func count_mines(board [][]cell, x, y, width, height int) int {
directions := []struct{ dx, dy int }{
{-1, -1}, {0, -1}, {1, -1},
{-1, 0}, {1, 0},
{-1, 1}, {0, 1}, {1, 1},
}
count := 0
for _, dir := range directions {
nx, ny := x+dir.dx, y+dir.dy
if nx >= 0 && nx < width && ny >= 0 && ny < height && board[ny][nx].isMine {
count++
}
}
return count
}
func print_board(board [][]cell) {
style := tcell.StyleDefault.Foreground(tcell.ColorWhite)
style2 := tcell.StyleDefault.Foreground(tcell.ColorWhite)
chars_i := "▔▕🭽🭼🭾🭿▏▁"
symbol := "H"
for i := 0; i < len(board); i++ {
for j := 0; j < len(board[0]); j++ {
chars_i = "▔▕🭽🭼🭾🭿▏▁"
if board[i][j].mines == 0 && board[i][j].reveal && !board[i][j].isMine {
symbol = ""
style = tcell.StyleDefault.Background(tcell.GetColor("#384048")).Foreground(tcell.GetColor("#1f272f"))
style2 = tcell.StyleDefault.Background(tcell.GetColor("#384048")).Foreground(tcell.GetColor("#1f272f"))
} else if board[i][j].flag && !board[i][j].err {
symbol = string(symbols[5])
style = tcell.StyleDefault.Background(tcell.GetColor("#4c545c")).Foreground(tcell.GetColor("#707880"))
style2 = tcell.StyleDefault.Background(tcell.GetColor("#4c545c")).Foreground(tcell.GetColor("#ff7d7d"))
chars_i = "🬂▐🬕🬲🬨🬷▌🬭"
} else if board[i][j].flag && board[i][j].err {
symbol = string(symbols[5])
style = tcell.StyleDefault.Background(tcell.GetColor("#883333")).Foreground(tcell.GetColor("#671212"))
style2 = tcell.StyleDefault.Background(tcell.GetColor("#883333")).Foreground(tcell.GetColor("#ff7d7d"))
chars_i = "🬂▐🬕🬲🬨🬷▌🬭"
} else if board[i][j].isMine && board[i][j].reveal && !board[i][j].err {
symbol = string(symbols[4])
style = tcell.StyleDefault.Background(tcell.GetColor("#464e56")).Foreground(tcell.GetColor("#1f272f"))
style2 = tcell.StyleDefault.Background(tcell.GetColor("#464e56")).Foreground(tcell.GetColor("#000000"))
} else if board[i][j].isMine && board[i][j].reveal && board[i][j].err {
symbol = string(symbols[4])
style = tcell.StyleDefault.Background(tcell.GetColor("#ee6666")).Foreground(tcell.GetColor("#1f272f"))
style2 = tcell.StyleDefault.Background(tcell.GetColor("#ee6666")).Foreground(tcell.GetColor("#000000"))
} else if !board[i][j].reveal {
symbol = ""
style = tcell.StyleDefault.Background(tcell.GetColor("#4c545c")).Foreground(tcell.GetColor("#707880")).Bold(true)
style2 = tcell.StyleDefault.Background(tcell.GetColor("#4c545c")).Foreground(tcell.GetColor("#707880")).Bold(true)
chars_i = "🬂▐🬕🬲🬨🬷▌🬭"
} else {
symbol = string(numbers[board[i][j].mines])
style = tcell.StyleDefault.Background(tcell.GetColor("#384048")).Foreground(tcell.GetColor("#1f272f")).Bold(true)
style2 = tcell.StyleDefault.Background(tcell.GetColor("#384048")).Foreground(tcell.GetColor(board[i][j].color)).Bold(true)
}
print_at(j*5, i*3+1, fmt.Sprint(" ", symbol, " "), style2)
draw_box(j*5, i*3, j*5+4, i*3+2, style, chars_i)
}
}
}
func buttonify(button tcell.ButtonMask) string {
var parts []string
if button&tcell.Button1 != 0 {
parts = append(parts, "L")
}
if button&tcell.Button2 != 0 {
parts = append(parts, "R")
}
if button&tcell.Button3 != 0 {
parts = append(parts, "M")
}
if button&tcell.WheelUp != 0 {
parts = append(parts, "U")
}
if button&tcell.WheelDown != 0 {
parts = append(parts, "D")
}
if len(parts) == 0 {
return ""
}
return strings.Join(parts, "")
}
func print_it(str string) {
screen.SetContent(9, pline, symbols[3], nil, tcell.StyleDefault.Background(tcell.GetColor("#00000000")).Foreground(tcell.GetColor("#FFFF00")))
screen.SetContent(10, pline, ' ', nil, tcell.StyleDefault.Background(tcell.GetColor("#00000000")).Foreground(tcell.GetColor("#FFFFFF")))
for i, char := range []rune(str) { for i, char := range []rune(str) {
s.SetContent(12+i, pline, char, nil, tcell.StyleDefault.Background(tcell.GetColor("#00000000")).Foreground(tcell.GetColor("#FFFFFF"))) screen.SetContent(12+i, pline, char, nil, tcell.StyleDefault.Background(tcell.GetColor("#00000000")).Foreground(tcell.GetColor("#FFFFFF")))
} }
pline++ pline++
} }
func draw_box(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, chars_i string) { func print_at(x, y int, str string, style tcell.Style) {
for i, char := range []rune(str) {
screen.SetContent(x+i, y, char, nil, style)
}
}
func draw_box(x1, y1, x2, y2 int, style tcell.Style, chars_i string) {
if chars_i == "" { if chars_i == "" {
chars_i = "─│╭╰╮╯" // "━┃┏┗┓┛" chars_i = "─│╭╰╮╯" // "━┃┏┗┓┛"
} }
@@ -77,38 +331,38 @@ func draw_box(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, chars_i str
if utf8.RuneCountInString(chars_i) == 6 { if utf8.RuneCountInString(chars_i) == 6 {
chars := []rune(chars_i) chars := []rune(chars_i)
for x := x1; x <= x2; x++ { for x := x1; x <= x2; x++ {
s.SetContent(x, y1, chars[0], nil, style) screen.SetContent(x, y1, chars[0], nil, style)
} }
for x := x1; x <= x2; x++ { for x := x1; x <= x2; x++ {
s.SetContent(x, y2, chars[0], nil, style) screen.SetContent(x, y2, chars[0], nil, style)
} }
for x := y1 + 1; x < y2; x++ { for x := y1 + 1; x < y2; x++ {
s.SetContent(x1, x, chars[1], nil, style) screen.SetContent(x1, x, chars[1], nil, style)
} }
for x := y1 + 1; x < y2; x++ { for x := y1 + 1; x < y2; x++ {
s.SetContent(x2, x, chars[1], nil, style) screen.SetContent(x2, x, chars[1], nil, style)
} }
s.SetContent(x1, y1, chars[2], nil, style) screen.SetContent(x1, y1, chars[2], nil, style)
s.SetContent(x1, y2, chars[3], nil, style) screen.SetContent(x1, y2, chars[3], nil, style)
s.SetContent(x2, y1, chars[4], nil, style) screen.SetContent(x2, y1, chars[4], nil, style)
s.SetContent(x2, y2, chars[5], nil, style) screen.SetContent(x2, y2, chars[5], nil, style)
} else { } else {
chars := []rune(chars_i) chars := []rune(chars_i)
for x := x1; x <= x2; x++ { for x := x1; x <= x2; x++ {
s.SetContent(x, y1, chars[0], nil, style) screen.SetContent(x, y1, chars[0], nil, style)
} }
for x := x1; x <= x2; x++ { for x := x1; x <= x2; x++ {
s.SetContent(x, y2, chars[7], nil, style) screen.SetContent(x, y2, chars[7], nil, style)
} }
for x := y1 + 1; x < y2; x++ { for x := y1 + 1; x < y2; x++ {
s.SetContent(x1, x, chars[6], nil, style) screen.SetContent(x1, x, chars[6], nil, style)
} }
for x := y1 + 1; x < y2; x++ { for x := y1 + 1; x < y2; x++ {
s.SetContent(x2, x, chars[1], nil, style) screen.SetContent(x2, x, chars[1], nil, style)
} }
s.SetContent(x1, y1, chars[2], nil, style) screen.SetContent(x1, y1, chars[2], nil, style)
s.SetContent(x1, y2, chars[3], nil, style) screen.SetContent(x1, y2, chars[3], nil, style)
s.SetContent(x2, y1, chars[4], nil, style) screen.SetContent(x2, y1, chars[4], nil, style)
s.SetContent(x2, y2, chars[5], nil, style) screen.SetContent(x2, y2, chars[5], nil, style)
} }
} }