examples/2048: Refactoring

This commit is contained in:
Hajime Hoshi 2016-07-30 17:23:39 +09:00
parent ef61e7a568
commit ba8138f69b
4 changed files with 115 additions and 106 deletions

View File

@ -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 (

View File

@ -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
}

View File

@ -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
}