package views import ( "bytes" "context" "errors" "fmt" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "image" "image/color" "image/draw" "image/png" "slices" "sync" ) func TenChinaGameView() { game := NewTenGame(nil) //go func() { // for { // select { // case <-game.Ctx.Done(): // return // case msg := <-global.Send.Game1Chan: // game.play() // } // } //}() game.StartShow() } type TenGame struct { lock sync.Mutex // 玩家操作锁 playerMax int // 玩家总人数 playerID2Image map[int]fyne.Resource // 各个玩家对应的图标 defaultImage fyne.Resource // 默认图标 currentRoundPlayer int // 当前行动的玩家 players [][]int // 各个玩家已完成下棋数据 allMaps []int // 所有下棋数据 winCallback func(int) // 胜利返回 Items []*canvas.Image // 各个板块对象 w fyne.Window itemSize fyne.Size //单个格子大小 itemX float32 // 格子总数x itemY float32 // 格子总数y winSum int // 胜利连线数 Ctx context.Context Cancel func() } func NewTenGame(winCallback func(int)) *TenGame { playerImageMap := map[int]fyne.Resource{ 0: theme.RadioButtonIcon(), 1: theme.CancelIcon(), //2: theme.DownloadIcon(), } ctx, cancel := context.WithCancel(context.Background()) game := &TenGame{ playerID2Image: playerImageMap, defaultImage: nil, //theme.ViewFullScreenIcon(), currentRoundPlayer: 0, players: make([][]int, len(playerImageMap)), winCallback: winCallback, itemSize: fyne.NewSize(50, 50), itemX: 10, itemY: 10, winSum: 5, Ctx: ctx, Cancel: cancel, } return game } func (t *TenGame) StartShow() { myApp := fyne.CurrentApp() myWindow := myApp.NewWindow(fmt.Sprintf("Game %0.f*%0.f win:%d", t.itemX, t.itemY, t.winSum)) t.w = myWindow wSize := fyne.NewSize(t.itemX*(t.itemSize.Width), t.itemY*(t.itemSize.Height)) myWindow.Resize(wSize) myWindow.SetContent(container.New(layout.NewMaxLayout(), canvas.NewImageFromResource(drawABackgroundImage(wSize, int(t.itemX), int(t.itemY))), t.CanvasObject())) myWindow.CenterOnScreen() myWindow.Show() } func (t *TenGame) CanvasObject() fyne.CanvasObject { var items []fyne.CanvasObject for i := 0; i < int(t.itemX*t.itemY); i++ { var itemIndex = i image := canvas.NewImageFromResource(t.defaultImage) image.FillMode = canvas.ImageFillOriginal image.Resize(t.itemSize) //fy t.Items = append(t.Items, image) toggle := widget.NewButton("", func() { _ = t.Play(0, itemIndex) }) toggle.Resize(t.itemSize) iViews := container.NewBorder(nil, nil, nil, nil, container.NewWithoutLayout(image, toggle)) iViews.Resize(t.itemSize) //gridWrap.Add() items = append(items, iViews) } gridWrap := container.NewGridWithRows(int(t.itemX), items...) return container.NewScroll(gridWrap) } func (t *TenGame) Play(userIndex int, pos int) error { t.lock.Lock() defer t.lock.Unlock() //if t.currentRoundPlayer != userIndex { // return errors.New("你急个der") //} if slices.Contains(t.allMaps, pos) { return errors.New("已经下过了") } // 下棋 t.allMaps = append(t.allMaps, pos) t.play(pos) // 推进 t.currentRoundPlayer++ if t.currentRoundPlayer+1 > len(t.playerID2Image) { t.currentRoundPlayer = 0 } return nil } /* 1, 2, 3 4, 5, 6 7, 8, 9 */ func (t *TenGame) play(pos int) { // 更新玩家数据 playerIntList := t.players[t.currentRoundPlayer] playerIntList = append(playerIntList, pos) t.players[t.currentRoundPlayer] = playerIntList // 刷新展示 t.Items[pos].Resource = t.playerID2Image[t.currentRoundPlayer] t.Items[pos].Refresh() // check 胜利 判断 if t.winCheck(playerIntList, pos) { endView := widget.NewButton("关闭", func() { 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() if t.winCallback != nil { 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, pos int) bool { //slices.Sort(playerIntList) return IsArithmeticSequence2(playerIntList, pos, t.winSum, int(t.itemX), int(t.itemY)) } /* 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 false } func lineSum(pos pos, mapX, mapY int, numbers []int, direction pos) (sum int) { for { 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)) { return } sum++ } } // 画背景图 func drawABackgroundImage(size fyne.Size, itemX, itemY int) fyne.Resource { img := image.NewRGBA(image.Rect(0, 0, int(size.Width), int(size.Height))) draw.Draw(img, img.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src) //itemX = itemX * 2 //itemY = itemY * 2 // 画横线 for ix := 1; ix < itemX; ix++ { i1 := int(size.Height * (float32(ix) / float32(itemX))) for x := 1; x < int(size.Width); x++ { img.Set(x, i1, color.Black) } //ix++ } // Draw vertical line for ix := 1; ix < itemY; ix++ { i2 := int(size.Width * (float32(ix) / float32(itemY))) for y := 0; y < int(size.Height); y++ { img.Set(i2, y, color.Black) } //ix++ } buffer := new(bytes.Buffer) err := png.Encode(buffer, img) if err != nil { return nil } return &fyne.StaticResource{ StaticName: "", StaticContent: buffer.Bytes(), } }