work
This commit is contained in:
297
2024/go/day24/day24.go
Normal file
297
2024/go/day24/day24.go
Normal file
@@ -0,0 +1,297 @@
|
||||
package day24
|
||||
|
||||
import (
|
||||
"adventofcode2024/utils"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Network struct {
|
||||
gates []*Gate
|
||||
wires []*Wire
|
||||
}
|
||||
|
||||
type State int
|
||||
|
||||
const (
|
||||
NA State = iota - 1
|
||||
ZERO
|
||||
ONE
|
||||
)
|
||||
|
||||
type Wire struct {
|
||||
name string
|
||||
state State
|
||||
}
|
||||
|
||||
type Operation int
|
||||
|
||||
const (
|
||||
AND Operation = iota
|
||||
OR
|
||||
XOR
|
||||
)
|
||||
|
||||
type Gate struct {
|
||||
in [2]*Wire
|
||||
out *Wire
|
||||
op Operation
|
||||
}
|
||||
|
||||
func Part1(input string) int {
|
||||
|
||||
network := &Network{}
|
||||
network.wires = make([]*Wire, 0)
|
||||
|
||||
data := strings.Split(input, "\n\n")
|
||||
|
||||
network.AddWires(data[0])
|
||||
network.AddGates(data[1])
|
||||
for {
|
||||
if network.OutputKnown() {
|
||||
break
|
||||
}
|
||||
for _, gate := range network.gates {
|
||||
// fmt.Printf("%d: %v\n", i, gate)
|
||||
if gate.out.state == NA && gate.in[0].state != NA && gate.in[1].state != NA {
|
||||
switch gate.op {
|
||||
case AND:
|
||||
gate.out.state = And(gate.in[0].state, gate.in[1].state)
|
||||
case OR:
|
||||
gate.out.state = Or(gate.in[0].state, gate.in[1].state)
|
||||
case XOR:
|
||||
gate.out.state = Xor(gate.in[0].state, gate.in[1].state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return int(network.Output())
|
||||
}
|
||||
|
||||
func Part2(input string) int64 {
|
||||
|
||||
data := strings.Split(input, "\n\n")
|
||||
|
||||
inputs := strings.Split(data[0], "\n")
|
||||
num_inputs := len(inputs) / 2
|
||||
fmt.Println(num_inputs)
|
||||
var x_value int64
|
||||
var y_value int64
|
||||
var z_value int64
|
||||
y_value = 0
|
||||
for i := 0; i < num_inputs; i++ {
|
||||
// y_value = 1 << i
|
||||
x_value = 1 << i
|
||||
network := &Network{}
|
||||
network.wires = make([]*Wire, 0)
|
||||
network.AddWires2("x", num_inputs, x_value)
|
||||
network.AddWires2("y", num_inputs, y_value)
|
||||
network.AddGates(data[1])
|
||||
// for i, gate := range network.gates {
|
||||
// fmt.Printf("%d: %v\n", i, gate)
|
||||
// }
|
||||
network.SwapOutputs("z07", "rts")
|
||||
network.SwapOutputs("z12", "jpj")
|
||||
network.SwapOutputs("z26", "kgj")
|
||||
network.SwapOutputs("vvw", "chv")
|
||||
|
||||
// for i, gate := range network.gates {
|
||||
// fmt.Printf("%d: %v\n", i, gate)
|
||||
// }
|
||||
for {
|
||||
if network.OutputKnown() {
|
||||
break
|
||||
}
|
||||
for _, gate := range network.gates {
|
||||
// fmt.Printf("%d: %v\n", i, gate)
|
||||
if gate.out.state == NA && gate.in[0].state != NA && gate.in[1].state != NA {
|
||||
switch gate.op {
|
||||
case AND:
|
||||
gate.out.state = And(gate.in[0].state, gate.in[1].state)
|
||||
case OR:
|
||||
gate.out.state = Or(gate.in[0].state, gate.in[1].state)
|
||||
case XOR:
|
||||
gate.out.state = Xor(gate.in[0].state, gate.in[1].state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
z_value = network.Output()
|
||||
if x_value + y_value != z_value {
|
||||
fmt.Printf("(%d):\t x:%4d\t: y:%4d z:%4d\n", i, x_value, y_value, z_value)
|
||||
}
|
||||
}
|
||||
ans := []string{"z07", "rts", "z12", "jpj", "z26", "kgj", "vvw", "chv"}
|
||||
sort.Strings(ans)
|
||||
fmt.Println(strings.Join(ans, ","))
|
||||
return z_value
|
||||
}
|
||||
|
||||
func (n *Network) AddWires(data string) {
|
||||
for _, line := range strings.Split(data, "\n") {
|
||||
v := strings.Split(line, ": ")
|
||||
n.AddWire(&Wire{name: v[0], state: to_state(v[1])})
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Network) AddWire(wire *Wire) {
|
||||
n.wires = append(n.wires, wire)
|
||||
}
|
||||
|
||||
func (n *Network) AddWires2(w string, count int, value int64) {
|
||||
for x := 0; x < count; x++ {
|
||||
name := fmt.Sprintf("%s%02d", w, x)
|
||||
v := fmt.Sprintf("%d", (value>>x)&1)
|
||||
n.AddWire(&Wire{name: name, state: to_state(v)})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (n *Network) AddGates(data string) {
|
||||
// ntg XOR fgs -> mjb
|
||||
pattern := `^([a-z0-9]{3}) (AND|OR|XOR) ([a-z0-9]{3}) -> ([a-z[0-9]{3})$`
|
||||
|
||||
re := regexp.MustCompile(pattern)
|
||||
for _, line := range strings.Split(data, "\n") {
|
||||
matches := re.FindAllStringSubmatch(line, -1)
|
||||
for _, match := range matches {
|
||||
n.AddGate(match[1], match[2], match[3], match[4], &n.wires)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Network) SwapOutputs(a, b string) {
|
||||
_, wire1 := to_wire(a, n.wires)
|
||||
_, wire2 := to_wire(b, n.wires)
|
||||
for _, gate := range n.gates {
|
||||
if gate.out.name == a {
|
||||
gate.out = wire2
|
||||
} else if gate.out.name == b {
|
||||
gate.out = wire1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Network) AddGate(in0, op, in1, out string, wires *[]*Wire) {
|
||||
var in [2]*Wire
|
||||
var outw *Wire
|
||||
*wires, in[0] = to_wire(in0, *wires)
|
||||
*wires, in[1] = to_wire(in1, *wires)
|
||||
*wires, outw = to_wire(out, *wires)
|
||||
n.gates = append(n.gates, &Gate{in: in,
|
||||
op: to_operation(op),
|
||||
out: outw})
|
||||
}
|
||||
|
||||
func (n *Network) OutputKnown() bool {
|
||||
for _, gate := range n.gates {
|
||||
if gate.out.name[0] != 'z' {
|
||||
continue
|
||||
}
|
||||
if gate.out.state == NA {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (n *Network) Output() int64 {
|
||||
var ret int64
|
||||
ret = 0
|
||||
for _, gate := range n.gates {
|
||||
if gate.out.name[0] != 'z' {
|
||||
continue
|
||||
}
|
||||
addr := utils.MustAtoi(gate.out.name[1:])
|
||||
if gate.out.state == ONE {
|
||||
ret += 1 << addr
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (n Gate) String() string {
|
||||
return n.in[0].name + "(" + n.in[0].state.String() + ")\t" + n.op.String() + " " + n.in[1].name + "(" + n.in[1].state.String() + ")\t ->\t" + n.out.name + " (" + n.out.state.String() + ")"
|
||||
}
|
||||
func to_state(in string) State {
|
||||
switch in {
|
||||
case "1":
|
||||
return ONE
|
||||
case "0":
|
||||
return ZERO
|
||||
}
|
||||
return NA
|
||||
}
|
||||
|
||||
func to_operation(in string) Operation {
|
||||
var val Operation
|
||||
switch in {
|
||||
case "AND":
|
||||
val = AND
|
||||
case "OR":
|
||||
val = OR
|
||||
case "XOR":
|
||||
val = XOR
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func to_wire(in string, wires []*Wire) ([]*Wire, *Wire) {
|
||||
for _, v := range wires {
|
||||
if in == v.name {
|
||||
return wires, v
|
||||
}
|
||||
}
|
||||
wire := Wire{name: in, state: NA}
|
||||
wires = append(wires, &wire)
|
||||
return wires, &wire
|
||||
}
|
||||
|
||||
func And(a, b State) State {
|
||||
if a == ONE && b == ONE {
|
||||
return ONE
|
||||
}
|
||||
return ZERO
|
||||
}
|
||||
|
||||
func Or(a, b State) State {
|
||||
if a == ONE || b == ONE {
|
||||
return ONE
|
||||
}
|
||||
return ZERO
|
||||
}
|
||||
|
||||
func Xor(a, b State) State {
|
||||
if (a == ONE && b == ZERO) || (a == ZERO && b == ONE) {
|
||||
return ONE
|
||||
}
|
||||
return ZERO
|
||||
}
|
||||
|
||||
func (state State) String() string {
|
||||
switch state {
|
||||
case NA:
|
||||
return "NA"
|
||||
case ZERO:
|
||||
return "0"
|
||||
case ONE:
|
||||
return "1"
|
||||
default:
|
||||
return "Invalid"
|
||||
}
|
||||
}
|
||||
|
||||
func (op Operation) String() string {
|
||||
switch op {
|
||||
case OR:
|
||||
return "OR"
|
||||
case AND:
|
||||
return "AND"
|
||||
case XOR:
|
||||
return "XOR"
|
||||
default:
|
||||
return "Invalid"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user