mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
examples/2048: Introduce TileData
This commit is contained in:
parent
3ce0572a81
commit
0ec07420f4
@ -46,13 +46,24 @@ func (b *Board) Update(input *Input) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for t := range b.tiles {
|
||||||
|
if err := t.Update(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextTiles := map[*Tile]struct{}{}
|
||||||
|
for t := range b.tiles {
|
||||||
|
if t.current.value == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
nextTiles[t] = struct{}{}
|
||||||
|
}
|
||||||
|
b.tiles = nextTiles
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Board) Move(dir Dir) error {
|
func (b *Board) Move(dir Dir) error {
|
||||||
moved := false
|
if moved := MoveTiles(b.tiles, b.size, dir); !moved {
|
||||||
b.tiles, moved = MoveTiles(b.tiles, b.size, dir)
|
|
||||||
if !moved {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := addRandomTile(b.tiles, b.size); err != nil {
|
if err := addRandomTile(b.tiles, b.size); err != nil {
|
||||||
|
@ -34,6 +34,7 @@ type TileData struct {
|
|||||||
type Tile struct {
|
type Tile struct {
|
||||||
current TileData
|
current TileData
|
||||||
next TileData
|
next TileData
|
||||||
|
moving bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTile(value int, x, y int) *Tile {
|
func NewTile(value int, x, y int) *Tile {
|
||||||
@ -54,16 +55,43 @@ func (t *Tile) Pos() (int, int) {
|
|||||||
return t.current.x, t.current.y
|
return t.current.x, t.current.y
|
||||||
}
|
}
|
||||||
|
|
||||||
func tileAt(tiles map[*Tile]struct{}, x, y int) *Tile {
|
func (t *Tile) NextValue() int {
|
||||||
for t := range tiles {
|
return t.next.value
|
||||||
if t.current.x == x && t.current.y == y {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) (map[*Tile]struct{}, bool) {
|
func (t *Tile) NextPos() (int, int) {
|
||||||
|
return t.next.x, t.next.y
|
||||||
|
}
|
||||||
|
|
||||||
|
func tileAt(tiles map[*Tile]struct{}, x, y int) *Tile {
|
||||||
|
var result *Tile
|
||||||
|
for t := range tiles {
|
||||||
|
if t.current.x != x || t.current.y != y {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if result != nil {
|
||||||
|
panic("not reach")
|
||||||
|
}
|
||||||
|
result = t
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextTileAt(tiles map[*Tile]struct{}, x, y int) *Tile {
|
||||||
|
var result *Tile
|
||||||
|
for t := range tiles {
|
||||||
|
if t.next.x != x || t.next.y != y || t.next.value == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if result != nil {
|
||||||
|
panic("not reach")
|
||||||
|
}
|
||||||
|
result = t
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) bool {
|
||||||
vx, vy := dir.Vector()
|
vx, vy := dir.Vector()
|
||||||
tx := []int{}
|
tx := []int{}
|
||||||
ty := []int{}
|
ty := []int{}
|
||||||
@ -78,8 +106,6 @@ func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) (map[*Tile]struct{},
|
|||||||
sort.Sort(sort.Reverse(sort.IntSlice(ty)))
|
sort.Sort(sort.Reverse(sort.IntSlice(ty)))
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTiles := map[*Tile]struct{}{}
|
|
||||||
merged := map[*Tile]bool{}
|
|
||||||
moved := false
|
moved := false
|
||||||
for _, j := range ty {
|
for _, j := range ty {
|
||||||
for _, i := range tx {
|
for _, i := range tx {
|
||||||
@ -95,40 +121,48 @@ func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) (map[*Tile]struct{},
|
|||||||
if ni < 0 || ni >= size || nj < 0 || nj >= size {
|
if ni < 0 || ni >= size || nj < 0 || nj >= size {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
tt := tileAt(nextTiles, ni, nj)
|
tt := nextTileAt(tiles, ni, nj)
|
||||||
if tt == nil {
|
if tt == nil {
|
||||||
ii = ni
|
ii = ni
|
||||||
jj = nj
|
jj = nj
|
||||||
moved = true
|
moved = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if t.current.value != tt.current.value {
|
if t.current.value != tt.next.value {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !merged[tt] {
|
if tt.current.value != tt.next.value {
|
||||||
ii = ni
|
// already merged
|
||||||
jj = nj
|
break
|
||||||
moved = true
|
|
||||||
}
|
}
|
||||||
|
ii = ni
|
||||||
|
jj = nj
|
||||||
|
moved = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if tt := tileAt(tiles, ii, jj); tt != t && tt != nil {
|
if tt := nextTileAt(tiles, ii, jj); tt != t && tt != nil {
|
||||||
t.current.value += tt.current.value
|
t.next.value = t.current.value + tt.next.value
|
||||||
merged[t] = true
|
tt.next = TileData{}
|
||||||
delete(nextTiles, tt)
|
} else {
|
||||||
|
t.next.value = t.current.value
|
||||||
}
|
}
|
||||||
t.current.x = ii
|
t.next.x = ii
|
||||||
t.current.y = jj
|
t.next.y = jj
|
||||||
nextTiles[t] = struct{}{}
|
t.moving = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nextTiles, moved
|
return moved
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRandomTile(tiles map[*Tile]struct{}, size int) error {
|
func addRandomTile(tiles map[*Tile]struct{}, size int) error {
|
||||||
cells := make([]bool, size*size)
|
cells := make([]bool, size*size)
|
||||||
for t := range tiles {
|
for t := range tiles {
|
||||||
i := t.current.x + t.current.y*size
|
i := 0
|
||||||
|
if t.moving {
|
||||||
|
i = t.next.x + t.next.y*size
|
||||||
|
} else {
|
||||||
|
i = t.current.x + t.current.y*size
|
||||||
|
}
|
||||||
cells[i] = true
|
cells[i] = true
|
||||||
}
|
}
|
||||||
availableCells := []int{}
|
availableCells := []int{}
|
||||||
@ -153,6 +187,16 @@ func addRandomTile(tiles map[*Tile]struct{}, size int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tile) Update() error {
|
||||||
|
if !t.moving {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
t.current = t.next
|
||||||
|
t.next = TileData{}
|
||||||
|
t.moving = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func colorToScale(clr color.Color) (float64, float64, float64, float64) {
|
func colorToScale(clr color.Color) (float64, float64, float64, float64) {
|
||||||
r, g, b, a := clr.RGBA()
|
r, g, b, a := clr.RGBA()
|
||||||
rf := float64(r) / 0xffff
|
rf := float64(r) / 0xffff
|
||||||
@ -170,10 +214,10 @@ func colorToScale(clr color.Color) (float64, float64, float64, float64) {
|
|||||||
|
|
||||||
func (t *Tile) Draw(boardImage *ebiten.Image) error {
|
func (t *Tile) Draw(boardImage *ebiten.Image) error {
|
||||||
i, j := t.current.x, t.current.y
|
i, j := t.current.x, t.current.y
|
||||||
|
v := t.current.value
|
||||||
op := &ebiten.DrawImageOptions{}
|
op := &ebiten.DrawImageOptions{}
|
||||||
x := i*tileSize + (i+1)*tileMargin
|
x := i*tileSize + (i+1)*tileMargin
|
||||||
y := j*tileSize + (j+1)*tileMargin
|
y := j*tileSize + (j+1)*tileMargin
|
||||||
v := t.current.value
|
|
||||||
op.GeoM.Translate(float64(x), float64(y))
|
op.GeoM.Translate(float64(x), float64(y))
|
||||||
r, g, b, a := colorToScale(tileBackgroundColor(v))
|
r, g, b, a := colorToScale(tileBackgroundColor(v))
|
||||||
op.ColorM.Scale(r, g, b, a)
|
op.ColorM.Scale(r, g, b, a)
|
||||||
|
@ -36,13 +36,19 @@ func cellsToTiles(cells []int, size int) map[*Tile]struct{} {
|
|||||||
return tiles
|
return tiles
|
||||||
}
|
}
|
||||||
|
|
||||||
func tilesToCells(tiles map[*Tile]struct{}, size int) []int {
|
func tilesToCells(tiles map[*Tile]struct{}, size int) ([]int, []int) {
|
||||||
cells := make([]int, size*size)
|
cells := make([]int, size*size)
|
||||||
|
nextCells := make([]int, size*size)
|
||||||
for t := range tiles {
|
for t := range tiles {
|
||||||
x, y := t.Pos()
|
x, y := t.Pos()
|
||||||
cells[x+y*size] = t.Value()
|
cells[x+y*size] = t.Value()
|
||||||
|
if t.NextValue() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
nx, ny := t.NextPos()
|
||||||
|
nextCells[nx+ny*size] = t.NextValue()
|
||||||
}
|
}
|
||||||
return cells
|
return cells, nextCells
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMoveTiles(t *testing.T) {
|
func TestMoveTiles(t *testing.T) {
|
||||||
@ -82,6 +88,21 @@ func TestMoveTiles(t *testing.T) {
|
|||||||
0, 0, 0, 2,
|
0, 0, 0, 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Dir: DirUp,
|
||||||
|
Input: []int{
|
||||||
|
2, 0, 0, 0,
|
||||||
|
0, 2, 0, 0,
|
||||||
|
0, 0, 2, 0,
|
||||||
|
0, 0, 0, 2,
|
||||||
|
},
|
||||||
|
Want: []int{
|
||||||
|
2, 2, 2, 2,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Dir: DirRight,
|
Dir: DirRight,
|
||||||
Input: []int{
|
Input: []int{
|
||||||
@ -189,10 +210,10 @@ func TestMoveTiles(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
|
want, _ := tilesToCells(cellsToTiles(test.Want, size), size)
|
||||||
tiles := cellsToTiles(test.Input, size)
|
tiles := cellsToTiles(test.Input, size)
|
||||||
want := tilesToCells(cellsToTiles(test.Want, size), size)
|
MoveTiles(tiles, size, test.Dir)
|
||||||
gotTiles, _ := MoveTiles(tiles, size, test.Dir)
|
_, got := tilesToCells(tiles, size)
|
||||||
got := tilesToCells(gotTiles, size)
|
|
||||||
if fmt.Sprint(got) != fmt.Sprint(want) {
|
if fmt.Sprint(got) != fmt.Sprint(want) {
|
||||||
t.Errorf("dir: %s, input: %v, got %v; want %v", test.Dir.String(), test.Input, got, want)
|
t.Errorf("dir: %s, input: %v, got %v; want %v", test.Dir.String(), test.Input, got, want)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user