godot-puzzle/board.gd
2025-05-02 00:29:45 -04:00

80 lines
2 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:
return get_children()
func pieces_at(pos: Vector2i) -> Array[Piece]:
var out: Array[Piece] = []
for piece in get_children():
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 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]):
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.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