///- --package .
map (test)
test map: prelude
///- --test static --symbol
:< testing
:== bytes = array u8
:= otbm_node_start () : u8 = 254u8
:= otbm_node_end () : u8 = 255u8
:= otbm_escape () : u8 = 253u8
:= otbm_identifier_bytes () : i32 = 4
:= area_node () : i32 = 4
:= tile_node () : i32 = 5
:= item_node () : i32 = 6
:= house_tile_node () : i32 = 14
:= tile_flags_attribute () : i32 = 3
:= tile_flags_attribute_bytes () : i32 = 5
:= protection_zone_flag () : i32 = 1
:= item_attribute () : i32 = 9
:= item_attribute_bytes () : i32 = 3
:= tile_props_before_attributes () : i32 = 2
:= house_tile_props_before_attributes () : i32 = 6
:= item_id_limit () : i32 = 65536
:= node_depth_limit () : i32 = 256
:= appearance_field () : i32 = 1
:= appearance_id_field () : i32 = 1
:= appearance_flags_field () : i32 = 3
:= unpassable_flag () : i32 = 13
:= sight_blocking_flag () : i32 = 15
:= bank_flag () : i32 = 1
:= bank_waypoints_field () : i32 = 1
:= height_flag () : i32 = 27
:= climbable_height_items () : i32 = 3
:= road_ground_speed () : i32 = 100
:= spot_x () : i32 = 1933
:= spot_y () : i32 = 1350
:= spot_z () : i32 = 7
:= spot_radius () : i32 = 45
:= spot_side () : i32 = 2 * spot_radius () + 1
:= row_word_bits () : i32 = 32
:= row_word_count () : i32 = (spot_side () + row_word_bits () - 1) / row_word_bits ()
:= (++) (a : string) (b : string) : string = sm'::(++#) a b
:= byte (b : bytes) (i : i32) : i32 = conv (index b i)
:= known_item (identity : i32) : bool = identity >= 0 && identity < item_id_limit ()
:= filled \* t. (count : i32) (value : t) : array t =
:= x : array t = create count
:~ ^ fill (i : i32) : () =
? i < count ?>
set x i value
fill (i + 1)
fill 0
x
:~ ^ varint_from (b : bytes) (i : i32) (value : u64) (shift : i32) : u64 * i32 =
:= c = index b i
:= value = value ||| ((conv (c &&& 127u8) : u64) <<< shift)
? c < 128u8 ?> value, i + 1 |: varint_from b (i + 1) value (shift + 7)
:~ varint (b : bytes) (start : i32) : u64 * i32 = varint_from b start 0u64 0
:== visitors state = { on_varint : state -> i32 -> u64 -> state; on_bytes : state -> i32 -> i32 -> i32 -> state }
:== field_head = { number : i32; wire : u64; at : i32 }
:= field_at (b : bytes) (i : i32) : field_head =
:= key, at = varint b i
{ number = conv (key >>> 3); wire = key &&& 7u64; at = at }
:= skipped_wire (i : i32) (wire : u64) : i32 =
? wire = 5u64 ?> i + 4
|? wire = 1u64 ?> i + 8
|: failwith "map: appearances.dat has an unknown protobuf wire type"
:= varint_field \* state. (b : bytes) (f : field_head) (s : state) (v : visitors state) : i32 * state =
:= value, i = varint b f::at
i, v::on_varint s f::number value
:= bytes_field \* state. (b : bytes) (f : field_head) (s : state) (v : visitors state) : i32 * state =
:= size, i = varint b f::at
i + conv size, v::on_bytes s f::number i (i + conv size)
:= field_next \* state. (b : bytes) (i : i32) (s : state) (v : visitors state) : i32 * state =
:= f = field_at b i
? f::wire = 0u64 ?> varint_field b f s v
|? f::wire = 2u64 ?> bytes_field b f s v
|: skipped_wire f::at f::wire, s
:= fold_fields \* st. (b : bytes) (start : i32) (stop : i32) (seed : st) (v : visitors st) : st =
:~ ^ next (i : i32) (s : st) : st =
? i >= stop ?> s
|:
:= i, s = field_next b i s v
next i s
next start seed
:== item_kinds =
{
unpassable : array bool
sight_blocking : array bool
ground : array bool
speed : array i32
height : array bool
}
:= none_marked () : array bool = filled (item_id_limit ()) !-
:= no_kinds () : item_kinds =
{
unpassable = none_marked ()
sight_blocking = none_marked ()
ground = none_marked ()
speed = filled (item_id_limit ()) 0
height = none_marked ()
}
:= varint_ignored () (field : i32) (value : u64) : () = ()
:= bytes_ignored () (field : i32) (from : i32) (stop : i32) : () = ()
:= waypoint_speed (speeds : array i32) (identity : i32) () (field : i32) (value : u64) : () =
? field = bank_waypoints_field () ?> set speeds identity (conv value)
:= bank_speed (b : bytes) (speeds : array i32) (identity : i32) (from : i32) (stop : i32) : () =
fold_fields b from stop () { on_varint = waypoint_speed speeds identity; on_bytes = bytes_ignored }
:= blocking_flag (kinds : item_kinds) (identity : i32) (flag : i32) : () =
? flag = unpassable_flag () ?> set kinds::unpassable identity !+
? flag = sight_blocking_flag () ?> set kinds::sight_blocking identity !+
:= flag_seen (kinds : item_kinds) (identity : i32) () (flag : i32) (value : u64) : () =
? flag = height_flag () ?> set kinds::height identity !+
? value <> 0u64 ?> blocking_flag kinds identity flag
:= bank_seen (b : bytes) (kinds : item_kinds) (identity : i32) (from : i32) (stop : i32) : () =
set kinds::ground identity !+
bank_speed b kinds::speed identity from stop
:= flag_bytes (b : bytes) (kinds : item_kinds) (identity : i32) () (flag : i32) (from : i32) (stop : i32) : () =
? flag = height_flag () ?> set kinds::height identity !+
? flag = bank_flag () ?> bank_seen b kinds identity from stop
:= flags_of (b : bytes) (kinds : item_kinds) (identity : i32) (from : i32) (stop : i32) : () =
fold_fields b from stop () { on_varint = flag_seen kinds identity; on_bytes = flag_bytes b kinds identity }
:== flag_span = i32 * i32 * i32
:= appearance_id (span : flag_span) (field : i32) (value : u64) : flag_span =
:= _, flags_from, flags_stop = span
? field = appearance_id_field () ?> (conv value, flags_from, flags_stop) |: span
:= appearance_flags (span : flag_span) (field : i32) (from : i32) (stop : i32) : flag_span =
:= identity, _, _ = span
? field = appearance_flags_field () ?> (identity, from, stop) |: span
:= appearance_visit () : visitors flag_span = { on_varint = appearance_id; on_bytes = appearance_flags }
:= appearance_seen (b : bytes) (kinds : item_kinds) (span : flag_span) : () =
:= identity, flags_from, flags_stop = span
? known_item identity && flags_from >= 0 ?> flags_of b kinds identity flags_from flags_stop
:= appearance (b : bytes) (kinds : item_kinds) () (field : i32) (from : i32) (stop : i32) : () =
? field = appearance_field ()
?> appearance_seen b kinds (fold_fields b from stop (-1, -1, -1) (appearance_visit ()))
:= item_kinds_of (b : bytes) : item_kinds =
:= kinds = no_kinds ()
fold_fields b 0 (length b) () { on_varint = varint_ignored; on_bytes = appearance b kinds }
kinds
:= word_byte (c : u8) : bool =
(c >= 48u8 && c <= 57u8) || (c >= 65u8 && c <= 90u8) || (c >= 97u8 && c <= 122u8) || c = 95u8
:== item_tags = { opening : bytes; closing : bytes; wanted : bytes }
:= item_tags_for (needle : string) : item_tags =
:= opening, closing = sm'::utf8_get_bytes "<item", sm'::utf8_get_bytes "</item>"
{ opening = opening; closing = closing; wanted = sm'::utf8_get_bytes needle }
:== id_names = { single : bytes; low : bytes; high : bytes }
:= id_attribute_names () : id_names =
{
single = sm'::utf8_get_bytes "id=\""
low = sm'::utf8_get_bytes "fromid=\""
high = sm'::utf8_get_bytes "toid=\""
}
:== item_scan = { text : bytes; exits : array bool; tags : item_tags; ids : id_names }
:~ ^ matches_from (text : bytes) (pattern : bytes) (i : i32) (k : i32) : bool =
? k >= length pattern ?> !+
|? i + k >= length text ?> !-
|? index text (i + k) <> index pattern k ?> !-
|: matches_from text pattern i (k + 1)
:~ ^ find_from (text : bytes) (i : i32) (stop : i32) (pattern : bytes) : i32 =
? i >= stop ?> -1 |? matches_from text pattern i 0 ?> i |: find_from text (i + 1) stop pattern
:~ ^ find_byte (text : bytes) (i : i32) (wanted : u8) : i32 =
? i >= length text ?> -1 |? index text i = wanted ?> i |: find_byte text (i + 1) wanted
:= word_start (text : bytes) (i : i32) : bool = i = 0 || word_byte (index text (i - 1)) = !-
:~ ^ digits_from (text : bytes) (from : i32) (k : i32) (value : i32) : i32 =
:= c = ? k < length text ?> index text k |: 0u8
? c >= 48u8 && c <= 57u8 ?> digits_from text from (k + 1) (value * 10 + conv (c - 48u8))
|? k > from && c = 34u8 ?> value
|: -1
:= value_at (text : bytes) (at : i32) (pattern : bytes) : i32 =
? word_start text at ?> digits_from text (at + length pattern) (at + length pattern) 0 |: -1
:~ ^ attribute_from (text : bytes) (i : i32) (stop : i32) (pattern : bytes) : i32 =
:= at = find_from text i stop pattern
:= value = ? at < 0 ?> -1 |: value_at text at pattern
? at < 0 || value >= 0 ?> value |: attribute_from text (at + 1) stop pattern
:~ ^ mark_ids (exits : array bool) (identity : i32) (high : i32) : () =
? identity <= high ?>
? known_item identity ?> set exits identity !+
mark_ids exits (identity + 1) high
:= range_ids (s : item_scan) (after : i32) (head_end : i32) : () =
:= low = attribute_from s::text after head_end s::ids::low
:= high = attribute_from s::text after head_end s::ids::high
? low >= 0 && high >= 0 ?> mark_ids s::exits low high
:= item_ids (s : item_scan) (after : i32) (head_end : i32) : () =
:= single = attribute_from s::text after head_end s::ids::single
? single >= 0 ?> mark_ids s::exits single single |: range_ids s after head_end
:= item_closed (s : item_scan) (after : i32) (head_end : i32) (close_at : i32) : i32 =
? find_from s::text (head_end + 1) close_at s::tags::wanted >= 0 ?> item_ids s after head_end
close_at + length s::tags::closing
:= item_body (s : item_scan) (open_at : i32) (after : i32) (head_end : i32) : i32 =
:= close_at = find_from s::text (head_end + 1) (length s::text) s::tags::closing
? close_at < 0 ?> open_at + 1 |: item_closed s after head_end close_at
:= item_head (s : item_scan) (open_at : i32) (after : i32) : i32 =
:= head_end = find_byte s::text after 62u8
? head_end < 0 ?> -1
|? index s::text (head_end - 1) = 47u8 ?> open_at + 1
|: item_body s open_at after head_end
:= item_at (s : item_scan) (open_at : i32) : i32 =
:= after = open_at + length s::tags::opening
? after < length s::text && word_byte (index s::text after) = !- ?> item_head s open_at after |: open_at + 1
:~ ^ items_from (s : item_scan) (from : i32) : () =
:= open_at = find_from s::text from (length s::text) s::tags::opening
? open_at >= 0 ?>
:= next = item_at s open_at
? next >= 0 ?> items_from s next
:= ids_with (text : bytes) (needle : string) : array bool =
:= exits = filled (item_id_limit ()) !-
items_from { text = text; exits = exits; tags = item_tags_for needle; ids = id_attribute_names () } 0
exits
:== map_inputs = { b : bytes; kinds : item_kinds; exits : array bool; teleports : array bool }
:== node_stack = { kind : array i32; area_x : array i32; area_y : array i32; area_z : array i32; item_id : array i32 }
:== tile_mark_stack =
{
ground : array bool
unpassable : array bool
sight_blocking : array bool
exit : array bool
teleport : array bool
protection : array bool
}
:== tile_count_stack =
{
cell : array i32
attribute_speed : array i32
child_speed : array i32
height_items : array i32
}
:== walk_cells = { blocked : array bool; sight_blocked : array bool; road : array bool; walkable : array bool }
:== mark_cells =
{
floor_change : array bool
teleport : array bool
climbable : array bool
protection : array bool
house : array bool
}
:== grid = { walk : walk_cells; marks : mark_cells }
:== stacks = { nodes : node_stack; marks : tile_mark_stack; counts : tile_count_stack; grid : grid }
:== node_at = { depth : i32; from : i32; stop : i32 }
:= fresh_nodes (n : i32) : node_stack =
{ kind = filled n 0; area_x = filled n 0; area_y = filled n 0; area_z = filled n 0; item_id = filled n (-1) }
:= fresh_tile_marks (n : i32) : tile_mark_stack =
{
ground = filled n !-
unpassable = filled n !-
sight_blocking = filled n !-
exit = filled n !-
teleport = filled n !-
protection = filled n !-
}
:= fresh_tile_counts (n : i32) : tile_count_stack =
{ cell = filled n (-1); attribute_speed = filled n 0; child_speed = filled n 0; height_items = filled n 0 }
:= fresh_walk_cells (n : i32) : walk_cells =
{ blocked = filled n !+; sight_blocked = filled n !-; road = filled n !-; walkable = filled n !- }
:= fresh_mark_cells (n : i32) : mark_cells =
{
floor_change = filled n !-
teleport = filled n !-
climbable = filled n !-
protection = filled n !-
house = filled n !-
}
:= fresh_grid () : grid =
:= n = spot_side () * spot_side ()
{ walk = fresh_walk_cells n; marks = fresh_mark_cells n }
:= fresh_stacks () : stacks =
:= depths = node_depth_limit ()
{
nodes = fresh_nodes depths
marks = fresh_tile_marks depths
counts = fresh_tile_counts depths
grid = fresh_grid ()
}
:~ ^ props_end (b : bytes) (i : i32) : i32 =
:= c = index b i
? c = otbm_escape () ?> props_end b (i + 2)
|? c = otbm_node_start () || c = otbm_node_end () ?> i
|: props_end b (i + 1)
:~ ^ prop_count_from (b : bytes) (i : i32) (stop : i32) (total : i32) : i32 =
? i >= stop ?> total
|? index b i = otbm_escape () ?> prop_count_from b (i + 2) stop (total + 1)
|: prop_count_from b (i + 1) stop (total + 1)
:= prop_count (b : bytes) (from : i32) (stop : i32) : i32 = prop_count_from b from stop 0
:~ ^ prop (b : bytes) (i : i32) (k : i32) : i32 =
:= at = ? index b i = otbm_escape () ?> i + 1 |: i
? k = 0 ?> byte b at |: prop b (at + 1) (k - 1)
:= prop_u16 (b : bytes) (from : i32) (k : i32) : i32 = prop b from k + 256 * prop b from (k + 1)
:= tile_kind (kind : i32) : bool = kind = tile_node () || kind = house_tile_node ()
:= copy_mark (from : array bool) (identity : i32) (into : array bool) (tile : i32) : () =
? index from identity ?> set into tile !+
:= note_blocking (k : item_kinds) (s : tile_mark_stack) (tile : i32) (identity : i32) : () =
copy_mark k::ground identity s::ground tile
copy_mark k::unpassable identity s::unpassable tile
copy_mark k::sight_blocking identity s::sight_blocking tile
:= note_passage (m : map_inputs) (s : tile_mark_stack) (tile : i32) (identity : i32) : () =
copy_mark m::exits identity s::exit tile
copy_mark m::teleports identity s::teleport tile
:= count_height (heights : array i32) (tile : i32) : () = set heights tile (index heights tile + 1)
:= note_kind (m : map_inputs) (t : stacks) (tile : i32) (identity : i32) : () =
note_blocking m::kinds t::marks tile identity
note_passage m t::marks tile identity
? index m::kinds::height identity ?> count_height t::counts::height_items tile
:= note_attribute_item (m : map_inputs) (t : stacks) (tile : i32) (identity : i32) : () =
? known_item identity ?>
note_kind m t tile identity
:= speed = index m::kinds::speed identity
? speed > 0 ?> set t::counts::attribute_speed tile speed
:= first_speed (speeds : array i32) (tile : i32) (speed : i32) : () =
? index speeds tile = 0 && speed > 0 ?> set speeds tile speed
:= note_child_item (m : map_inputs) (t : stacks) (tile : i32) (identity : i32) : () =
? known_item identity ?>
note_kind m t tile identity
first_speed t::counts::child_speed tile (index m::kinds::speed identity)
:~ ^ nearest_tile_below (kinds : array i32) (d : i32) : i32 =
? d < 0 ?> -1 |? tile_kind (index kinds d) ?> d |: nearest_tile_below kinds (d - 1)
:= in_spot (dx : i32) (dy : i32) : bool =
:= radius = spot_radius ()
dx >= 0 - radius && dx <= radius && dy >= 0 - radius && dy <= radius
:= spot_cell (dx : i32) (dy : i32) : i32 = (dy + spot_radius ()) * spot_side () + dx + spot_radius ()
:= reset_marks (s : tile_mark_stack) (depth : i32) : () =
set s::ground depth !-
set s::unpassable depth !-
set s::sight_blocking depth !-
set s::exit depth !-
set s::teleport depth !-
set s::protection depth !-
:= reset_counts (c : tile_count_stack) (depth : i32) (cell : i32) : () =
set c::cell depth cell
set c::attribute_speed depth 0
set c::child_speed depth 0
set c::height_items depth 0
:= flags_attribute (m : map_inputs) (t : stacks) (n : node_at) (offset : i32) : i32 =
? prop m::b n::from (offset + 1) % 2 = protection_zone_flag () ?> set t::marks::protection n::depth !+
offset + tile_flags_attribute_bytes ()
:= item_attribute_at (m : map_inputs) (t : stacks) (n : node_at) (offset : i32) : i32 =
note_attribute_item m t n::depth (prop_u16 m::b n::from (offset + 1))
offset + item_attribute_bytes ()
:= attribute_step (m : map_inputs) (t : stacks) (n : node_at) (offset : i32) : i32 =
:= kind = prop m::b n::from offset
? kind = tile_flags_attribute () ?> flags_attribute m t n offset
|? kind = item_attribute () ?> item_attribute_at m t n offset
|: -1
:~ ^ tile_attributes (m : map_inputs) (t : stacks) (n : node_at) (count : i32) (offset : i32) : () =
? offset >= 0 && offset < count ?> tile_attributes m t n count (attribute_step m t n offset)
:= first_attribute (kind : i32) : i32 =
? kind = house_tile_node () ?> house_tile_props_before_attributes () |: tile_props_before_attributes ()
:= tile_opened (m : map_inputs) (t : stacks) (n : node_at) (cell : i32) : () =
reset_marks t::marks n::depth
reset_counts t::counts n::depth cell
tile_attributes m t n (prop_count m::b n::from n::stop) (first_attribute (index t::nodes::kind n::depth))
:= area_dx (b : bytes) (nodes : node_stack) (n : node_at) (parent : i32) : i32 =
index nodes::area_x parent + prop b n::from 0 - spot_x ()
:= area_dy (b : bytes) (nodes : node_stack) (n : node_at) (parent : i32) : i32 =
index nodes::area_y parent + prop b n::from 1 - spot_y ()
:= area_cell (b : bytes) (nodes : node_stack) (n : node_at) (parent : i32) : i32 =
:= dx, dy = area_dx b nodes n parent, area_dy b nodes n parent
? index nodes::area_z parent = spot_z () && in_spot dx dy ?> spot_cell dx dy |: -1
:= parent_area (nodes : node_stack) (depth : i32) : bool = depth >= 1 && index nodes::kind (depth - 1) = area_node ()
:= open_tile (m : map_inputs) (t : stacks) (n : node_at) : () =
set t::counts::cell n::depth (-1)
? parent_area t::nodes n::depth ?>
:= cell = area_cell m::b t::nodes n (n::depth - 1)
? cell >= 0 ?> tile_opened m t n cell
:= close_item (m : map_inputs) (t : stacks) (depth : i32) : () =
:= tile = nearest_tile_below t::nodes::kind (depth - 1)
? tile >= 0 && index t::counts::cell tile >= 0 ?> note_child_item m t tile (index t::nodes::item_id depth)
:= tile_walkable (s : tile_mark_stack) (depth : i32) : bool = index s::ground depth && index s::unpassable depth = !-
:= tile_speed (c : tile_count_stack) (depth : i32) : i32 =
:= attribute_speed = index c::attribute_speed depth
? attribute_speed > 0 ?> attribute_speed |: index c::child_speed depth
:= climbable_tile (c : tile_count_stack) (depth : i32) : bool = index c::height_items depth >= climbable_height_items ()
:= blocking_closed (s : tile_mark_stack) (g : walk_cells) (depth : i32) (cell : i32) (walkable : bool) : () =
set g::blocked cell (walkable = !- || index s::exit depth || index s::teleport depth)
set g::sight_blocked cell (index s::sight_blocking depth)
:= walk_closed (t : stacks) (g : walk_cells) (depth : i32) (cell : i32) : () =
:= walkable = tile_walkable t::marks depth
set g::walkable cell walkable
blocking_closed t::marks g depth cell walkable
:= passage_closed (s : tile_mark_stack) (g : mark_cells) (depth : i32) (cell : i32) : () =
set g::floor_change cell (index s::exit depth)
set g::teleport cell (index s::teleport depth)
:= zone_closed (t : stacks) (g : mark_cells) (depth : i32) (kind : i32) (cell : i32) : () =
set g::climbable cell (climbable_tile t::counts depth)
set g::protection cell (index t::marks::protection depth)
set g::house cell (kind = house_tile_node ())
:= road_closed (c : tile_count_stack) (g : walk_cells) (depth : i32) (cell : i32) : () =
set g::road cell (tile_speed c depth = road_ground_speed ())
:= tile_closed (t : stacks) (depth : i32) (kind : i32) (cell : i32) : () =
walk_closed t t::grid::walk depth cell
passage_closed t::marks t::grid::marks depth cell
zone_closed t t::grid::marks depth kind cell
road_closed t::counts t::grid::walk depth cell
:= close_node (m : map_inputs) (t : stacks) (depth : i32) : () =
:= kind = index t::nodes::kind depth
? kind = item_node () ?> close_item m t depth
|? tile_kind kind && index t::counts::cell depth >= 0 ?> tile_closed t depth kind (index t::counts::cell depth)
:= area_opened (b : bytes) (nodes : node_stack) (n : node_at) : () =
set nodes::area_x n::depth (prop_u16 b n::from 0)
set nodes::area_y n::depth (prop_u16 b n::from 2)
set nodes::area_z n::depth (prop b n::from 4)
:= item_identity (b : bytes) (n : node_at) : i32 = ? prop_count b n::from n::stop >= 2 ?> prop_u16 b n::from 0 |: -1
:= node_opened (m : map_inputs) (t : stacks) (n : node_at) (kind : i32) : () =
? kind = area_node () ?> area_opened m::b t::nodes n
|? tile_kind kind ?> open_tile m t n
|? kind = item_node () ?> set t::nodes::item_id n::depth (item_identity m::b n)
:= node_start (m : map_inputs) (t : stacks) (i : i32) (depth : i32) : i32 =
:= kind, from = byte m::b (i + 1), i + 2
:= n = { depth = depth + 1; from = from; stop = props_end m::b from }
set t::nodes::kind n::depth kind
node_opened m t n kind
n::stop
:= node_closed (m : map_inputs) (t : stacks) (i : i32) (depth : i32) : i32 * i32 =
? depth >= 0 ?> close_node m t depth
i + 1, depth - 1
:= walk_step (m : map_inputs) (t : stacks) (i : i32) (depth : i32) : i32 * i32 =
:= c = index m::b i
? c = otbm_node_start () ?> (node_start m t i depth, depth + 1)
|? c = otbm_node_end () ?> node_closed m t i depth
|: (i + 1, depth)
:~ ^ walk_from (m : map_inputs) (t : stacks) (i : i32) (depth : i32) : () =
? i < length m::b ?>
:= i, depth = walk_step m t i depth
walk_from m t i depth
:= walk_tiles (b : bytes) (kinds : item_kinds) (exits : array bool) (teleports : array bool) : grid =
:= m, t = { b = b; kinds = kinds; exits = exits; teleports = teleports }, fresh_stacks ()
walk_from m t (otbm_identifier_bytes ()) (-1)
t::grid
:= bit_set (cells : array bool) (row : i32) (column : i32) : bool =
column < spot_side () && index cells (row * spot_side () + column)
:= bit_of (on : bool) (bit : i32) : u32 = ? on ?> 1u32 <<< bit |: 0u32
:~ ^ row_bits (cells : array bool) (row : i32) (first : i32) (bit : i32) (acc : u32) : u32 =
? bit >= row_word_bits () ?> acc
|: row_bits cells row first (bit + 1) (acc ||| bit_of (bit_set cells row (first + bit)) bit)
:= row_word (cells : array bool) (row : i32) (word : i32) : u32 = row_bits cells row (word * row_word_bits ()) 0 0u32
:= word_mask (word : i32) : u32 =
:= valid = spot_side () - word * row_word_bits ()
? valid >= row_word_bits () ?> 4294967295u32 |: (1u32 <<< valid) - 1u32
:= word_literal (words : array u32) (row : i32) (word : i32) : string =
sm'::obj_to_string (index words (row * row_word_count () + word)) ++ "u32"
:= if_then (condition : string) (yes : string) (no : string) : string =
"if " ++ condition ++ " then " ++ yes ++ " else " ++ no
:= word_test (word : i32) : string = "word = " ++ sm'::obj_to_string word
:= outside_value (outside_blocked : bool) (word : i32) : string =
sm'::obj_to_string (? outside_blocked ?> word_mask word |: 0u32) ++ "u32"
:~ ^ outside_choice (outside_blocked : bool) (word : i32) : string =
:= value = outside_value outside_blocked word
? word = row_word_count () - 1
?> value
|: if_then (word_test word) value (outside_choice outside_blocked (word + 1))
:~ ^ words_from (cells : array bool) (words : array u32) (cell : i32) : () =
:= count = row_word_count ()
? cell < length words ?>
set words cell (row_word cells (cell / count) (cell % count))
words_from cells words (cell + 1)
:= row_words (cells : array bool) : array u32 =
:= words : array u32 = filled (spot_side () * row_word_count ()) 0u32
words_from cells words 0
words
:= table_fan () : i32 = 4
:== table_item = i32 * string
:= items_by (count : i32) (item : i32 -> table_item) : array table_item =
:= items : array table_item = filled count (0, "")
:~ ^ fill (i : i32) : () =
? i < count ?>
set items i (item i)
fill (i + 1)
fill 0
items
:= item_first (items : array table_item) (i : i32) : i32 =
:= first, _ = index items i
first
:= item_text (items : array table_item) (i : i32) : string =
:= _, text = index items i
text
:= row_test (items : array table_item) (i : i32) : string = "row <= " ++ sm'::obj_to_string (item_first items i - 1)
:~ ^ item_chain (items : array table_item) (lo : i32) (hi : i32) : string =
? lo = hi ?> item_text items lo
|:
:= mid = (lo + hi) / 2
if_then (row_test items (mid + 1)) (item_chain items lo mid) (item_chain items (mid + 1) hi)
:= whole_chain (items : array table_item) : string = item_chain items 0 (length items - 1)
:= row_items (words : array u32) (word : i32) : array table_item =
items_by (spot_side ()) \ row => row, word_literal words row word
:= group_items (items : array table_item) (g : i32) : array table_item =
:= lo = g * table_fan ()
:= count = ? length items - lo < table_fan () ?> length items - lo |: table_fan ()
items_by count \ i => index items (lo + i)
:= row_function (name : string) (body : string) : () =
console::write_line ("let " ++ name ++ " (row : i32) : u32 =")
console::write_line (" " ++ body)
:= group_item (prefix : string) (items : array table_item) (g : i32) : table_item =
:= group, name = group_items items g, prefix ++ "_" ++ sm'::obj_to_string g
row_function name (whole_chain group)
item_first group 0, name ++ " row"
:= group_count (items : array table_item) : i32 = (length items + table_fan () - 1) / table_fan ()
:= next_items (base : string) (level : i32) (items : array table_item) : array table_item =
items_by (group_count items) (group_item (base ++ "_" ++ sm'::obj_to_string level) items)
:~ ^ emit_level (base : string) (level : i32) (items : array table_item) : () =
? length items <= table_fan () ?> row_function base (whole_chain items)
|: emit_level base (level + 1) (next_items base level items)
:= word_name (table : string) (word : i32) : string = table ++ "_" ++ sm'::obj_to_string word
:~ ^ word_choice (table : string) (word : i32) : string =
:= part = word_name table word ++ " row"
? word = row_word_count () - 1 ?> part |: if_then (word_test word) part (word_choice table (word + 1))
:= emit_words (name : string) (words : array u32) : () =
:~ ^ each_word (word : i32) : () =
? word < row_word_count () ?>
emit_level (word_name name word) 0 (row_items words word)
each_word (word + 1)
each_word 0
:= emit_outside (name : string) (outside_blocked : bool) : () =
console::write_line ("let " ++ name ++ "_outside (word : i32) : u32 =")
console::write_line (" " ++ outside_choice outside_blocked 0)
:= bits_root (name : string) : string =
:= guard = "row < 0 || row > " ++ sm'::obj_to_string (spot_side () - 1)
" " ++ if_then guard (name ++ "_outside word") (word_choice name 0)
:= emit (name : string) (cells : array bool) (blocked : bool) : () =
emit_words name (row_words cells)
emit_outside name blocked
console::write_line ("let " ++ name ++ " (word : i32) (row : i32) : u32 =")
console::write_line (bits_root name)
:= literal (n : i32) : string = ? n < 0 ?> "(0 - " ++ sm'::obj_to_string (0 - n) ++ ")" |: sm'::obj_to_string n
:~ ^ last_of (cells : array bool) (row : i32) (column : i32) : i32 =
? bit_set cells row (column + 1) ?> last_of cells row (column + 1) |: column
:= span_text (first : i32) (last : i32) : string =
:= radius = spot_radius ()
? last = first
?> "dx = " ++ literal (first - radius)
|: "(dx >= " ++ literal (first - radius) ++ " && dx <= " ++ literal (last - radius) ++ ")"
:= joined (text : string) (part : string) (separator : string) : string =
? text = "" ?> part |: text ++ separator ++ part
:= span_step (cells : array bool) (row : i32) (column : i32) (text : string) : i32 * string =
? bit_set cells row column = !- ?> (column + 1, text)
|:
:= last = last_of cells row column
last + 1, joined text (span_text column last) " || "
:~ ^ spans_from (cells : array bool) (row : i32) (column : i32) (text : string) : string =
? column >= spot_side () ?> text
|:
:= column, text = span_step cells row column text
spans_from cells row column text
:= row_spans (cells : array bool) (row : i32) : string = spans_from cells row 0 ""
:= dy_test (row : i32) : string = "dy = " ++ literal (row - spot_radius ())
:= zone_budget () : i32 = 150
:~ ^ span_rows_from (cells : array bool) (row : i32) (count : i32) : i32 =
? row >= spot_side () ?> count
|: span_rows_from cells (row + 1) (? row_spans cells row = "" ?> count |: count + 1)
:~ ^ span_row_from (cells : array bool) (row : i32) (n : i32) : i32 =
? row_spans cells row = "" ?> span_row_from cells (row + 1) n
|? n = 0 ?> row
|: span_row_from cells (row + 1) (n - 1)
:= zone_clause (cells : array bool) (n : i32) : table_item =
:= row = span_row_from cells 0 n
row, row_spans cells row
:= zone_clauses (cells : array bool) : array table_item = items_by (span_rows_from cells 0 0) (zone_clause cells)
:= zone_group (rows : array table_item) (lo : i32) (hi : i32) (rest : string) : string =
:~ ^ build (i : i32) (text : string) : string =
? i < lo ?> text |: build (i - 1) (if_then (dy_test (item_first rows i)) (item_text rows i) text)
build hi rest
:= zone_part (name : string) (k : i32) : string = ? k = 0 ?> name |: name ++ "_" ++ sm'::obj_to_string k
:= zone_function (label : string) (body : string) : () =
console::write_line ("let " ++ label ++ " (dx : i32) (dy : i32) : bool =")
console::write_line (" " ++ body)
:= span_function (label : string) (body : string) : () =
console::write_line ("let " ++ label ++ " (dx : i32) : bool =")
console::write_line (" " ++ body)
:= hoisted_span (name : string) (row : i32) (spans : string) : string =
:= helper = name ++ "_dy" ++ sm'::obj_to_string row
span_function helper spans
helper ++ " dx"
:= hoist (name : string) (clauses : array table_item) (i : i32) : table_item =
:= row, spans = item_first clauses i, item_text clauses i
row, (? (sm'::length spans : i32) <= 100 ?> spans |: hoisted_span name row spans)
:= clause_weight (clauses : array table_item) (i : i32) : i32 = (sm'::length (item_text clauses i) : i32) + 20
:~ ^ zone_end (clauses : array table_item) (hi : i32) (used : i32) : i32 =
:= next = hi + 1
? next >= length clauses || used + clause_weight clauses next > zone_budget () ?> hi
|: zone_end clauses next (used + clause_weight clauses next)
:= zone_hi (clauses : array table_item) (lo : i32) : i32 = zone_end clauses lo (clause_weight clauses lo)
:= zone_rest (name : string) (clauses : array table_item) (hi : i32) (k : i32) : string =
? hi + 1 >= length clauses ?> "false" |: zone_part name (k + 1) ++ " dx dy"
:= emit_zone_group (name : string) (clauses : array table_item) (lo : i32) (hi : i32) (k : i32) : () =
zone_function (zone_part name k) (zone_group clauses lo hi (zone_rest name clauses hi k))
:~ ^ emit_zone_from (name : string) (clauses : array table_item) (lo : i32) (k : i32) : () =
? lo < length clauses ?>
:= hi = zone_hi clauses lo
emit_zone_from name clauses (hi + 1) (k + 1)
emit_zone_group name clauses lo hi k
:= emit_spans (name : string) (cells : array bool) : () =
:= found = zone_clauses cells
:= clauses = items_by (length found) (hoist name found)
? length clauses = 0 ?> zone_function name "false" |: emit_zone_from name clauses 0 0
:= signed_label (n : i32) : string =
:= digits = ? n < 0 ?> "-" ++ sm'::obj_to_string (0 - n) |: "+" ++ sm'::obj_to_string n
:~ ^ pad (text : string) : string = ? (sm'::length text : i32) >= 4 ?> text |: pad (" " ++ text)
pad digits
:= spot_xy () : string = sm'::obj_to_string (spot_x ()) ++ "," ++ sm'::obj_to_string (spot_y ())
:= spot_text () : string = spot_xy () ++ "," ++ sm'::obj_to_string (spot_z ())
:= radius_text () : string = " radius " ++ sm'::obj_to_string (spot_radius ())
:~ ^ marks_from (cells : array bool) (row : i32) (column : i32) (text : string) : string =
? column >= spot_side () ?> text
|: marks_from cells row (column + 1) (text ++ (? bit_set cells row column ?> "." |: "#"))
:~ ^ dump_rows (cells : array bool) (row : i32) : () =
? row < spot_side () ?>
console::write_line (signed_label (row - spot_radius ()) ++ " " ++ marks_from cells row 0 "")
dump_rows cells (row + 1)
:= walk_dump (cells : array bool) : () =
console::write_line ("walkability around " ++ spot_text () ++ radius_text () ++ " (# blocked, . walkable)")
dump_rows cells 0
:= listed_line (column : i32) (row : i32) (label : string) : string =
:= x, y = spot_x () - spot_radius () + column, spot_y () - spot_radius () + row
sm'::obj_to_string x ++ "," ++ sm'::obj_to_string y ++ " " ++ label
:~ ^ listed_rows (cells : array bool) (label : string) (column : i32) (row : i32) : () =
? row < spot_side () ?>
? bit_set cells row column ?> console::write_line (listed_line column row label)
listed_rows cells label column (row + 1)
:~ ^ listed_columns (cells : array bool) (label : string) (column : i32) : () =
? column < spot_side () ?>
listed_rows cells label column 0
listed_columns cells label (column + 1)
:= listed (cells : array bool) (label : string) : () = listed_columns cells label 0
:~ ^ exit_count (exits : array bool) (identity : i32) (total : i32) : i32 =
? identity >= item_id_limit () ?> total
|: exit_count exits (identity + 1) (? index exits identity ?> total + 1 |: total)
:= listing_place () : string =
:= floor, radius = sm'::obj_to_string (spot_z ()), sm'::obj_to_string (spot_radius ())
"floor-change tiles on floor " ++ floor ++ " within radius " ++ radius ++ " of " ++ spot_xy ()
:= listing_header (exits : array bool) : string =
listing_place () ++ " (from " ++ sm'::obj_to_string (exit_count exits 0 0) ++ " floorchange item ids)"
:~ ^ any_from (cells : array bool) (i : i32) : bool =
? i >= length cells ?> !- |? index cells i ?> !+ |: any_from cells (i + 1)
:= any (cells : array bool) : bool = any_from cells 0
:= passage_listing (g : mark_cells) : () =
listed g::floor_change "floorchange"
listed g::teleport "teleport"
? any g::floor_change = !- || any g::climbable = !- ?> console::write_line ""
:= zone_listing (g : mark_cells) : () =
listed g::climbable "height3"
? any g::climbable || any g::protection || any g::house ?> console::write_line ""
listed g::protection "protection-zone"
listed g::house "house"
:= floor_change_listing (g : mark_cells) (exits : array bool) : () =
console::write_line (listing_header exits)
passage_listing g
zone_listing g
:= read_input (variable : string) : bytes =
am'::from_vec (file_system::read_all_bytes (env::get_environment_variable variable))
:~ ^ merge_from (marks : array bool) (overrides : array bool) (identity : i32) : () =
? identity < item_id_limit () ?>
? index overrides identity ?> set marks identity !+
merge_from marks overrides (identity + 1)
:= sight_merged (kinds : item_kinds) (items : bytes) : () =
merge_from kinds::sight_blocking (ids_with items "key=\"blockProjectile\" value=\"1\"") 0
:= item_marks (kinds : item_kinds) (items : bytes) : array bool * array bool =
:= exits, teleports = ids_with items "key=\"floorchange\"", ids_with items "value=\"teleport\""
sight_merged kinds items
exits, teleports
:= emit_all (g : grid) : () =
emit "arena_spot_bits" g::walk::blocked !+
emit "arena_road_bits" g::walk::road !-
emit "arena_sight_bits" g::walk::sight_blocked !-
emit_spans "arena_protection_zone" g::marks::protection
walk_dump g::walk::walkable
:= report (g : grid) (exits : array bool) : () =
emit_all g
floor_change_listing g::marks exits
varint_reads_little_endian_base_128 (test)
test varint_reads_little_endian_base_128: passed
///- --test --symbol
///> rust
///> c
(varint ;[150u8; 1u8] 0, varint ;[5u8; 172u8; 2u8] 1, varint ;[5u8] 0)
|> _assert_eq ((150u64, 2i32), (300u64, 3i32), (5u64, 1i32))
.rs (rust)
__assert_eq { expected = ((150, 2), (300, 3), 5, 1) }
.c (c)
__assert_eq { expected = ((150, 2), (300, 3), 5, 1) }
0
literal_and_signed_label_render_negative_numbers (test)
test literal_and_signed_label_render_negative_numbers: passed
///- --test --symbol
///> rust
///> c
(literal (0 - 5), literal 7, signed_label 5, signed_label (0 - 12), signed_label 0, signed_label 1234)
|> _assert_eq ("(0 - 5)", "7", " +5", " -12", " +0", "+1234")
.rs (rust)
__assert_eq { expected = ((0 - 5), 7, +5, -12, +0, +1234) }
.c (c)
__assert_eq { expected = ((0 - 5), 7, +5, -12, +0, +1234) }
0
word_mask_covers_only_tiles_inside_the_spot (test)
test word_mask_covers_only_tiles_inside_the_spot: passed
///- --test --symbol
///> rust
///> c
(row_word_count (), word_mask 0, word_mask 1, word_mask 2)
|> _assert_eq (3i32, 4294967295u32, 4294967295u32, 134217727u32)
.rs (rust)
__assert_eq { expected = (3, 4294967295, 4294967295, 134217727) }
.c (c)
__assert_eq { expected = (3, 4294967295, 4294967295, 134217727) }
0
row_spans_merge_runs_into_ranges (test)
test row_spans_merge_runs_into_ranges: passed
///- --test --symbol
///> rust
///> c
:= cells : array bool = filled (spot_side () * spot_side ()) !-
set cells 45 !+
set cells 47 !+
set cells 48 !+
row_spans cells 0 |> _assert_eq "dx = 0 || (dx >= 2 && dx <= 3)"
.rs (rust)
__assert_eq { expected = dx = 0 || (dx >= 2 && dx <= 3) }
.c (c)
__assert_eq { expected = dx = 0 || (dx >= 2 && dx <= 3) }
0
row_spans_of_an_empty_row_is_empty (test)
test row_spans_of_an_empty_row_is_empty: passed
///- --test --symbol
///> rust
///> c
row_spans (filled (spot_side () * spot_side ()) !-) 1 |> _assert_eq ""
.rs (rust)
__assert_eq { expected = }
.c (c)
__assert_eq { expected = }
0
///> _
:= main () =
:= kinds, items = item_kinds_of (read_input "TIBIA_MAP_APPEARANCES"), read_input "TIBIA_MAP_ITEMS"
:= exits, teleports = item_marks kinds items
:= grid = walk_tiles (read_input "TIBIA_MAP_OTBM") kinds exits teleports
report grid exits