fix: correct overflow and buffer issues preventing use of negative coordinates
This commit is contained in:
parent
ba5a1b6256
commit
ff6e95a33b
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
31
src/state.rs
31
src/state.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue