From ba8138f69bea44638ce07564c5a8a5dfcc98e4d8 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 30 Jul 2016 17:23:39 +0900 Subject: [PATCH] examples/2048: Refactoring --- examples/2048/2048/board.go | 112 ++---------------- examples/2048/2048/game.go | 4 +- examples/2048/2048/tile.go | 105 ++++++++++++++++ .../2048/2048/{board_test.go => tile_test.go} | 0 4 files changed, 115 insertions(+), 106 deletions(-) rename examples/2048/2048/{board_test.go => tile_test.go} (100%) diff --git a/examples/2048/2048/board.go b/examples/2048/2048/board.go index fe0032656..2cc6a5b3a 100644 --- a/examples/2048/2048/board.go +++ b/examples/2048/2048/board.go @@ -16,8 +16,6 @@ package twenty48 import ( "image/color" - "math/rand" - "sort" "strconv" "github.com/hajimehoshi/ebiten" @@ -35,121 +33,25 @@ func NewBoard(size int) *Board { tiles: map[*Tile]struct{}{}, } for i := 0; i < 2; i++ { - b.addRandomTile() + addRandomTile(b.tiles, b.size) } return b } -func (b *Board) addRandomTile() bool { - cells := make([]bool, b.size*b.size) - for t := range b.tiles { - i := t.x + t.y*b.size - cells[i] = true - } - availableCells := []int{} - for i, b := range cells { - if b { - continue - } - availableCells = append(availableCells, i) - } - if len(availableCells) == 0 { - return false - } - c := availableCells[rand.Intn(len(availableCells))] - v := 2 - if rand.Intn(10) == 0 { - v = 4 - } - x := c % b.size - y := c / b.size - t := NewTile(v, x, y) - b.tiles[t] = struct{}{} - return true -} - -func tileAt(tiles map[*Tile]struct{}, x, y int) *Tile { - for t := range tiles { - if t.x == x && t.y == y { - return t - } - } - return nil -} - func (b *Board) tileAt(x, y int) *Tile { return tileAt(b.tiles, x, y) } -func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) (map[*Tile]struct{}, bool) { - vx, vy := dir.Vector() - tx := []int{} - ty := []int{} - for i := 0; i < size; i++ { - tx = append(tx, i) - ty = append(ty, i) - } - if vx > 0 { - sort.Sort(sort.Reverse(sort.IntSlice(tx))) - } - if vy > 0 { - sort.Sort(sort.Reverse(sort.IntSlice(ty))) - } - - nextTiles := map[*Tile]struct{}{} - merged := map[*Tile]bool{} - moved := false - for _, j := range ty { - for _, i := range tx { - t := tileAt(tiles, i, j) - if t == nil { - continue - } - ii := i - jj := j - for { - ni := ii + vx - nj := jj + vy - if ni < 0 || ni >= size || nj < 0 || nj >= size { - break - } - tt := tileAt(nextTiles, ni, nj) - if tt == nil { - ii = ni - jj = nj - moved = true - continue - } - if t.value != tt.value { - break - } - if !merged[tt] { - ii = ni - jj = nj - moved = true - } - break - } - if tt := tileAt(tiles, ii, jj); tt != t && tt != nil { - t.value += tt.value - merged[t] = true - delete(nextTiles, tt) - } - t.x = ii - t.y = jj - nextTiles[t] = struct{}{} - } - } - return nextTiles, moved -} - -func (b *Board) Move(dir Dir) { +func (b *Board) Move(dir Dir) error { moved := false b.tiles, moved = MoveTiles(b.tiles, b.size, dir) if !moved { - return + return nil } - b.addRandomTile() + if err := addRandomTile(b.tiles, b.size); err != nil { + return err + } + return nil } const ( diff --git a/examples/2048/2048/game.go b/examples/2048/2048/game.go index 073595b7d..355f22d7f 100644 --- a/examples/2048/2048/game.go +++ b/examples/2048/2048/game.go @@ -49,7 +49,9 @@ func (g *Game) Update() error { return err } if dir, ok := g.input.Dir(); ok { - g.board.Move(dir) + if err := g.board.Move(dir); err != nil { + return err + } } return nil } diff --git a/examples/2048/2048/tile.go b/examples/2048/2048/tile.go index 835fd6bc6..0f9d04ca9 100644 --- a/examples/2048/2048/tile.go +++ b/examples/2048/2048/tile.go @@ -14,6 +14,12 @@ package twenty48 +import ( + "errors" + "math/rand" + "sort" +) + type Tile struct { value int x int @@ -35,3 +41,102 @@ func (t *Tile) Value() int { func (t *Tile) Pos() (int, int) { return t.x, t.y } + +func tileAt(tiles map[*Tile]struct{}, x, y int) *Tile { + for t := range tiles { + if t.x == x && t.y == y { + return t + } + } + return nil +} + +func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) (map[*Tile]struct{}, bool) { + vx, vy := dir.Vector() + tx := []int{} + ty := []int{} + for i := 0; i < size; i++ { + tx = append(tx, i) + ty = append(ty, i) + } + if vx > 0 { + sort.Sort(sort.Reverse(sort.IntSlice(tx))) + } + if vy > 0 { + sort.Sort(sort.Reverse(sort.IntSlice(ty))) + } + + nextTiles := map[*Tile]struct{}{} + merged := map[*Tile]bool{} + moved := false + for _, j := range ty { + for _, i := range tx { + t := tileAt(tiles, i, j) + if t == nil { + continue + } + ii := i + jj := j + for { + ni := ii + vx + nj := jj + vy + if ni < 0 || ni >= size || nj < 0 || nj >= size { + break + } + tt := tileAt(nextTiles, ni, nj) + if tt == nil { + ii = ni + jj = nj + moved = true + continue + } + if t.value != tt.value { + break + } + if !merged[tt] { + ii = ni + jj = nj + moved = true + } + break + } + if tt := tileAt(tiles, ii, jj); tt != t && tt != nil { + t.value += tt.value + merged[t] = true + delete(nextTiles, tt) + } + t.x = ii + t.y = jj + nextTiles[t] = struct{}{} + } + } + return nextTiles, moved +} + +func addRandomTile(tiles map[*Tile]struct{}, size int) error { + cells := make([]bool, size*size) + for t := range tiles { + i := t.x + t.y*size + cells[i] = true + } + availableCells := []int{} + for i, b := range cells { + if b { + continue + } + availableCells = append(availableCells, i) + } + if len(availableCells) == 0 { + return errors.New("twenty48: there is no space to add a new tile") + } + c := availableCells[rand.Intn(len(availableCells))] + v := 2 + if rand.Intn(10) == 0 { + v = 4 + } + x := c % size + y := c / size + t := NewTile(v, x, y) + tiles[t] = struct{}{} + return nil +} diff --git a/examples/2048/2048/board_test.go b/examples/2048/2048/tile_test.go similarity index 100% rename from examples/2048/2048/board_test.go rename to examples/2048/2048/tile_test.go