godot-puzzle/board.gd
2025-05-03 19:37:06 -04:00

98 lines
2.4 KiB
GDScript

class_name Board
extends Node3D
@export var dims: Vector2i
# idea: board has very little logic, delegates to something else
# l8r tho
# literally just linearly search to find pieces at a position
# children
# for zooming out to see the whole puzzle
func top_left_aabb() -> AABB:
return AABB(position-Vector3(1,0,1), Vector3.ONE*0.1)
func bottom_right_aabb() -> AABB:
return AABB(position + Vector3(dims.x, 0, dims.y), Vector3.ONE*0.1)
# todo: Array[Piece]
func pieces() -> Array:
# todo: sort for consistency
return get_children()
func pieces_at(pos: Vector2i) -> Array[Piece]:
var out: Array[Piece] = []
for piece in pieces():
if piece.lpos == pos:
out.push_back(piece)
return out
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 any_at(pos: Vector2i, filter: Callable) -> bool:
return pieces_at(pos).any(filter)
func type_at(pos: Vector2i, type: Piece.Type) -> Piece:
return find_piece_at(pos, func(p): return p.type == type)
# TODO: ball collisions
func solid_at(pos: Vector2i) -> bool:
return any_at(pos, func(p): return p.type == Piece.Type.Wall or p.type == Piece.Type.Ball)
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]):
for p in piece:
add_piece(p)
static func from_string(src: String) -> Board:
var lines := src.lstrip("\n").rstrip("\n").split("\n")
var width := 0
for line in lines:
width = max(width, line.length())
var dims := Vector2i(width, lines.size())
var board := Board.new()
board.dims = dims
for y in range(lines.size()):
var line := lines[y]
for x in range(line.length()):
var c := line[x]
var pos := Vector2i(x, y)
match c:
".": board.add_piece(Piece.goal(pos))
"+": board.add_pieces([Piece.goal(pos), Piece.player(pos)])
"o": board.add_piece(Piece.ball(pos))
"O": assert(false)
"@": board.add_piece(Piece.player(pos))
"#": board.add_piece(Piece.wall(pos))
"_": board.add_piece(Piece.floor_ice(pos))
return board
func do_step():
for piece in pieces():
piece.do_step(self)
func undo_step() -> Callable:
var undos: Array[Callable] = []
for piece in pieces():
undos.push_back(piece.undo_step())
return func():
for undo in undos:
undo.call()