<jupyter_start><jupyter_text>Day 21 - boolean logicFor part 1, I can see from the _springscript_ example that the robot can jump across three holes (`NOT D J`). Given that it only has sensors for the next 4 locations, that's quite helpful, and we do *not* want to jump if there is a hole at `D`.So we need it to instruct to jump if a) there is a hole ahead, and b) we can land again. That's$$(\lnot A \lor \lnot  B \lor \lnot  C) \land D$$So at least one of A, B or C is `false` (not ground, so a hole), and D is `true` (there is ground). We can use the `T` temporary register to record the required `NOT` outcomes, then `OR` those with the `J` register, then finally `AND` the outcome of those with `D`. Remember that `J` and `T` start out `false`:```NOT A J    if A is a hole perhaps jumpNOT B T    or if B is a holeOR  T J    perhaps jumpNOT C T    or if C is a holeOR  T J    perhaps jumpAND D J    but only if D is ground```That's 6 instructions. Using [De Morgan's laws](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) we can transform a group of $(\lnot R_1 \lor \lnot R_2 \lor \lnot \cdots)$ to $\lnot(R_1 \land R_2 \land \ldots)$ and so save an instruction:```OR  A T    copy A to T, if A is groundAND B T    and if B is groundAND C T    and C is groundNOT T J    if none of that is true, jumpAND D J    but only if D is ground```<jupyter_code>from __future__ import annotations
from typing import List, Sequence, Union

from intcode import CPU, ioset

def exec_springscript(memory: List[int], script: Sequence[Union[bytes, str]], exec: bytes = b"WALK") -> int:
    """Accepts springscript lines with extra whitespace and comments after #"""
    if isinstance(exec, str):
        exec = exec.encode("ASCII")
    lines = []
    for line in script:
        if isinstance(line, str):
            line = line.encode("ASCII")
        if b"#" in line:
            line = line.partition(b"#")[0]
        # normalise whitespace
        line = b" ".join(line.split())
        if line:
            lines.append(line)
    if lines[-1] != exec:
        lines.append(exec)
    springscript = b"\n".join(lines) + b"\n"
    outputs, opcodes = ioset(*springscript)
    CPU(opcodes).reset(memory).execute()
    
    if 0 <= outputs[-1] < 256:
        raise ValueError(bytes(outputs).decode("ASCII"))
    return outputs[-1]
import aocd
data = aocd.get_data(day=21, year=2019)
memory = list(map(int, data.split(',')))
part1_springscript = """\
OR  A T   # copy A to T, if A is ground
AND B T   # and if B is ground
AND C T   # and C is ground
NOT T J   # if none of that is true, jump
AND D J   # but only if D is ground
""".splitlines()
print("Part 1:", exec_springscript(memory, part1_springscript))<jupyter_output>Part 1: 19352720<jupyter_text>Part 2Now we are told we *can* look further. I'm going to assume this means we only want to enter an area if we know we can cross the next 9 positions. From experiments it appears that the bot will walk one step after a jump that we can jump twice and so can test the options for *2* different positions after the second jump (H and I), we need to make sure we can make those jumps. Given that the bot will re-evaluate, on landing on `D`, how to proceed from there, we want to avaid jumping into a situation we can't handle from that point.Here's the first such situation we can handle; we can jump across to D, and we can jump across to H, so we are fine, and presumably we can jump from H onwards if `I` is a hole:```@???????^ ABCDEFGHI|We are here, to jump from the next tile, distance 4, to D```We can also handle walking a single step, then evaluate if we need to jump again:```@???????  ABCDEFGHI```Together with the logic of part 1, that's:$$(\lnot A \lor \lnot  B \lor \lnot  C) \land D \land (H \lor E)$$which turns into the following springscript:```OR  A T    copy A to T, if A is groundAND B T    and if B is groundAND C T    and C is groundNOT T J    if none of that is true, jumpAND D J    but only if D is ground we need to copy H to T to ignore the previous value of TNOT H T    not H is the inverse of HNOT T T    not T is now equal to H, true if H is groundOR  E T    or if E is groundAND T J    then confirm the jump```9 instructions, so well within the limit.<jupyter_code>part2_springscript = """\
OR  A T   # copy A to T, if A is ground
AND B T   # and if B is ground
AND C T   # and C is ground
NOT T J   # if none of that is true, jump
AND D J   # but only if D is ground
# we need to copy H to T to ignore
# the previous value of T
NOT H T   # not H is the inverse of H
NOT T T   # not T is now equal to H, true if H is ground
OR  E T   # or if E is ground
AND T J   # then confirm the jump
""".splitlines()
print("Part 2:", exec_springscript(memory, part2_springscript, "RUN"))<jupyter_output>Part 2: 1143652885
{'fraction_non_alphanumeric': 0.0919179229480737, 'fraction_numerical': 0.01193467336683417, 'mean_word_length': 3.1611498257839723, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 8, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '560235', 'license': 'MIT', 'n_tokens_mistral': 1538, 'n_tokens_neox': 1480, 'n_words': 795, 'path': '2019/Day 21.ipynb', 'repo_name': 'AwesomeGitHubRepos/adventofcode', 'size': '4776'}