From 1a6529c7d2ef161ab570b00d8aad5e6c45b3d8a1 Mon Sep 17 00:00:00 2001 From: Parnic Date: Fri, 24 Jun 2022 23:20:31 -0500 Subject: [PATCH] Day 21 solution Hopefully my logic is explained well enough in the comments for this one. We're just layering more programming languages on top of other programming languages. This is how you anger the computer gods and bring about the AI singularity. I also made some general tweaks to the Intcode machine to make ASCII intcode machines dead simple to deal with. Is it worth the extra branches for each input and output instruction in the interpreter? Probably not...but I was never going to win any speed competitions anyway. --- days/17.go | 6 ++-- days/21.go | 85 ++++++++++++++++++++++++++++++++++++++++++++ inputs/21p.txt | 1 + main.go | 1 + utilities/intcode.go | 39 +++++++++++++++++--- 5 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 days/21.go create mode 100644 inputs/21p.txt diff --git a/days/17.go b/days/17.go index 5c37472..8ab32c1 100644 --- a/days/17.go +++ b/days/17.go @@ -48,6 +48,7 @@ type Day17 struct { func (d *Day17) Parse() { d.program = u.LoadIntcodeProgram("17p") + // d.program.SetDebugASCIIPrint(true) } func (d Day17) Num() int { @@ -388,9 +389,8 @@ func (d *Day17) Part2() string { row := 0 var outputState int var lastOutput int64 - var instructionStr string d.program.RunIn(func(inputStep int) int64 { - return int64(instructionStr[inputStep-1]) + panic("unexpected read") }, func(val int64, state u.IntcodeProgramState) { rVal := rune(val) if outputState == 0 { @@ -401,7 +401,7 @@ func (d *Day17) Part2() string { if rVal == '\n' && lastOutput == '\n' { if outputState == 0 { - instructionStr = beforeGrid.solvePath(beforeBotLocation, beforeBotFacing) + d.program.FeedInputString(beforeGrid.solvePath(beforeBotLocation, beforeBotFacing)) } outputState++ row = 0 diff --git a/days/21.go b/days/21.go new file mode 100644 index 0000000..ca09487 --- /dev/null +++ b/days/21.go @@ -0,0 +1,85 @@ +package days + +import ( + "fmt" + "strings" + + u "parnic.com/aoc2019/utilities" +) + +type Day21 struct { + program u.IntcodeProgram +} + +func (d *Day21) Parse() { + d.program = u.LoadIntcodeProgram("21p") + // d.program.SetDebugASCIIPrint(true) +} + +func (d Day21) Num() int { + return 21 +} + +func (d *Day21) Part1() string { + // if there's any hole up to 3 ahead of us but there's ground where we'd land if we jumped + // (a jump takes 4 spaces), go ahead and jump + cmds := []string{ + // check if a hole at 1 or 2 ahead + "NOT A T", + "NOT B J", + // store that result in J + "OR T J", + // check if a hole at 3 ahead + "NOT C T", + // store hole in 1, 2, or 3 in T + "OR J T", + // set J true if hole in 1, 2, or 3 + "OR T J", + // set J true if also no hole at 4 ahead + "AND D J", + "WALK", + } + instructionStr := strings.Join(cmds, "\n") + "\n" + d.program.FeedInputString(instructionStr) + + res := d.program.Run() + + return fmt.Sprintf("Hull damage value when walking: %s%d%s", u.TextBold, res, u.TextReset) +} + +func (d *Day21) Part2() string { + // @ + // #####.#.##.##.### + // ABCDEFGHI + // using the first program, this kills us. if we jump, we land at D and H becomes our new D, so it won't jump again. + // but if we waited to jump until we got one more ahead, we'd be ok. + // so now we want to know essentially the same thing as part 1, but also if our multiple (immediate second jump) would be successful. + // in problem terms, that's: if there's a hole at 1 or 2 ahead, and there's a hole at C with ground at H, and there's ground at D. + // so now for the above example we'd wait to jump until here: + // @ + // #####.#.##.##.### + // ABCDEFGHI + // and all will be well. + cmds := []string{ + // check if a hole at 1 or 2 ahead + "NOT A J", + "NOT B T", + // store that result in J + "OR T J", + // check if a hole at 3 ahead... + "NOT C T", + // and ground at 8 ahead (so we can immediately jump again if needed)... + "AND H T", + // combine those into J + "OR T J", + // and ensure we also still have a place to land if we jumped right away + "AND D J", + "RUN", + } + instructionStr := strings.Join(cmds, "\n") + "\n" + d.program.FeedInputString(instructionStr) + + res := d.program.Run() + + return fmt.Sprintf("Hull damage value when running: %s%d%s", u.TextBold, res, u.TextReset) +} diff --git a/inputs/21p.txt b/inputs/21p.txt new file mode 100644 index 0000000..78e2192 --- /dev/null +++ b/inputs/21p.txt @@ -0,0 +1 @@ +109,2050,21102,966,1,1,21101,0,13,0,1106,0,1378,21101,0,20,0,1105,1,1337,21101,27,0,0,1105,1,1279,1208,1,65,748,1005,748,73,1208,1,79,748,1005,748,110,1208,1,78,748,1005,748,132,1208,1,87,748,1005,748,169,1208,1,82,748,1005,748,239,21102,1,1041,1,21102,1,73,0,1105,1,1421,21101,0,78,1,21101,0,1041,2,21102,1,88,0,1105,1,1301,21101,0,68,1,21102,1041,1,2,21102,103,1,0,1105,1,1301,1102,1,1,750,1105,1,298,21101,82,0,1,21102,1,1041,2,21102,1,125,0,1105,1,1301,1101,0,2,750,1106,0,298,21101,79,0,1,21102,1,1041,2,21102,1,147,0,1105,1,1301,21102,84,1,1,21101,0,1041,2,21102,162,1,0,1105,1,1301,1102,3,1,750,1106,0,298,21101,0,65,1,21102,1,1041,2,21101,184,0,0,1105,1,1301,21102,1,76,1,21102,1,1041,2,21102,199,1,0,1105,1,1301,21101,75,0,1,21102,1041,1,2,21102,1,214,0,1105,1,1301,21102,221,1,0,1105,1,1337,21102,1,10,1,21101,1041,0,2,21102,1,236,0,1106,0,1301,1106,0,553,21101,0,85,1,21101,0,1041,2,21102,1,254,0,1105,1,1301,21101,78,0,1,21102,1041,1,2,21102,1,269,0,1106,0,1301,21101,0,276,0,1106,0,1337,21102,1,10,1,21101,1041,0,2,21101,0,291,0,1105,1,1301,1102,1,1,755,1106,0,553,21101,32,0,1,21102,1,1041,2,21101,0,313,0,1106,0,1301,21102,320,1,0,1105,1,1337,21101,327,0,0,1106,0,1279,1201,1,0,749,21102,1,65,2,21102,73,1,3,21102,1,346,0,1105,1,1889,1206,1,367,1007,749,69,748,1005,748,360,1101,0,1,756,1001,749,-64,751,1105,1,406,1008,749,74,748,1006,748,381,1101,-1,0,751,1105,1,406,1008,749,84,748,1006,748,395,1101,-2,0,751,1106,0,406,21101,0,1100,1,21101,0,406,0,1106,0,1421,21102,32,1,1,21101,0,1100,2,21101,0,421,0,1105,1,1301,21102,428,1,0,1105,1,1337,21101,0,435,0,1106,0,1279,2101,0,1,749,1008,749,74,748,1006,748,453,1102,-1,1,752,1106,0,478,1008,749,84,748,1006,748,467,1102,-2,1,752,1105,1,478,21101,1168,0,1,21101,478,0,0,1105,1,1421,21101,0,485,0,1105,1,1337,21101,10,0,1,21102,1168,1,2,21101,0,500,0,1105,1,1301,1007,920,15,748,1005,748,518,21101,0,1209,1,21102,518,1,0,1106,0,1421,1002,920,3,529,1001,529,921,529,1002,750,1,0,1001,529,1,537,1002,751,1,0,1001,537,1,545,101,0,752,0,1001,920,1,920,1105,1,13,1005,755,577,1006,756,570,21102,1,1100,1,21102,1,570,0,1105,1,1421,21101,0,987,1,1105,1,581,21101,0,1001,1,21102,588,1,0,1105,1,1378,1101,758,0,594,102,1,0,753,1006,753,654,21001,753,0,1,21101,610,0,0,1106,0,667,21101,0,0,1,21102,1,621,0,1106,0,1463,1205,1,647,21102,1015,1,1,21102,1,635,0,1106,0,1378,21102,1,1,1,21102,646,1,0,1106,0,1463,99,1001,594,1,594,1106,0,592,1006,755,664,1101,0,0,755,1106,0,647,4,754,99,109,2,1102,1,726,757,22101,0,-1,1,21102,1,9,2,21102,697,1,3,21102,1,692,0,1106,0,1913,109,-2,2105,1,0,109,2,101,0,757,706,2101,0,-1,0,1001,757,1,757,109,-2,2106,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,255,63,95,127,159,223,191,0,69,237,34,117,213,198,217,216,221,172,218,185,178,53,177,174,122,163,196,226,103,162,70,111,46,84,233,238,246,206,245,175,166,157,42,248,47,212,118,109,56,121,108,200,92,78,190,155,215,235,59,38,182,76,234,49,71,116,137,68,43,220,107,169,125,179,204,99,54,152,189,123,173,143,232,124,86,126,252,139,241,214,183,187,39,244,113,136,188,203,253,171,58,184,57,242,98,140,154,205,168,119,85,102,239,50,222,100,55,60,229,228,247,79,197,254,35,51,153,167,227,142,251,94,201,249,61,110,62,236,114,158,141,170,219,77,156,138,101,250,199,106,181,243,230,115,202,231,93,120,186,87,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,73,110,112,117,116,32,105,110,115,116,114,117,99,116,105,111,110,115,58,10,13,10,87,97,108,107,105,110,103,46,46,46,10,10,13,10,82,117,110,110,105,110,103,46,46,46,10,10,25,10,68,105,100,110,39,116,32,109,97,107,101,32,105,116,32,97,99,114,111,115,115,58,10,10,58,73,110,118,97,108,105,100,32,111,112,101,114,97,116,105,111,110,59,32,101,120,112,101,99,116,101,100,32,115,111,109,101,116,104,105,110,103,32,108,105,107,101,32,65,78,68,44,32,79,82,44,32,111,114,32,78,79,84,67,73,110,118,97,108,105,100,32,102,105,114,115,116,32,97,114,103,117,109,101,110,116,59,32,101,120,112,101,99,116,101,100,32,115,111,109,101,116,104,105,110,103,32,108,105,107,101,32,65,44,32,66,44,32,67,44,32,68,44,32,74,44,32,111,114,32,84,40,73,110,118,97,108,105,100,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,59,32,101,120,112,101,99,116,101,100,32,74,32,111,114,32,84,52,79,117,116,32,111,102,32,109,101,109,111,114,121,59,32,97,116,32,109,111,115,116,32,49,53,32,105,110,115,116,114,117,99,116,105,111,110,115,32,99,97,110,32,98,101,32,115,116,111,114,101,100,0,109,1,1005,1262,1270,3,1262,21002,1262,1,0,109,-1,2106,0,0,109,1,21101,0,1288,0,1105,1,1263,21001,1262,0,0,1101,0,0,1262,109,-1,2106,0,0,109,5,21101,1310,0,0,1106,0,1279,21202,1,1,-2,22208,-2,-4,-1,1205,-1,1332,22101,0,-3,1,21101,1332,0,0,1105,1,1421,109,-5,2105,1,0,109,2,21101,0,1346,0,1105,1,1263,21208,1,32,-1,1205,-1,1363,21208,1,9,-1,1205,-1,1363,1106,0,1373,21101,0,1370,0,1105,1,1279,1105,1,1339,109,-2,2105,1,0,109,5,2102,1,-4,1386,20101,0,0,-2,22101,1,-4,-4,21101,0,0,-3,22208,-3,-2,-1,1205,-1,1416,2201,-4,-3,1408,4,0,21201,-3,1,-3,1106,0,1396,109,-5,2106,0,0,109,2,104,10,21201,-1,0,1,21101,0,1436,0,1106,0,1378,104,10,99,109,-2,2105,1,0,109,3,20002,594,753,-1,22202,-1,-2,-1,201,-1,754,754,109,-3,2105,1,0,109,10,21102,5,1,-5,21101,1,0,-4,21101,0,0,-3,1206,-9,1555,21102,1,3,-6,21101,0,5,-7,22208,-7,-5,-8,1206,-8,1507,22208,-6,-4,-8,1206,-8,1507,104,64,1105,1,1529,1205,-6,1527,1201,-7,716,1515,21002,0,-11,-8,21201,-8,46,-8,204,-8,1105,1,1529,104,46,21201,-7,1,-7,21207,-7,22,-8,1205,-8,1488,104,10,21201,-6,-1,-6,21207,-6,0,-8,1206,-8,1484,104,10,21207,-4,1,-8,1206,-8,1569,21101,0,0,-9,1106,0,1689,21208,-5,21,-8,1206,-8,1583,21101,0,1,-9,1105,1,1689,1201,-5,716,1589,20102,1,0,-2,21208,-4,1,-1,22202,-2,-1,-1,1205,-2,1613,21201,-5,0,1,21101,0,1613,0,1105,1,1444,1206,-1,1634,21201,-5,0,1,21101,1627,0,0,1105,1,1694,1206,1,1634,21101,0,2,-3,22107,1,-4,-8,22201,-1,-8,-8,1206,-8,1649,21201,-5,1,-5,1206,-3,1663,21201,-3,-1,-3,21201,-4,1,-4,1106,0,1667,21201,-4,-1,-4,21208,-4,0,-1,1201,-5,716,1676,22002,0,-1,-1,1206,-1,1686,21101,0,1,-4,1106,0,1477,109,-10,2105,1,0,109,11,21101,0,0,-6,21102,0,1,-8,21102,1,0,-7,20208,-6,920,-9,1205,-9,1880,21202,-6,3,-9,1201,-9,921,1724,21001,0,0,-5,1001,1724,1,1733,20102,1,0,-4,21201,-4,0,1,21101,1,0,2,21102,1,9,3,21101,1754,0,0,1105,1,1889,1206,1,1772,2201,-10,-4,1767,1001,1767,716,1767,20101,0,0,-3,1106,0,1790,21208,-4,-1,-9,1206,-9,1786,21202,-8,1,-3,1106,0,1790,21201,-7,0,-3,1001,1733,1,1795,21001,0,0,-2,21208,-2,-1,-9,1206,-9,1812,21201,-8,0,-1,1106,0,1816,22101,0,-7,-1,21208,-5,1,-9,1205,-9,1837,21208,-5,2,-9,1205,-9,1844,21208,-3,0,-1,1106,0,1855,22202,-3,-1,-1,1105,1,1855,22201,-3,-1,-1,22107,0,-1,-1,1105,1,1855,21208,-2,-1,-9,1206,-9,1869,21202,-1,1,-8,1106,0,1873,21202,-1,1,-7,21201,-6,1,-6,1105,1,1708,21202,-8,1,-10,109,-11,2106,0,0,109,7,22207,-6,-5,-3,22207,-4,-6,-2,22201,-3,-2,-1,21208,-1,0,-6,109,-7,2106,0,0,0,109,5,2101,0,-2,1912,21207,-4,0,-1,1206,-1,1930,21102,1,0,-4,22101,0,-4,1,22102,1,-3,2,21101,1,0,3,21102,1,1949,0,1106,0,1954,109,-5,2106,0,0,109,6,21207,-4,1,-1,1206,-1,1977,22207,-5,-3,-1,1206,-1,1977,22102,1,-5,-5,1106,0,2045,21201,-5,0,1,21201,-4,-1,2,21202,-3,2,3,21101,0,1996,0,1105,1,1954,21202,1,1,-5,21102,1,1,-2,22207,-5,-3,-1,1206,-1,2015,21102,0,1,-2,22202,-3,-2,-3,22107,0,-4,-1,1206,-1,2037,22101,0,-2,1,21102,2037,1,0,106,0,1912,21202,-3,-1,-3,22201,-5,-3,-5,109,-6,2105,1,0 \ No newline at end of file diff --git a/main.go b/main.go index ef64316..b6b82e1 100644 --- a/main.go +++ b/main.go @@ -54,6 +54,7 @@ var dayMap = []day{ &days.Day18{}, &days.Day19{}, &days.Day20{}, + &days.Day21{}, } func main() { diff --git a/utilities/intcode.go b/utilities/intcode.go index d037711..b9162ff 100644 --- a/utilities/intcode.go +++ b/utilities/intcode.go @@ -28,6 +28,8 @@ type IntcodeProgram struct { program []int64 relativeBase int haltRequested bool + printASCII bool + feedInput []rune } type IntcodeProgramState struct { @@ -140,14 +142,15 @@ func (p *IntcodeProgram) Reset() { p.relativeBase = 0 } -func (p *IntcodeProgram) Run() { - p.RunIn(func(int) int64 { return 0 }, func(int64, IntcodeProgramState) {}) +func (p *IntcodeProgram) Run() int64 { + return p.RunIn(func(int) int64 { return 0 }, func(int64, IntcodeProgramState) {}) } -func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOutputFunc) { +func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOutputFunc) int64 { p.init() inputsRequested := 0 + lastOutput := int64(0) for instructionPointer := 0; instructionPointer < len(p.program) && !p.haltRequested; { instruction := p.GetMemory(instructionPointer) instructionPointer++ @@ -184,13 +187,28 @@ func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOut case opInput: inputsRequested++ param1 := p.GetMemory(instructionPointer) - p.setMemory(int(param1), inputFunc(inputsRequested), paramModes[0]) + var inputVal int64 + if len(p.feedInput) > 0 { + inputVal = int64(p.feedInput[0]) + p.feedInput = p.feedInput[1:] + } else { + inputVal = inputFunc(inputsRequested) + } + if p.printASCII && inputVal <= 255 { + fmt.Printf("%c", rune(inputVal)) + } + p.setMemory(int(param1), inputVal, paramModes[0]) instructionPointer += 1 case opOutput: param1 := p.GetMemory(instructionPointer) - outputFunc(p.getParamValue(int(param1), paramModes[0]), p.makeState(instructionPointer)) + param1Val := p.getParamValue(int(param1), paramModes[0]) + if p.printASCII && param1Val <= 255 { + fmt.Printf("%c", rune(param1Val)) + } + outputFunc(param1Val, p.makeState(instructionPointer)) + lastOutput = param1Val instructionPointer += 1 @@ -256,8 +274,19 @@ func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOut } p.haltRequested = false + + return lastOutput } func (p *IntcodeProgram) Stop() { p.haltRequested = true } + +func (p *IntcodeProgram) SetDebugASCIIPrint(enable bool) { + p.printASCII = enable +} + +func (p *IntcodeProgram) FeedInputString(str string) { + p.feedInput = make([]rune, len(str)) + copy(p.feedInput, []rune(str)) +}