diff --git a/day17/copy.go b/day17/copy.go deleted file mode 100644 index f55d6fd..0000000 --- a/day17/copy.go +++ /dev/null @@ -1,157 +0,0 @@ -package main - -import ("math"; "errors"; "strconv"; "strings"; "fmt"; "os") - -//--------------------------------------------------------- -func check(err error) { if err != nil { panic(err) } } - -//--------------------------------------------------------- -type Computer struct { - pc uint - ra uint - rb uint - rc uint - mem []byte -} - -func NewComputer(input string) *Computer { - registers := strings.Split(input, "\n\n")[0] - memory := strings.Split(strings.Split(input, "\n\n")[1], " ")[1] - - lines := strings.Split(registers, "\n") - ra, err := strconv.Atoi(strings.TrimSpace(strings.Split(lines[0], ":")[1])) - check(err) - rb, err := strconv.Atoi(strings.TrimSpace(strings.Split(lines[1], ":")[1])) - check(err) - rc, err := strconv.Atoi(strings.TrimSpace(strings.Split(lines[2], ":")[1])) - check(err) - - mem := make([]byte, 0) - for _, str := range strings.Split(memory, ",") { - num, err := strconv.Atoi(str) - check(err) - mem = append(mem, byte(num)) - } - - return &Computer{ - pc: 0, - ra: uint(ra), - rb: uint(rb), - rc: uint(rc), - mem: mem, - } -} - -func (c *Computer) literalop() uint { - // current literal operator - return uint(c.mem[c.pc + 1]) -} - -func (c *Computer) comboop() uint { - // current combo operator - val := uint(c.mem[c.pc + 1]) - - switch { - case val == 4: val = c.ra - case val == 5: val = c.rb - case val == 6: val = c.rc - case val == 7: panic("invalid program") - } - - return val -} - -func (c *Computer) adv(op uint) uint { - // division - numerator := c.ra - denominator := math.Pow(2, float64(op)) - return uint(float64(numerator) / float64(denominator)) -} - -func (c *Computer) bxl(op uint) uint { - // bitwise xor - return c.rb ^ op -} - -func (c *Computer) bst(op uint) uint { - // mod 8 - return op % 8 -} - -func (c *Computer) jnz(op uint) { - // jump if non zero - if c.ra == 0 { - return - } else { - c.pc = op - 2 - return - } -} - -func (c *Computer) bxc() uint { - // bitwise xor - return c.rb ^ c.rc -} - -func (c *Computer) tick() (int, error) { - // returns an error if the program halts - if c.pc >= uint(len(c.mem)) { return -1, errors.New("halted") } - - instr := c.mem[c.pc] - out := -1 - switch { - case instr == 0: c.ra = c.adv(c.comboop()) - case instr == 1: c.rb = c.bxl(c.literalop()) - case instr == 2: c.rb = c.bst(c.comboop()) - case instr == 3: c.jnz(c.literalop()) - case instr == 4: c.rb = c.bxc() - case instr == 5: out = int(c.comboop() % 8) - case instr == 6: c.rb = c.adv(c.comboop()) - case instr == 7: c.rc = c.adv(c.comboop()) - } - - c.pc += 2 - return out, nil -} - -func (c *Computer) returns_its_source() bool { - i := 0 - for { - out, err := c.tick() - - if err != nil { return false } - if out != -1 { - if byte(out) != c.mem[i] { return false } - i++ - if i == len(c.mem) { return true } - } - } - // never reached - return false -} - -func (c *Computer) restore(ra uint) { - c.pc = 0 - c.ra = ra - c.rb = 0 - c.rc = 0 -} - - -//--------------------------------------------------------- -func main() { - dat, err := os.ReadFile("data.txt") - check(err) - input := strings.TrimSpace(string(dat)) - - comp := NewComputer(input) - - for i := range 1000000000 { - comp.restore(uint(i)) - if comp.returns_its_source() { - fmt.Println(i) - break - } - } -} - diff --git a/day17/reversed.go b/day17/reversed.go new file mode 100644 index 0000000..a694104 --- /dev/null +++ b/day17/reversed.go @@ -0,0 +1,107 @@ +package main + +import ( + "fmt" + "strconv" +) + +func reverseSlice(slice []uint) { + for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 { + slice[i], slice[j] = slice[j], slice[i] + } +} + +func compressedProgram(ra uint) []uint { + out := make([]uint, 0) + + var A, B uint + A = ra + + for { + B = ((A % 8) ^ 2) ^ 7 ^ (A >> ((A % 8) ^ 2)) + A = A >> 3 + + out = append(out, B%8) + + if A == 0 { + break + } + } + + return out +} + +func reversedProgram(out []uint) uint { + reverseSlice(out) + A := uint(0) + + for _, o := range out { + + // find next n bits so that o is returned + n := 2 + searching := true + for searching { + n++ + + // for every combination of n bits + for i := range 1 << n { + A_ := (A << n) + uint(i) + + //fmt.Println("add", i, "as binary with", n, "bits") + //fmt.Println("old", strconv.FormatUint(uint64(A), 2)) + //fmt.Println("new", strconv.FormatUint(uint64(A_), 2)) + + if o == ((A_%8)^2)^7^(A_>>((A_%8)^2))%8 { + A = A_ + //fmt.Println("valid") + //fmt.Println("yields", compressedProgram(A)) + searching = false + break + } + + //fmt.Println("invalid") + } + } + + } + return A +} + +func main() { + /* + + + fmt.Println(input) + + a := uint64(0) + for _, elem := range input { + + expected_d := elem ^ 7 + for b := range 8 { + e := uint64(b ^ 2) + c := (((a << 3) | uint64(b)) >> (e)) % 8 + actual_d := c ^ e + if uint64(expected_d) == actual_d { + fmt.Println(b) + fmt.Println(e) + fmt.Println(c) + a = a << 3 + a = a | uint64(b) + fmt.Println(strconv.FormatUint(a, 2)) + fmt.Println(a, 2) + break + } + } + + } + fmt.Println(a) + //fmt.Println(strconv.FormatUint(a, 2)) + */ + + //fmt.Println(compressedProgram(41644071)) + + input := []uint{2, 4, 1, 2, 7, 5, 1, 7, 4, 4, 0, 3, 5, 5, 3, 0} + fmt.Println("-- input: ", input, "--") + ra := reversedProgram(input) + fmt.Println("-- ra: ", ra, "--") +}