If it works it works, the fugliest code ever hehe
This commit is contained in:
@@ -316,6 +316,372 @@ fn solve_first(instructions: &[Instruction], output_wire: &str) -> (u16, HashMap
|
||||
}
|
||||
}
|
||||
|
||||
fn solve_second(
|
||||
instructions: &[Instruction],
|
||||
output_wire: &str,
|
||||
override_wire: &str,
|
||||
) -> (u16, HashMap<String, Node>) {
|
||||
// Because the graph is centered around the edges instead of nodes, we have to go through a lot of gymnastics to build it
|
||||
let mut signals = HashMap::<String, Node>::new();
|
||||
|
||||
// For OneAnd operator
|
||||
signals.insert("one".to_string(), (Port::Noop, vec![], Some(1)));
|
||||
|
||||
for instruction in instructions {
|
||||
match instruction {
|
||||
Instruction::Assign(value, wire) => {
|
||||
signals.insert(wire.to_owned(), (Port::Noop, vec![], Some(*value)));
|
||||
}
|
||||
Instruction::Connect(source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::Noop, vec![source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
// We could already preprocess a bit by calculating the result if we know the input, but that might make it overly complicated a this point
|
||||
// Instead, we do the actual traversal and calculations later
|
||||
Instruction::Not(source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::Not, vec![source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
Instruction::And(source_1, source_2, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(
|
||||
Port::And,
|
||||
vec![source_1.to_owned(), source_2.to_owned()],
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
Instruction::OneAnd(source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::And, vec!["one".to_string(), source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
Instruction::Or(source_1, source_2, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(
|
||||
Port::Or,
|
||||
vec![source_1.to_owned(), source_2.to_owned()],
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
Instruction::Lshift(shift, source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::Lshift(*shift), vec![source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
Instruction::Rshift(shift, source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::Rshift(*shift), vec![source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let mut edges_to_calc = vec![output_wire.to_string()];
|
||||
|
||||
while !edges_to_calc.is_empty() {
|
||||
let edge_to_calc = edges_to_calc.pop().unwrap();
|
||||
|
||||
if let Some(signal) = signals.get(&edge_to_calc) {
|
||||
match signal {
|
||||
(port, incoming_wires, None) => {
|
||||
let incoming_signals: Vec<Option<u16>> = incoming_wires
|
||||
.iter()
|
||||
.map(|x| match signals.get(x).unwrap() {
|
||||
(_, _, None) => None,
|
||||
(_, _, s) => s.to_owned(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
if incoming_signals.iter().any(|s| s.is_none()) {
|
||||
edges_to_calc.push(edge_to_calc);
|
||||
|
||||
for (s, w) in zip(incoming_signals, incoming_wires) {
|
||||
if s.is_none() {
|
||||
edges_to_calc.push(w.to_owned());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match port {
|
||||
Port::Noop => {
|
||||
assert_eq!(incoming_signals.len(), 1);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(*port, incoming_wires.to_owned(), incoming_signals[0]),
|
||||
);
|
||||
}
|
||||
Port::Not => {
|
||||
assert_eq!(incoming_signals.len(), 1);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(!incoming_signals[0].unwrap()),
|
||||
),
|
||||
);
|
||||
}
|
||||
Port::And => {
|
||||
assert_eq!(incoming_signals.len(), 2);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(
|
||||
incoming_signals[0].unwrap()
|
||||
& incoming_signals[1].unwrap(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Port::Or => {
|
||||
assert_eq!(incoming_signals.len(), 2);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(
|
||||
incoming_signals[0].unwrap()
|
||||
| incoming_signals[1].unwrap(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Port::Lshift(shift) => {
|
||||
assert_eq!(incoming_signals.len(), 1);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(incoming_signals[0].unwrap() << shift),
|
||||
),
|
||||
);
|
||||
}
|
||||
Port::Rshift(shift) => {
|
||||
assert_eq!(incoming_signals.len(), 1);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(incoming_signals[0].unwrap() >> shift),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(_, _, Some(_)) => { /* do nothing */ }
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
let result = signals.get(&output_wire.to_string()).unwrap().to_owned();
|
||||
|
||||
for instruction in instructions {
|
||||
match instruction {
|
||||
Instruction::Assign(value, wire) => {
|
||||
signals.insert(wire.to_owned(), (Port::Noop, vec![], Some(*value)));
|
||||
}
|
||||
Instruction::Connect(source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::Noop, vec![source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
// We could already preprocess a bit by calculating the result if we know the input, but that might make it overly complicated a this point
|
||||
// Instead, we do the actual traversal and calculations later
|
||||
Instruction::Not(source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::Not, vec![source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
Instruction::And(source_1, source_2, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(
|
||||
Port::And,
|
||||
vec![source_1.to_owned(), source_2.to_owned()],
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
Instruction::OneAnd(source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::And, vec!["one".to_string(), source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
Instruction::Or(source_1, source_2, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(
|
||||
Port::Or,
|
||||
vec![source_1.to_owned(), source_2.to_owned()],
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
Instruction::Lshift(shift, source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::Lshift(*shift), vec![source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
Instruction::Rshift(shift, source, target) => {
|
||||
signals.insert(
|
||||
target.to_owned(),
|
||||
(Port::Rshift(*shift), vec![source.to_owned()], None),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
signals.insert(
|
||||
override_wire.to_string(),
|
||||
(Port::Noop, vec![], Some(result.2.unwrap())),
|
||||
);
|
||||
|
||||
let mut edges_to_calc = vec![output_wire.to_string()];
|
||||
|
||||
while !edges_to_calc.is_empty() {
|
||||
let edge_to_calc = edges_to_calc.pop().unwrap();
|
||||
|
||||
if let Some(signal) = signals.get(&edge_to_calc) {
|
||||
match signal {
|
||||
(port, incoming_wires, None) => {
|
||||
let incoming_signals: Vec<Option<u16>> = incoming_wires
|
||||
.iter()
|
||||
.map(|x| match signals.get(x).unwrap() {
|
||||
(_, _, None) => None,
|
||||
(_, _, s) => s.to_owned(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
if incoming_signals.iter().any(|s| s.is_none()) {
|
||||
edges_to_calc.push(edge_to_calc);
|
||||
|
||||
for (s, w) in zip(incoming_signals, incoming_wires) {
|
||||
if s.is_none() {
|
||||
edges_to_calc.push(w.to_owned());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match port {
|
||||
Port::Noop => {
|
||||
assert_eq!(incoming_signals.len(), 1);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(*port, incoming_wires.to_owned(), incoming_signals[0]),
|
||||
);
|
||||
}
|
||||
Port::Not => {
|
||||
assert_eq!(incoming_signals.len(), 1);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(!incoming_signals[0].unwrap()),
|
||||
),
|
||||
);
|
||||
}
|
||||
Port::And => {
|
||||
assert_eq!(incoming_signals.len(), 2);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(
|
||||
incoming_signals[0].unwrap()
|
||||
& incoming_signals[1].unwrap(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Port::Or => {
|
||||
assert_eq!(incoming_signals.len(), 2);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(
|
||||
incoming_signals[0].unwrap()
|
||||
| incoming_signals[1].unwrap(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Port::Lshift(shift) => {
|
||||
assert_eq!(incoming_signals.len(), 1);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(incoming_signals[0].unwrap() << shift),
|
||||
),
|
||||
);
|
||||
}
|
||||
Port::Rshift(shift) => {
|
||||
assert_eq!(incoming_signals.len(), 1);
|
||||
|
||||
signals.insert(
|
||||
edge_to_calc.to_owned(),
|
||||
(
|
||||
*port,
|
||||
incoming_wires.to_owned(),
|
||||
Some(incoming_signals[0].unwrap() >> shift),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(_, _, Some(_)) => { /* do nothing */ }
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
let result = signals.get(&output_wire.to_string()).unwrap().to_owned();
|
||||
|
||||
match result {
|
||||
(_, _, None) => (0, HashMap::new()),
|
||||
(_, _, Some(s)) => (s, signals.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, this is Patrick!");
|
||||
|
||||
@@ -326,4 +692,11 @@ fn main() {
|
||||
let (first_result, _) = solve_first(&instructions[..], "a");
|
||||
|
||||
println!("The provided signal at wire 'a' is {}", first_result);
|
||||
|
||||
let (second_result, _) = solve_second(&instructions[..], "a", "b");
|
||||
|
||||
println!(
|
||||
"The signal at 'a' is {} when overriding 'b' with it and running it again",
|
||||
{ second_result }
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user