完善十子棋功能

This commit is contained in:
2024-10-16 19:30:07 +08:00
parent 7986bb1c9b
commit 411876b377
5 changed files with 184 additions and 49 deletions
+12
View File
@@ -0,0 +1,12 @@
package main
import (
"fmt"
"testing"
"work_cation/views"
)
func TestP1(t *testing.T) {
r := views.IsArithmeticSequence2([]int{0, 4, 8}, 8, 3, 3, 3)
fmt.Println(r)
}
+5 -1
View File
@@ -4,6 +4,10 @@ import "work_cation/models"
type SendGlobal struct { type SendGlobal struct {
SendChan chan *models.Message SendChan chan *models.Message
Game1Chan chan *models.GameMessage
} }
var Send = &SendGlobal{SendChan: make(chan *models.Message, 1000)} var Send = &SendGlobal{
SendChan: make(chan *models.Message, 1000),
Game1Chan: make(chan *models.GameMessage, 1000),
}
+6
View File
@@ -0,0 +1,6 @@
package models
type GameMessage struct {
UserID string `json:"user_id"`
Pos int `json:"pos"`
}
+22
View File
@@ -105,6 +105,28 @@ func (s *serverService) StartListenServer() error {
c.JSON(200, gin.H{"message": "ok"}) c.JSON(200, gin.H{"message": "ok"})
}) })
// 游戏接口
router.POST("/game", func(c *gin.Context) {
uuid := c.GetHeader("User-UserID")
user := repo.UserFollow.GetUser(global.DB, uuid)
if user.Ip != c.ClientIP() {
c.JSON(200, gin.H{"message": "对方未关注你"})
return
}
var msg = make(map[string]interface{})
if err := c.ShouldBind(&msg); err != nil {
c.JSON(200, gin.H{"message": "输入异常"})
return
}
message := &models.GameMessage{
UserID: user.ID,
Pos: msg["text"].(int),
}
global.Send.Game1Chan <- message
c.JSON(200, gin.H{"message": "ok"})
})
srv := &http.Server{ srv := &http.Server{
Addr: cfg.T.ServerAddr, Addr: cfg.T.ServerAddr,
Handler: router, Handler: router,
+134 -43
View File
@@ -1,6 +1,9 @@
package views package views
import ( import (
"context"
"errors"
"fmt"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
@@ -13,18 +16,29 @@ import (
func TenChinaGameView() { func TenChinaGameView() {
game := NewTenGame(nil) game := NewTenGame(nil)
//go func() {
// for {
// select {
// case <-game.Ctx.Done():
// return
// case msg := <-global.Send.Game1Chan:
// game.play()
// }
// }
//}()
game.StartShow() game.StartShow()
} }
type TenGame struct { type TenGame struct {
lock sync.Mutex lock sync.Mutex // 玩家操作锁
playerMax int // 玩家总人数 playerMax int // 玩家总人数
playerID2Image map[int]fyne.Resource // 各个玩家对应的图标 playerID2Image map[int]fyne.Resource // 各个玩家对应的图标
defaultImage fyne.Resource defaultImage fyne.Resource // 默认图标
CurrentRoundPlayer int // 当前行动的玩家 currentRoundPlayer int // 当前行动的玩家
players [][]int // 各个玩家已完成下棋数据 players [][]int // 各个玩家已完成下棋数据
allMaps []int // 所有下棋数据
winCallback func(int) // 胜利返回 winCallback func(int) // 胜利返回
@@ -34,38 +48,52 @@ type TenGame struct {
itemSize fyne.Size //单个格子大小 itemSize fyne.Size //单个格子大小
itemX float32 // 格子总数x itemX float32 // 格子总数x
itemY float32 // 格子总数y itemY float32 // 格子总数y
winSum int // 胜利连线数
Ctx context.Context
Cancel func()
} }
func NewTenGame(winCallback func(int)) *TenGame { func NewTenGame(winCallback func(int)) *TenGame {
game := &TenGame{ playerImageMap := map[int]fyne.Resource{
playerID2Image: map[int]fyne.Resource{
0: theme.RadioButtonIcon(), 0: theme.RadioButtonIcon(),
1: theme.CancelIcon(), 1: theme.CancelIcon(),
}, //2: theme.DownloadIcon(),
}
ctx, cancel := context.WithCancel(context.Background())
game := &TenGame{
playerID2Image: playerImageMap,
defaultImage: theme.CheckButtonIcon(), defaultImage: theme.CheckButtonIcon(),
CurrentRoundPlayer: 0, currentRoundPlayer: 0,
players: make([][]int, 2), players: make([][]int, len(playerImageMap)),
winCallback: winCallback, winCallback: winCallback,
itemSize: fyne.NewSize(100, 100), itemSize: fyne.NewSize(25, 25),
itemX: 3, itemX: 3,
itemY: 3, itemY: 3,
winSum: 3,
Ctx: ctx,
Cancel: cancel,
} }
return game return game
} }
func (t *TenGame) StartShow() { func (t *TenGame) StartShow() {
myApp := fyne.CurrentApp() myApp := fyne.CurrentApp()
myWindow := myApp.NewWindow("Game") myWindow := myApp.NewWindow(fmt.Sprintf("Game %0.f*%0.f win:%d", t.itemX, t.itemY, t.winSum))
t.w = myWindow t.w = myWindow
myWindow.SetContent(t.CanvasObject()) myWindow.SetContent(t.CanvasObject())
myWindow.Resize(fyne.NewSize(t.itemX*t.itemSize.Width+20, t.itemY*t.itemSize.Height+20)) myWindow.Resize(fyne.NewSize(t.itemX*(t.itemSize.Width+8), t.itemY*(t.itemSize.Height+8)))
myWindow.CenterOnScreen() myWindow.CenterOnScreen()
t.w.SetOnClosed(func() { t.Cancel() })
myWindow.Show() myWindow.Show()
} }
func (t *TenGame) CanvasObject() fyne.CanvasObject { func (t *TenGame) CanvasObject() fyne.CanvasObject {
gridWrap := container.NewGridWrap(t.itemSize) var items []fyne.CanvasObject
for i := 0; i < int(t.itemX*t.itemY); i++ { for i := 0; i < int(t.itemX*t.itemY); i++ {
var itemIndex = i var itemIndex = i
@@ -75,28 +103,34 @@ func (t *TenGame) CanvasObject() fyne.CanvasObject {
t.Items = append(t.Items, image) t.Items = append(t.Items, image)
toggle := widget.NewButton("", func() { toggle := widget.NewButton("", func() {
t.Play(0, itemIndex) _ = t.Play(0, itemIndex)
}) })
toggle.Resize(t.itemSize) toggle.Resize(t.itemSize)
//toggle.Alignment = 3
gridWrap.Add(container.NewBorder(nil, nil, nil, nil, container.NewWithoutLayout(image, toggle))) iViews := container.NewBorder(nil, nil, nil, nil, container.NewWithoutLayout(image, toggle))
//gridWrap.Add()
items = append(items, iViews)
} }
gridWrap := container.NewGridWithRows(int(t.itemX), items...)
return container.NewScroll(gridWrap) return container.NewScroll(gridWrap)
} }
func (t *TenGame) Play(userIndex int, pos int) error { func (t *TenGame) Play(userIndex int, pos int) error {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
//if t.CurrentRoundPlayer != userIndex { //if t.currentRoundPlayer != userIndex {
// return errors.New("not your turn") // return errors.New("你急个der")
//} //}
if slices.Contains(t.allMaps, pos) {
return errors.New("已经下过了")
}
// 下棋
t.allMaps = append(t.allMaps, pos)
t.play(pos) t.play(pos)
// 推进 // 推进
t.CurrentRoundPlayer++ t.currentRoundPlayer++
if t.CurrentRoundPlayer+1 > len(t.playerID2Image) { if t.currentRoundPlayer+1 > len(t.playerID2Image) {
t.CurrentRoundPlayer = 0 t.currentRoundPlayer = 0
} }
return nil return nil
} }
@@ -108,53 +142,110 @@ func (t *TenGame) Play(userIndex int, pos int) error {
*/ */
func (t *TenGame) play(pos int) { func (t *TenGame) play(pos int) {
// 更新玩家数据 // 更新玩家数据
playerIntList := t.players[t.CurrentRoundPlayer] playerIntList := t.players[t.currentRoundPlayer]
playerIntList = append(playerIntList, pos) playerIntList = append(playerIntList, pos)
t.players[t.CurrentRoundPlayer] = playerIntList t.players[t.currentRoundPlayer] = playerIntList
// 刷新展示 // 刷新展示
t.Items[pos].Resource = t.playerID2Image[t.CurrentRoundPlayer] t.Items[pos].Resource = t.playerID2Image[t.currentRoundPlayer]
t.Items[pos].Refresh() t.Items[pos].Refresh()
// check 胜利 判断 // check 胜利 判断
if t.winCheck(playerIntList) { if t.winCheck(playerIntList, pos) {
endView := widget.NewButton("关闭", func() { endView := widget.NewButton("关闭", func() {
t.w.Close() t.w.Close()
}) })
img := canvas.NewImageFromResource(t.playerID2Image[t.CurrentRoundPlayer]) img := canvas.NewImageFromResource(t.playerID2Image[t.currentRoundPlayer])
img.FillMode = canvas.ImageFillOriginal img.FillMode = canvas.ImageFillOriginal
v := container.NewBorder(nil, endView, nil, nil, v := container.NewBorder(nil, endView, nil, nil,
container.NewBorder(nil, nil, img, nil, widget.NewLabel("胜利"))) container.NewBorder(nil, nil, img, nil, widget.NewLabel("胜利")))
dialog.NewCustomWithoutButtons("游戏结束", v, t.w).Show() dialog.NewCustomWithoutButtons("游戏结束", v, t.w).Show()
if t.winCallback != nil { if t.winCallback != nil {
t.winCallback(t.CurrentRoundPlayer) t.winCallback(t.currentRoundPlayer)
} }
} else if len(t.allMaps) == int(t.itemX*t.itemY) {
endView := widget.NewButton("关闭", t.w.Close)
img := canvas.NewImageFromResource(t.playerID2Image[t.currentRoundPlayer])
img.FillMode = canvas.ImageFillOriginal
v := container.NewBorder(nil, endView, nil, nil,
container.NewBorder(nil, nil, img, nil, widget.NewLabel("平局")))
dialog.NewCustomWithoutButtons("游戏结束", v, t.w).Show()
} }
} }
func (t *TenGame) winCheck(playerIntList []int) bool { func (t *TenGame) winCheck(playerIntList []int, pos int) bool {
slices.Sort(playerIntList) //slices.Sort(playerIntList)
if isArithmeticSequence(playerIntList, 1) ||
isArithmeticSequence(playerIntList, 2) || return IsArithmeticSequence2(playerIntList, pos, t.winSum, int(t.itemX), int(t.itemY))
isArithmeticSequence(playerIntList, 3) ||
isArithmeticSequence(playerIntList, 4) { }
/*
0, 1, 2
3, 4, 5
6, 7, 8
*/
type pos struct {
x int
y int
}
/*
{0, 0}, {1, 0}, {2, 0}
{0, 1}, {1, 1}, {2, 1}
{0, 2}, {1, 2}, {2, 2}
0 1 2
3 4 5
6 7 8
*/
func int3pos(maxX, i int) pos {
return pos{x: i % maxX, y: i / maxX}
}
func pos2int(maxX int, pos pos) int {
return pos.x + pos.y*maxX
}
var lineDirection = [][]pos{
{{1, 1}, {-1, -1}},
{{1, -1}, {-1, 1}},
{{1, 0}, {-1, 0}},
{{0, 1}, {0, -1}},
}
func IsArithmeticSequence2(numbers []int, in int, diff int, mapX, mapY int) bool {
if len(numbers) <= diff-1 {
return false
}
inPos := int3pos(mapX, in)
for _, direction := range lineDirection {
var sum = 0
for _, idirec := range direction {
sum += lineSum(inPos, mapX, mapY, numbers, idirec)
}
if sum >= diff-1 {
return true return true
} }
}
return false return false
} }
func isArithmeticSequence(numbers []int, diff int) bool { func lineSum(pos pos, mapX, mapY int, numbers []int, direction pos) (sum int) {
if len(numbers) <= 2 { for {
return false pos.x += direction.x
pos.y += direction.y
if pos.x >= mapX || pos.y >= mapY || pos.x < 0 || pos.y < 0 {
return
} }
if !slices.Contains(numbers, pos2int(mapX, pos)) {
for i := 1; i < len(numbers); i++ { return
if numbers[i]-numbers[i-1] != diff { }
return false sum++
} }
} }
return true
}