feat: implement semaphores
This commit is contained in:
parent
06e8e5d293
commit
58ba166392
|
@ -96,46 +96,28 @@ pub fn op_define(instruction: &u16, tree: &mut Tree, rules: &Vec<Rule>, rules_to
|
|||
tree.push_by_stack_code(stack_code, (rules.len() + rules_to_define.len() - 2) as u16)
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn op_wait(instruction: &u16, tree: &mut Tree, land: &mut Land, instruction_pointer: &u16) {
|
||||
let (_, relative_x, relative_y) = extract_forestry_format(instruction);
|
||||
let (abs_x, abs_y) = land.derelativize(tree, relative_x, relative_y);
|
||||
let (abs_x, abs_y) = land.derelativize(tree.position, relative_x, relative_y);
|
||||
|
||||
// Decrement the counting semaphore
|
||||
let current_value = land.map.get(&(abs_x, abs_y)).unwrap();
|
||||
land.sow(abs_x, abs_y, current_value - 1);
|
||||
let semaphore = land.get_semaphore(&(abs_x, abs_y));
|
||||
let semaphore_value = semaphore.wait(tree.id);
|
||||
|
||||
if current_value - 1 < 0 {
|
||||
if semaphore_value < 0 {
|
||||
tree.asleep = true;
|
||||
tree.resume_from = instruction_pointer + 1;
|
||||
if land.semaphores.contains_key(&(abs_x, abs_y)) {
|
||||
land.semaphores.get(&(abs_x, abs_y)).unwrap().push_back(tree.id);
|
||||
} else {
|
||||
// We've got to create if it doesn't already exist
|
||||
let semaphores_for_cell: VecDeque<u16> = VecDeque::from([tree.id]);
|
||||
land.semaphores.insert((abs_x, abs_y), semaphores_for_cell);
|
||||
}
|
||||
tree.resume_from = *instruction_pointer;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn op_signal(instruction: &u16, tree: &mut Tree, trees: &mut HashMap<u16, Tree>, land: &mut Land) {
|
||||
pub fn op_signal(instruction: &u16, tree: &mut Tree, trees_to_wake: &mut Vec<u16>, land: &mut Land) {
|
||||
let (_, relative_x, relative_y) = extract_forestry_format(instruction);
|
||||
let (abs_x, abs_y) = land.derelativize(tree, relative_x, relative_y);
|
||||
let (abs_x, abs_y) = land.derelativize(tree.position, relative_x, relative_y);
|
||||
|
||||
// Increment the counting semaphore
|
||||
let current_value = land.map.get(&(abs_x, abs_y)).unwrap();
|
||||
land.sow(abs_x, abs_y, current_value + 1);
|
||||
let semaphore = land.get_semaphore(&(abs_x, abs_y));
|
||||
|
||||
// Wake the oldest sleeping tree if needed
|
||||
if *current_value >= 0 {
|
||||
// If this call returns None, there's a logic error somewhere, either in the
|
||||
// VM, or someone called signal on an uninitialized semaphore
|
||||
let semaphores_for_cell = land.semaphores.get(&(abs_x, abs_y)).unwrap();
|
||||
let tree_id_to_wake = semaphores_for_cell.pop_front().unwrap();
|
||||
|
||||
let tree_to_wake = trees.get(&tree_id_to_wake).unwrap();
|
||||
tree_to_wake.asleep = false;
|
||||
tree.resume_from = 0;
|
||||
if let Some(tree_id) = semaphore.signal() {
|
||||
trees_to_wake.push(tree_id);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -123,6 +123,7 @@ fn main() -> io::Result<()> {
|
|||
for _ in 0..generation_count {
|
||||
let mut trees_to_plant: Vec<state::Tree> = Vec::new();
|
||||
let mut rules_to_define: Vec<state::Rule> = Vec::new();
|
||||
let mut trees_to_wake: Vec<u16> = Vec::new();
|
||||
|
||||
// We shouldn't be able to compost the same tree twice in a generation,
|
||||
// so we use a BTreeSet here. BTreeSets have the advantage of not
|
||||
|
@ -179,10 +180,8 @@ fn main() -> io::Result<()> {
|
|||
break;
|
||||
},
|
||||
27 => forestry::op_define(word, tree, &rules, &mut rules_to_define),
|
||||
/*
|
||||
28 => forestry::op_wait(word, tree, &mut land, &instruction_pointer),
|
||||
29 => forestry::op_signal(word, tree, &mut trees, &mut land),
|
||||
*/
|
||||
29 => forestry::op_signal(word, tree, &mut trees_to_wake, &mut land),
|
||||
_ => panic!("Unknown opcode: {}", opcode)
|
||||
};
|
||||
|
||||
|
@ -190,8 +189,8 @@ fn main() -> io::Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
for tree_index in trees_to_compost_by_index.iter() {
|
||||
let tree_id = scheduled_trees.swap_remove(*tree_index as usize);
|
||||
while let Some(tree_index) = trees_to_compost_by_index.pop_first() {
|
||||
let tree_id = scheduled_trees.swap_remove(tree_index as usize);
|
||||
let (parent_id, recovered_stack_size) = {
|
||||
let tree = trees.remove(&tree_id).unwrap();
|
||||
(tree.parent_id, tree.stack_size)
|
||||
|
@ -200,6 +199,12 @@ fn main() -> io::Result<()> {
|
|||
parent.stack_size += recovered_stack_size;
|
||||
}
|
||||
|
||||
while let Some(tree_id) = trees_to_wake.pop() {
|
||||
let tree = trees.get_mut(&tree_id).unwrap();
|
||||
tree.asleep = true;
|
||||
tree.resume_from = 0;
|
||||
}
|
||||
|
||||
for _ in 0..trees_to_plant.len() {
|
||||
let tree_to_plant = trees_to_plant.pop().unwrap();
|
||||
trees.insert(tree_to_plant.id, tree_to_plant);
|
||||
|
|
51
src/state.rs
51
src/state.rs
|
@ -1,13 +1,49 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub struct Semaphore {
|
||||
queue: VecDeque<u16>, // Positions -> tree ID
|
||||
value: i16, // If below zero, the tree gets enqueued
|
||||
}
|
||||
|
||||
impl Semaphore {
|
||||
/**
|
||||
* Returns the new value of the semaphore
|
||||
*/
|
||||
pub fn wait(&mut self, rule_id: u16) -> i16 {
|
||||
self.value -= 1;
|
||||
|
||||
if self.value < 0 {
|
||||
self.queue.push_back(rule_id);
|
||||
}
|
||||
|
||||
return self.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the tree that's been polled
|
||||
*/
|
||||
pub fn signal(&mut self) -> Option<u16> {
|
||||
self.value += 1;
|
||||
|
||||
return if self.value >= 0 {
|
||||
// This should never fail because self.value should correspond to
|
||||
// the number of enqueued trees, but it should fail loudly if that
|
||||
// were to happen
|
||||
Some(self.queue.pop_front().unwrap())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Land {
|
||||
pub map: HashMap<(u16, u16), u16>,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
|
||||
// Maps positions to a queue of rule IDs
|
||||
pub semaphores: HashMap<(u16, u16), VecDeque<u16>>,
|
||||
pub semaphores: HashMap<(u16, u16), Semaphore>,
|
||||
}
|
||||
|
||||
impl Land {
|
||||
|
@ -34,6 +70,19 @@ impl Land {
|
|||
|
||||
return (absolute_x, absolute_y);
|
||||
}
|
||||
|
||||
pub fn get_semaphore(&mut self, position: &(u16, u16)) -> &mut Semaphore {
|
||||
if !self.semaphores.contains_key(position) {
|
||||
let new_semaphore = Semaphore {
|
||||
value: 0,
|
||||
queue: VecDeque::new(),
|
||||
};
|
||||
|
||||
self.semaphores.insert(*position, new_semaphore);
|
||||
}
|
||||
|
||||
return self.semaphores.get_mut(position).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub type Rule = VecDeque<u16>;
|
||||
|
|
Loading…
Reference in New Issue