UndoRedo poc

This commit is contained in:
mehbark 2025-05-01 16:02:47 -04:00
parent 3653f2a18d
commit 498554be29
3 changed files with 87 additions and 38 deletions

View file

@ -3,32 +3,47 @@ extends Node3D
@export var dims: Vector2i
var pieces: Dictionary[Vector2i, Array] = {}
# idea: board has very little logic, delegates to something else
# l8r tho
# literally just linearly search to find pieces at a position
# children
# todo: Array[Piece]
func pieces() -> Array:
return get_children()
func pieces_at(pos: Vector2i) -> Array[Piece]:
return pieces.get(pos, [])
var out: Array[Piece] = []
for piece in get_children():
if piece.lpos == pos:
out.push_back(piece)
return out
func remove_piece(piece: Piece, from: Vector2i):
pieces[from] = pieces_at(from).filter(func (p): return p != piece)
func find_piece_at(pos: Vector2i, filter: Callable) -> Piece:
var at := pieces_at(pos)
var idx := at.find_custom(filter)
if idx < 0: return
return at[idx]
func add_piece(piece: Piece, to: Vector2i):
pieces.get_or_add(to, []).push_back(piece)
piece.position = Vector3(to.x, 0, to.y)
func any_at(pos: Vector2i, filter: Callable) -> bool:
return pieces_at(pos).any(filter)
func solid_at(pos: Vector2i) -> bool:
return any_at(pos, func(p): return p.type == Piece.Type.Wall or p.type == Piece.Type.Box)
func passable_at(pos: Vector2i) -> bool:
return not solid_at(pos)
func remove_piece(piece: Piece):
remove_child(piece)
func add_piece(piece: Piece):
add_child(piece)
func add_pieces(piece: Array[Piece], to: Vector2i):
func add_pieces(piece: Array[Piece]):
for p in piece:
add_piece(p, to)
func do_move(piece: Piece, from: Vector2i, to: Vector2i) -> Callable:
return func():
remove_piece(piece, from)
add_piece(piece, to)
func undo_move(piece: Piece, from: Vector2i, to: Vector2i) -> Callable:
return func():
remove_piece(piece, to)
add_piece(piece, from)
add_piece(p)
static func from_string(src: String) -> Board:
var lines := src.lstrip("\n").rstrip("\n").split("\n")
@ -48,10 +63,10 @@ static func from_string(src: String) -> Board:
var c := line[x]
var pos := Vector2i(x, y)
match c:
".": board.add_piece(Piece.goal(), pos)
"*": board.add_pieces([Piece.goal(), Piece.box()], pos)
"+": board.add_pieces([Piece.goal(), Piece.player()], pos)
"$": board.add_piece(Piece.box(), pos)
"@": board.add_piece(Piece.player(), pos)
"#": board.add_piece(Piece.wall(), pos)
".": board.add_piece(Piece.goal(pos))
"*": board.add_pieces([Piece.goal(pos), Piece.box(pos)])
"+": board.add_pieces([Piece.goal(pos), Piece.player(pos)])
"$": board.add_piece(Piece.box(pos))
"@": board.add_piece(Piece.player(pos))
"#": board.add_piece(Piece.wall(pos))
return board

24
main.gd
View file

@ -13,9 +13,14 @@ var microban_1 := "
var hist := UndoRedo.new()
@onready var board := Board.from_string(microban_1)
var player: Piece
func _ready() -> void:
add_child(board)
for piece in board.pieces():
if piece.type == Piece.Type.Player:
player = piece
break
func _input(event: InputEvent) -> void:
if event.is_action_pressed("u"):
@ -29,7 +34,6 @@ func _input(event: InputEvent) -> void:
elif event.is_action_pressed("undo"):
hist.undo()
elif event.is_action_pressed("redo"):
print('hi')
hist.redo()
elif event.is_action_pressed("restart"):
restart()
@ -39,6 +43,18 @@ func restart():
pass
func step(move: Vector2i):
hist.create_action("move")
hist.commit_action()
var pos := player.lpos
var box := board.find_piece_at(pos + move, func(p): return p.type == Piece.Type.Box)
if board.passable_at(pos + move):
hist.create_action("move")
hist.add_do_method(player.do_move(move))
hist.add_undo_method(player.undo_move())
hist.commit_action()
elif box != null and board.passable_at(pos + move * 2):
hist.create_action("push")
hist.add_do_method(player.do_move(move))
hist.add_do_method(box.do_move(move))
hist.add_undo_method(player.undo_move())
hist.add_undo_method(box.undo_move())
hist.commit_action()

View file

@ -13,22 +13,40 @@ enum Type {
Player,
}
# logical position
@export var lpos: Vector2i:
get:
return lpos
set(val):
lpos = val
position = Vector3(val.x, 0, val.y)
@export var type: Piece.Type
static func make(type: Piece.Type, mesh: Mesh) -> Piece:
func do_move(move: Vector2i) -> Callable:
return func():
lpos += move
func undo_move() -> Callable:
var old_pos := lpos
return func():
lpos = old_pos
static func make(lpos: Vector2i, type: Piece.Type, mesh: Mesh) -> Piece:
var piece := Piece.new()
piece.lpos = lpos
piece.mesh = mesh
piece.type = type
return piece
static func wall() -> Piece:
return make(Piece.Type.Wall, WALL)
static func wall(lpos: Vector2i) -> Piece:
return make(lpos, Piece.Type.Wall, WALL)
static func goal() -> Piece:
return make(Piece.Type.Goal, GOAL)
static func goal(lpos: Vector2i) -> Piece:
return make(lpos, Piece.Type.Goal, GOAL)
static func box() -> Piece:
return make(Piece.Type.Box, BOX)
static func box(lpos: Vector2i) -> Piece:
return make(lpos, Piece.Type.Box, BOX)
static func player() -> Piece:
return make(Piece.Type.Player, PLAYER)
static func player(lpos: Vector2i) -> Piece:
return make(lpos, Piece.Type.Player, PLAYER)