go语言实现扫雷

打印 上一主题 下一主题

主题 865|帖子 865|积分 2595

源码如下
  1. package main
  2. import (
  3.         "archive/zip"
  4.         "bytes"
  5.         "encoding/base64"
  6.         "fmt"
  7.         "image"
  8.         "image/color"
  9.         "image/png"
  10.         "log"
  11.         "math/rand"
  12.         "strings"
  13.         "time"
  14.         "github.com/hajimehoshi/ebiten/v2"
  15.         "github.com/hajimehoshi/ebiten/v2/ebitenutil"
  16.         "github.com/hajimehoshi/ebiten/v2/inpututil"
  17. )
  18. func main() {
  19.         //goland:noinspection GoDeprecation
  20.         rand.Seed(time.Now().Unix())
  21.         m := &mine{h: 16, w: 30, mineCnt: 99}
  22.         err := m.loadResources()
  23.         if err != nil {
  24.                 log.Fatal(err)
  25.         }
  26.         m.initData() // 开局初始数据
  27.         ebiten.SetWindowTitle("Mine Sweeping")
  28.         if err = ebiten.RunGame(m); err != nil {
  29.                 log.Fatal(err)
  30.         }
  31. }
  32. const (
  33.         gridHW = 16 // 格子宽高
  34. )
  35. type (
  36.         mine struct {
  37.                 // 雷区宽高
  38.                 h, w int
  39.                 // 0: 正常,1: 赢,2: 输
  40.                 playing int
  41.                 // 雷区格子数据
  42.                 data [][]*grid
  43.                 // 总雷数
  44.                 mineCnt int
  45.                 // 开始时间
  46.                 timeStart time.Time
  47.                 // 计时器
  48.                 timeCnt int
  49.                 // 计时器最右侧数字坐标
  50.                 timeX float64
  51.                 // 界面宽高
  52.                 gridW, gridH int
  53.                 // 显示哪个笑脸
  54.                 faceNum int
  55.                 // 笑脸坐标
  56.                 faceX float64
  57.                 // 判断在笑脸位置
  58.                 isFace func(h, w int) bool
  59.                 // 界面图片,数字图片,笑脸图片
  60.                 img, num, face []*ebiten.Image
  61.                 // 背景图片
  62.                 background *ebiten.Image
  63.                 // 显示输入数据
  64.                 text string
  65.         }
  66.         grid struct {
  67.                 data  int // 格子数据
  68.                 state int // 状态
  69.         }
  70. )
  71. var aroundPos = [][]int{
  72.         {-1, 1, 0, 0, -1, -1, 1, 1},
  73.         {0, 0, -1, 1, -1, 1, -1, 1},
  74. }
  75. func (m *mine) around(h, w int, f func(h, w int)) {
  76.         var i, nh, nw int
  77.         for ; i < 8; i++ {
  78.                 nh, nw = h+aroundPos[0][i], w+aroundPos[1][i]
  79.                 if nh >= 0 && nh < m.h && nw >= 0 && nw < m.w {
  80.                         f(nh, nw) // [h,w]周围合法8个位置
  81.                 }
  82.         }
  83. }
  84. func (m *mine) initData() {
  85.         var i, j int
  86.         if len(m.data) < m.h {
  87.                 m.data = make([][]*grid, m.h)
  88.         }
  89.         for i = 0; i < m.h; i++ {
  90.                 if len(m.data[i]) < m.w {
  91.                         m.data[i] = make([]*grid, m.w)
  92.                 }
  93.         }
  94.         for i = 0; i < m.h; i++ {
  95.                 for j = 0; j < m.w; j++ {
  96.                         if d := m.data[i][j]; d == nil {
  97.                                 m.data[i][j] = new(grid)
  98.                         } else {
  99.                                 d.data, d.state = 0, 0
  100.                         }
  101.                 }
  102.         }
  103.         cnt := 0
  104.         for cnt < m.mineCnt {
  105.                 i, j = rand.Intn(m.h), rand.Intn(m.w)
  106.                 if d := m.data[i][j]; d.data != 10 {
  107.                         cnt++
  108.                         d.data = 10
  109.                 }
  110.         }
  111.         for i = 0; i < m.h; i++ {
  112.                 for j = 0; j < m.w; j++ {
  113.                         if d := m.data[i][j]; d.data != 10 {
  114.                                 m.around(i, j, func(h, w int) {
  115.                                         if m.data[h][w].data == 10 {
  116.                                                 d.data++
  117.                                         }
  118.                                 })
  119.                         }
  120.                 }
  121.         }
  122.         m.playing = 0
  123.         m.timeStart = time.Time{}
  124.         m.timeCnt = 0
  125.         m.gridW, m.gridH = m.w*gridHW+6, (m.h+3)*gridHW+6
  126.         faceX := m.gridW/2 - 18
  127.         m.faceX = float64(faceX)
  128.         m.isFace = func(h, w int) bool {
  129.                 return h >= 4 && h <= 28 && w >= faceX && w < faceX+24
  130.         }
  131.         m.faceNum = 0
  132.         m.timeX = float64(m.gridW - 18)
  133.         ebiten.SetWindowSize(m.gridW, m.gridH)
  134.         m.background = ebiten.NewImage(m.gridW, m.gridH-gridHW)
  135.         m.background.Fill(backgroundColor) // 创建背景图片
  136.         m.text = fmt.Sprintf("H:%d,W:%d,M:%d >", m.h, m.w, m.mineCnt)
  137. }
  138. func (m *mine) cursorPos() (h, w, state int) {
  139.         w, h = ebiten.CursorPosition()
  140.         if m.isFace(h, w) {
  141.                 state = 1
  142.         } else {
  143.                 w, h = (w-3)/gridHW, h/gridHW-2
  144.                 if w >= 0 && w < m.w && h >= 0 && h < m.h {
  145.                         state = 2
  146.                 }
  147.         }
  148.         return
  149. }
  150. func (m *mine) reactionChain(h, w int) {
  151.         d := m.data[h][w]
  152.         if d.state != 0 {
  153.                 return // 已打开或插旗 或 游戏完成
  154.         }
  155.         d.state = -1
  156.         switch d.data {
  157.         case 10:
  158.                 if m.playing == 0 {
  159.                         m.playing = 2
  160.                         d.data = 12 // 游戏结束,标记第1个踩到的雷
  161.                 }
  162.         case 0: // 递归点开所有空白区域
  163.                 m.around(h, w, func(h, w int) { m.reactionChain(h, w) })
  164.         }
  165. }
  166. func (m *mine) Update() error {
  167.         var state int
  168.         if m.playing != 0 {
  169.                 if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
  170.                         _, _, state = m.cursorPos()
  171.                         if state == 1 {
  172.                                 m.faceNum = 4
  173.                         } else {
  174.                                 switch m.playing {
  175.                                 case 1:
  176.                                         m.faceNum = 3
  177.                                 case 2:
  178.                                         m.faceNum = 2
  179.                                 }
  180.                         }
  181.                 } else if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) {
  182.                         _, _, state = m.cursorPos()
  183.                         if state == 1 {
  184.                                 m.initData() // 左键小脸松开重新开始游戏
  185.                         }
  186.                 }
  187.                 return nil
  188.         }
  189.         if m.timeCnt < 999 && !m.timeStart.IsZero() {
  190.                 m.timeCnt = int(time.Since(m.timeStart) / time.Second)
  191.         }
  192.         var d *grid
  193.         var i, j int
  194.         if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
  195.                 for i = 0; i < m.h; i++ {
  196.                         for j = 0; j < m.w; j++ {
  197.                                 if d = m.data[i][j]; d.state == 1 {
  198.                                         d.state = 0
  199.                                 }
  200.                         }
  201.                 }
  202.                 i, j, state = m.cursorPos()
  203.                 switch state {
  204.                 case 1:
  205.                         m.faceNum = 4
  206.                 case 2:
  207.                         switch d = m.data[i][j]; d.state {
  208.                         case 0:
  209.                                 d.state = 1
  210.                         case -1:
  211.                                 m.around(i, j, func(ah, aw int) {
  212.                                         if ad := m.data[ah][aw]; ad.state == 0 {
  213.                                                 ad.state = 1
  214.                                         }
  215.                                 })
  216.                         }
  217.                         m.faceNum = 1
  218.                 default:
  219.                         m.faceNum = 1
  220.                 }
  221.         } else if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) {
  222.                 for i = 0; i < m.h; i++ {
  223.                         for j = 0; j < m.w; j++ {
  224.                                 if d = m.data[i][j]; d.state == 1 {
  225.                                         d.state = 0
  226.                                 }
  227.                         }
  228.                 }
  229.                 m.faceNum = 0
  230.                 i, j, state = m.cursorPos()
  231.                 switch state {
  232.                 case 1:
  233.                         m.initData() // 笑脸位置松开左键,重新开局
  234.                         return nil
  235.                 case 2:
  236.                         if m.timeStart.IsZero() {
  237.                                 m.timeStart = time.Now()
  238.                         }
  239.                         switch d = m.data[i][j]; d.state {
  240.                         case 0: // 判断单击
  241.                                 m.reactionChain(i, j)
  242.                         case -1: // 判断双击
  243.                                 if d.data >= 1 && d.data <= 8 {
  244.                                         state = 0
  245.                                         m.around(i, j, func(ah, aw int) {
  246.                                                 if ad := m.data[ah][aw]; ad.state == 2 {
  247.                                                         state++
  248.                                                 }
  249.                                         })
  250.                                         if d.data == state {
  251.                                                 m.around(i, j, func(ah, aw int) {
  252.                                                         m.reactionChain(ah, aw)
  253.                                                 })
  254.                                         }
  255.                                 }
  256.                         }
  257.                         if m.playing == 2 {
  258.                                 m.faceNum = 2 // 游戏结束,输了
  259.                                 for i = 0; i < m.h; i++ {
  260.                                         for j = 0; j < m.w; j++ {
  261.                                                 switch d = m.data[i][j]; d.state {
  262.                                                 case 0: // 将所有雷打开
  263.                                                         if d.data == 10 {
  264.                                                                 d.state = -1
  265.                                                         }
  266.                                                 case 2: // 插旗位置不是雷,设置标雷错误
  267.                                                         if d.data != 10 {
  268.                                                                 d.state = -1
  269.                                                                 d.data = 11
  270.                                                         }
  271.                                                 }
  272.                                         }
  273.                                 }
  274.                                 return nil
  275.                         }
  276.                         state = 0
  277.                         for i = 0; i < m.h; i++ {
  278.                                 for j = 0; j < m.w; j++ {
  279.                                         if d = m.data[i][j]; d.state == -1 {
  280.                                                 state++
  281.                                         }
  282.                                 }
  283.                         }
  284.                         // 点开位置 + 总雷数 = 全部格子数, 此时赢
  285.                         if state+m.mineCnt == m.h*m.w {
  286.                                 m.faceNum = 3 // 游戏结束,赢了
  287.                                 m.playing = 1
  288.                                 for i = 0; i < m.h; i++ {
  289.                                         for j = 0; j < m.w; j++ {
  290.                                                 if d = m.data[i][j]; d.state == 0 {
  291.                                                         d.state = 2 // 剩余全插旗
  292.                                                 }
  293.                                         }
  294.                                 }
  295.                                 return nil
  296.                         }
  297.                 }
  298.         } else if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonRight) {
  299.                 i, j, state = m.cursorPos()
  300.                 if state == 2 {
  301.                         switch d = m.data[i][j]; d.state {
  302.                         case 0:
  303.                                 d.state = 2 // 插旗
  304.                         case 2:
  305.                                 d.state = 0 // 取消
  306.                         }
  307.                 }
  308.         }
  309.         for k, v := range eKey {
  310.                 if inpututil.IsKeyJustReleased(k) {
  311.                         switch v {
  312.                         case "d":
  313.                                 if i = len(m.text) - 1; m.text[i] != '>' {
  314.                                         m.text = m.text[:i]
  315.                                 }
  316.                         case "e":
  317.                                 i = strings.IndexByte(m.text, '>') + 1
  318.                                 var ok bool
  319.                                 n, _ := fmt.Sscanf(m.text[i:], "%d %d %d", &i, &j, &state)
  320.                                 switch n {
  321.                                 case 3: // 读取 h/w/mine 这3个数据
  322.                                         if i >= 9 && i <= 45 && j >= 9 && j <= 45 &&
  323.                                                 state >= 10 && state <= (i-1)*(j-1) {
  324.                                                 m.h, m.w, m.mineCnt = i, j, state
  325.                                                 ok = true
  326.                                         }
  327.                                 case 1: // 输入单个数字切换难度模式
  328.                                         switch i {
  329.                                         case 1:
  330.                                                 m.h, m.w, m.mineCnt = 9, 9, 10 // 初级
  331.                                                 ok = true
  332.                                         case 2:
  333.                                                 m.h, m.w, m.mineCnt = 16, 16, 40 // 中级
  334.                                                 ok = true
  335.                                         case 3:
  336.                                                 m.h, m.w, m.mineCnt = 16, 30, 99 // 高级
  337.                                                 ok = true
  338.                                         case 4:
  339.                                                 m.h, m.w, m.mineCnt = 24, 30, 99 // 最大
  340.                                                 ok = true
  341.                                         }
  342.                                 }
  343.                                 if ok {
  344.                                         m.initData()
  345.                                         return nil
  346.                                 }
  347.                         default:
  348.                                 m.text += v
  349.                         }
  350.                 }
  351.         }
  352.         return nil
  353. }
  354. var (
  355.         eKey = map[ebiten.Key]string{
  356.                 ebiten.KeyDigit0: "0",
  357.                 ebiten.KeyDigit1: "1",
  358.                 ebiten.KeyDigit2: "2",
  359.                 ebiten.KeyDigit3: "3",
  360.                 ebiten.KeyDigit4: "4",
  361.                 ebiten.KeyDigit5: "5",
  362.                 ebiten.KeyDigit6: "6",
  363.                 ebiten.KeyDigit7: "7",
  364.                 ebiten.KeyDigit8: "8",
  365.                 ebiten.KeyDigit9: "9",
  366.                 ebiten.KeySpace:  " ",
  367.                 ebiten.KeyBackspace:   "d", // 删除
  368.                 ebiten.KeyEnter:       "e", // 回车
  369.                 ebiten.KeyNumpadEnter: "e", // 回车
  370.         }
  371.         backgroundColor = color.RGBA{R: 0xc0, G: 0xc0, B: 0xc0, A: 0xff}
  372. )
  373. func (m *mine) Draw(screen *ebiten.Image) {
  374.         screen.DrawImage(m.background, nil)
  375.         ct := m.mineCnt
  376.         op := &ebiten.DrawImageOptions{}
  377.         op.GeoM.Translate(3, 2*gridHW)
  378.         for i := 0; i < m.h; i++ {
  379.                 for j := 0; j < m.w; j++ {
  380.                         switch d := m.data[i][j]; d.state {
  381.                         case 0: // 默认状态
  382.                                 screen.DrawImage(m.img[15], op)
  383.                         case 1: // 按住左键不松开
  384.                                 screen.DrawImage(m.img[0], op)
  385.                         case 2: // 标记旗子
  386.                                 screen.DrawImage(m.img[14], op)
  387.                                 ct--
  388.                         default: // 按照数据显示
  389.                                 if d.data == 11 {
  390.                                         ct-- // 错误插旗也算标雷
  391.                                 }
  392.                                 screen.DrawImage(m.img[d.data], op)
  393.                         }
  394.                         op.GeoM.Translate(gridHW, 0)
  395.                 }
  396.                 op.GeoM.Translate(0, gridHW)
  397.                 op.GeoM.SetElement(0, 2, 3)
  398.         }
  399.         op.GeoM.Reset() // 显示雷数
  400.         op.GeoM.Translate(5, 5)
  401.         var num []int
  402.         if ct >= 0 {
  403.                 num = []int{(ct / 100) % 10, (ct / 10) % 10, ct % 10}
  404.         } else {
  405.                 ct = -ct // 负数只显示2位
  406.                 num = []int{11, (ct / 10) % 10, ct % 10}
  407.         }
  408.         for _, v := range num {
  409.                 screen.DrawImage(m.num[v], op)
  410.                 op.GeoM.Translate(13, 0)
  411.         }
  412.         op.GeoM.Reset() // 显示时间
  413.         op.GeoM.Translate(m.timeX, 5)
  414.         for _, v := range []int{m.timeCnt % 10, (m.timeCnt / 10) % 10, (m.timeCnt / 100) % 10} {
  415.                 screen.DrawImage(m.num[v], op)
  416.                 op.GeoM.Translate(-13, 0)
  417.         }
  418.         op.GeoM.Reset() // 显示笑脸
  419.         op.GeoM.Translate(m.faceX, 4)
  420.         screen.DrawImage(m.face[m.faceNum], op)
  421.         // 打印输入的[高 宽 雷]数据,以及输入数据显示
  422.         ebitenutil.DebugPrintAt(screen, m.text, 10, m.gridH-gridHW)
  423. }
  424. func (m *mine) Layout(_, _ int) (int, int) {
  425.         return m.gridW, m.gridH
  426. }
  427. func (m *mine) loadResources() error {
  428.         //goland:noinspection SpellCheckingInspection
  429.         const sd = "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"
  430.         bd, err := base64.StdEncoding.DecodeString(sd)
  431.         if err != nil {
  432.                 return err
  433.         }
  434.         data := bytes.NewReader(bd)
  435.         zr, err := zip.NewReader(data, data.Size())
  436.         if err != nil {
  437.                 return err
  438.         }
  439.         subImg := func(img image.Image, x, y, num int) []*ebiten.Image {
  440.                 var (
  441.                         ei = ebiten.NewImageFromImage(img)
  442.                         ri = make([]*ebiten.Image, num)
  443.                 )
  444.                 for i := 0; i < num; i++ {
  445.                         var rc image.Rectangle
  446.                         rc.Min.Y, rc.Max.X = i*y, x
  447.                         rc.Max.Y = rc.Min.Y + y
  448.                         ri[num-i-1] = ei.SubImage(rc).(*ebiten.Image)
  449.                 }
  450.                 return ri
  451.         }
  452.         for _, fv := range zr.File {
  453.                 fr, err := fv.Open()
  454.                 if err != nil {
  455.                         return err
  456.                 }
  457.                 img, err := png.Decode(fr)
  458.                 _ = fr.Close()
  459.                 if err != nil {
  460.                         return err
  461.                 }
  462.                 switch fv.Name {
  463.                 case "ico.png":
  464.                         ebiten.SetWindowIcon([]image.Image{img})
  465.                 case "mine.png":
  466.                         m.img = subImg(img, 16, 16, 16)
  467.                 case "num.png":
  468.                         m.num = subImg(img, 13, 23, 12)
  469.                 case "face.png":
  470.                         m.face = subImg(img, 24, 24, 5)
  471.                 }
  472.         }
  473.         return nil
  474. }
复制代码
如下显示结果

长按鼠标左键划过格子会有提示,与windows扫雷结果划一。
左键既是单击,点数字时也是双击,右键标雷。
在界面输入,1 + 回车 = 初级,2 + 回车 = 中级,3 + 回车 = 高级
在界面输入, 11 22 33 + 回车 = 高度11,宽度22,总雷数33 。可以自界说数据
如果想在浏览器中运行,可到项目 LittleGame
执行
  1. # 编译项目
  2. .\build.bat minesweeper
  3. # 运行http服务器
  4. .\httpServer
复制代码
然后浏览器访问:  http://127.0.0.1:8080  ,结果显示如下

出处:https://www.cnblogs.com/janbar本文版权归作者和博客园所有,欢迎转载,转载请标明出处。喜好我的文章请[关注我]吧。如果您觉得本篇博文对您有所劳绩,可点击[推荐][收藏]
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立聪堂德州十三局店

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表