diff --git a/src/bin/ponderosa-cpu.rs b/src/bin/ponderosa-cpu.rs index 643d838..3c178fc 100644 --- a/src/bin/ponderosa-cpu.rs +++ b/src/bin/ponderosa-cpu.rs @@ -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, 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(); } } diff --git a/src/forestry.rs b/src/forestry.rs index e4a34ac..7d6efd8 100644 --- a/src/forestry.rs +++ b/src/forestry.rs @@ -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; diff --git a/src/state.rs b/src/state.rs index d6d7651..a5ce2ba 100644 --- a/src/state.rs +++ b/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, // 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); } }