mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
examples/2048: Refactoring
This commit is contained in:
parent
ef61e7a568
commit
ba8138f69b
@ -16,8 +16,6 @@ package twenty48
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"math/rand"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
@ -35,121 +33,25 @@ func NewBoard(size int) *Board {
|
|||||||
tiles: map[*Tile]struct{}{},
|
tiles: map[*Tile]struct{}{},
|
||||||
}
|
}
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
b.addRandomTile()
|
addRandomTile(b.tiles, b.size)
|
||||||
}
|
}
|
||||||
return b
|
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 {
|
func (b *Board) tileAt(x, y int) *Tile {
|
||||||
return tileAt(b.tiles, x, y)
|
return tileAt(b.tiles, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) (map[*Tile]struct{}, bool) {
|
func (b *Board) Move(dir Dir) error {
|
||||||
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) {
|
|
||||||
moved := false
|
moved := false
|
||||||
b.tiles, moved = MoveTiles(b.tiles, b.size, dir)
|
b.tiles, moved = MoveTiles(b.tiles, b.size, dir)
|
||||||
if !moved {
|
if !moved {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
b.addRandomTile()
|
if err := addRandomTile(b.tiles, b.size); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -49,7 +49,9 @@ func (g *Game) Update() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if dir, ok := g.input.Dir(); ok {
|
if dir, ok := g.input.Dir(); ok {
|
||||||
g.board.Move(dir)
|
if err := g.board.Move(dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,12 @@
|
|||||||
|
|
||||||
package twenty48
|
package twenty48
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/rand"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
type Tile struct {
|
type Tile struct {
|
||||||
value int
|
value int
|
||||||
x int
|
x int
|
||||||
@ -35,3 +41,102 @@ func (t *Tile) Value() int {
|
|||||||
func (t *Tile) Pos() (int, int) {
|
func (t *Tile) Pos() (int, int) {
|
||||||
return t.x, t.y
|
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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user