99 lines
2.3 KiB
GDScript
99 lines
2.3 KiB
GDScript
class_name State
|
|
extends Resource
|
|
|
|
@export var dims: Vector2i
|
|
@export var player_pos: Vector2i
|
|
@export var walls := BitMap.new()
|
|
@export var goals := BitMap.new()
|
|
@export var boxes := BitMap.new()
|
|
|
|
static func from_string(src: String) -> State:
|
|
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 state := State.new()
|
|
state.dims = dims
|
|
state.walls.create(dims)
|
|
state.goals.create(dims)
|
|
state.boxes.create(dims)
|
|
|
|
for y in range(lines.size()):
|
|
var line := lines[y]
|
|
for x in range(line.length()):
|
|
var pos := Vector2i(x, y)
|
|
match line[x]:
|
|
"#": state.walls.set_bitv(pos, true)
|
|
".": state.goals.set_bitv(pos, true)
|
|
"@":
|
|
assert(not state.player_pos)
|
|
state.player_pos = pos
|
|
"+":
|
|
assert(not state.player_pos)
|
|
state.goals.set_bitv(pos, true)
|
|
state.player_pos = pos
|
|
"$": state.boxes.set_bitv(pos, true)
|
|
"*":
|
|
state.goals.set_bitv(pos, true)
|
|
state.boxes.set_bitv(pos, true)
|
|
assert(state.player_pos)
|
|
|
|
return state
|
|
|
|
func solid_at(pos: Vector2i) -> bool:
|
|
return wall_at(pos) or box_at(pos)
|
|
|
|
func wall_at(pos: Vector2i) -> bool:
|
|
return walls.get_bitv(pos)
|
|
|
|
func goal_at(pos: Vector2i) -> bool:
|
|
return goals.get_bitv(pos)
|
|
|
|
func box_at(pos: Vector2i) -> bool:
|
|
return boxes.get_bitv(pos)
|
|
|
|
func passable_at(pos: Vector2i) -> bool:
|
|
return not solid_at(pos)
|
|
|
|
# todo: keep shared structure (e.g. walls are always the same)
|
|
func step(move: Vector2i) -> State:
|
|
var new: State = duplicate(true)
|
|
var p0 := new.player_pos
|
|
var p1 := p0 + move
|
|
var p2 := p1 + move
|
|
|
|
if passable_at(p1):
|
|
new.player_pos = p1
|
|
elif box_at(p1) and passable_at(p2):
|
|
new.boxes.set_bitv(p1, false)
|
|
new.boxes.set_bitv(p2, true)
|
|
new.player_pos = p1
|
|
|
|
return new
|
|
|
|
func _to_string() -> String:
|
|
var out := "#<<state:{0}>, {1}@{2}\n".format([get_instance_id(), dims, player_pos])
|
|
for y in range(dims.y):
|
|
out += " "
|
|
for x in range(dims.x):
|
|
if player_pos == Vector2i(x, y):
|
|
out += "+" if goals.get_bit(x, y) else "@"
|
|
continue
|
|
|
|
if walls.get_bit(x, y):
|
|
out += "#"
|
|
continue
|
|
|
|
match [goals.get_bit(x, y), boxes.get_bit(x, y)]:
|
|
[true, true ]: out += "*"
|
|
[true, false]: out += "."
|
|
[false, true ]: out += "$"
|
|
[false, false]: out += " "
|
|
out += "\n"
|
|
out += ">"
|
|
return out
|