fix: correct overflow and buffer issues preventing use of negative coordinates

This commit is contained in:
Nat 2024-12-13 10:50:40 -08:00
parent ba5a1b6256
commit ff6e95a33b
3 changed files with 33 additions and 42 deletions

View File

@ -2,7 +2,7 @@ use std::io;
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::{VecDeque, HashMap, BTreeSet};
use std::collections::{VecDeque, HashMap, BTreeSet, BTreeMap};
use ponderosa::{math, stack, state, control, forestry};
@ -99,7 +99,7 @@ fn parse_rom(path: &String) -> io::Result<(state::Land, Vec<state::Rule>, HashMa
resume_from: 0,
stack_size: original_stack_size,
position: (seed_cell_x % land.width, seed_cell_y % land.height),
span: [[0u16; 8]; 8],
buffer: BTreeMap::new(),
});
Ok((land, rules, trees))
@ -134,13 +134,6 @@ fn main() -> io::Result<()> {
continue;
}
// Reconcile the tree's span with the current state of the land
for x in 0..8 {
for y in 0..8 {
tree.span[x][y] = land.get(&(x.try_into().unwrap(), y.try_into().unwrap()));
}
}
let instructions = &rules[tree.rule_id as usize];
// tree.resume_from will be 0, unless it's awoken after having to
@ -173,8 +166,8 @@ fn main() -> io::Result<()> {
18 => stack::op_clear(word, &mut tree),
19 => control::op_skip(word, &mut instruction_pointer),
20 => control::op_skim(word, &mut tree, &mut instruction_pointer),
21 => forestry::op_sow(word, tree),
22 => forestry::op_reap(word, tree),
21 => forestry::op_sow(word, tree, &land),
22 => forestry::op_reap(word, tree, &land),
23 => forestry::op_plant(word, tree, &mut next_tree_id, &mut trees_to_plant, &mut land),
24 => forestry::op_replant(word, tree, &land),
25 => break, // yeild
@ -191,16 +184,16 @@ fn main() -> io::Result<()> {
instruction_pointer += 1;
}
// Update the land with the new state of every tree.
for tree_index in 0..scheduled_trees.len() {
let tree_id = &scheduled_trees[tree_index];
let tree = trees.get(tree_id).unwrap();
for x in 0..8 {
for y in 0..8 {
land.sow(&(x, y), tree.span[x as usize][y as usize]);
}
let tree = trees.get_mut(tree_id).unwrap();
for coordinates in tree.buffer.keys() {
land.sow(&coordinates, *tree.buffer.get(&coordinates).unwrap());
}
tree.buffer.clear();
}
}

View File

@ -1,4 +1,4 @@
use std::collections::VecDeque;
use std::collections::{VecDeque, BTreeMap};
use crate::state::{Land, Rule, Tree};
fn extract_forestry_format(instruction: &u16) -> (u16, i16, i16) {
@ -25,17 +25,22 @@ fn extract_forestry_format(instruction: &u16) -> (u16, i16, i16) {
);
}
pub fn op_sow(instruction: &u16, tree: &mut Tree) {
pub fn op_sow(instruction: &u16, tree: &mut Tree, land: &Land) {
let (stack_code, relative_x, relative_y) = extract_forestry_format(instruction);
let value = tree.pull_by_stack_code(stack_code);
tree.sow(relative_x, relative_y, value);
tree.sow(land, relative_x, relative_y, value);
}
pub fn op_reap(instruction: &u16, tree: &mut Tree) {
pub fn op_reap(instruction: &u16, tree: &mut Tree, land: &Land) {
let (stack_code, relative_x, relative_y) = extract_forestry_format(instruction);
let value = tree.reap(relative_x, relative_y);
let coordinates = land.derelativize(tree.position, relative_x, relative_y);
if !tree.buffer.contains_key(&coordinates) {
tree.buffer.insert(coordinates, land.get(&coordinates));
}
let value = tree.reap(land, relative_x, relative_y);
if stack_code == 0 {
tree.push_root(value);
@ -66,7 +71,7 @@ pub fn op_plant(instruction: &u16, tree: &mut Tree, next_tree_id: &mut u16, tree
asleep: false,
resume_from: 0,
position: land.derelativize(tree.position, relative_x, relative_y),
span: [[0u16; 8]; 8], // TODO: should take from current state of land!
buffer: BTreeMap::new(),
});
*next_tree_id += 1;

View File

@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::collections::VecDeque;
use std::collections::{BTreeMap, HashMap, VecDeque};
pub struct Semaphore {
queue: VecDeque<u16>, // Positions -> tree ID
@ -52,20 +51,16 @@ impl Land {
// because land itself cannot exceed integer limits in size and
// so that check's implicitly handled with the modulo operator.
// Underflows are a bit trickier to catch, though
let absolute_x = if relative_x < 0 && position.0 - relative_x.unsigned_abs() > position.0 {
let absolute_x = if relative_x < 0 && position.0.checked_sub(relative_x.unsigned_abs()).is_none() {
(self.width - (relative_x.unsigned_abs() - position.0)) % self.width
} else if relative_x < 0 {
(position.0 - relative_x.unsigned_abs()) % self.height
} else {
(position.0 + relative_x.unsigned_abs()) % self.height
(((position.0 as i16) + relative_x) % self.width as i16) as u16
};
let absolute_y = if relative_y < 0 && position.1 - relative_y.unsigned_abs() > position.1 {
let absolute_y = if relative_y < 0 && position.1.checked_sub(relative_y.unsigned_abs()).is_none() {
(self.height - (relative_y.unsigned_abs() - position.1)) % self.height
} else if relative_x < 0 {
(position.1 - relative_y.unsigned_abs()) % self.height
} else {
(position.1 + relative_y.unsigned_abs()) % self.height
(((position.1 as i16) + relative_y) % self.height as i16) as u16
};
return (absolute_x, absolute_y);
@ -109,7 +104,7 @@ pub struct Tree {
pub resume_from: u16,
pub stack_size: usize,
pub position: (u16, u16),
pub span: [[u16; 8]; 8],
pub buffer: BTreeMap<(u16, u16), u16>,
}
fn derelativize_span_coordinates(x: i16, y: i16) -> (usize, usize) {
@ -163,15 +158,13 @@ impl Tree {
}
}
pub fn sow(&mut self, relative_x: i16, relative_y: i16, value: u16) {
let (x, y) = derelativize_span_coordinates(relative_x, relative_y);
self.span[x][y] = value;
pub fn sow(&mut self, land: &Land, relative_x: i16, relative_y: i16, value: u16) {
let coordinates = land.derelativize(self.position, relative_x, relative_y);
self.buffer.insert(coordinates, value);
}
pub fn reap(&mut self, relative_x: i16, relative_y: i16) -> u16 {
let (x, y) = derelativize_span_coordinates(relative_x, relative_y);
let value = self.span[x][y];
self.sow(relative_x, relative_y, 0);
return value;
pub fn reap(&mut self, land: &Land, relative_x: i16, relative_y: i16) -> u16 {
let coordinates = land.derelativize(self.position, relative_x, relative_y);
return self.buffer.insert(coordinates, 0u16).unwrap_or(0u16);
}
}