https://github.com/akkartik/mu/blob/main/linux/advent2020/2b.mu
  1 # https://adventofcode.com/2020/day/2
  2 #
  3 # To run (on Linux):
  4 #   $ git clone https://github.com/akkartik/mu
  5 #   $ cd mu
  6 #   $ ./translate advent2020/2b.mu
  7 #   $ ./a.elf < input
  8 #
  9 # You'll need to register to download the 'input' file for yourself.
 10 
 11 fn main -> _/ebx: int {
 12   var valid-password-count/edi: int <- copy 0
 13   var line-storage: (stream byte 0x100)  # 256 bytes
 14   var line/edx: (addr stream byte) <- address line-storage
 15   var slice-storage: slice
 16   var slice/ecx: (addr slice) <- address slice-storage
 17   {
 18     # read line from stdin
 19     clear-stream line
 20     read-line-from-real-keyboard line
 21     # if line is empty (not even a newline), quit
 22     var done?/eax: boolean <- stream-empty? line
 23     compare done?, 0/false
 24     break-if-!=
 25     print-stream-to-real-screen line
 26     # slice = next-token(line, '-')
 27     next-token line, 0x2d, slice
 28     # pos1 = parse-int(slice)
 29     var _pos1/eax: int <- parse-decimal-int-from-slice slice
 30     var pos1/ebx: int <- copy _pos1
 31     var dash/eax: byte <- read-byte line  # skip '-'
 32     # slice = next-token(line, ' ')
 33     next-token line, 0x20, slice
 34     var _pos2/eax: int <- parse-decimal-int-from-slice slice
 35     var pos2/esi: int <- copy _pos2
 36     print-int32-decimal 0, pos1
 37     print-string 0, " "
 38     print-int32-decimal 0, pos2
 39     print-string 0, "\n"
 40     compare pos1, pos2
 41     {
 42       break-if-<=
 43       print-string 0, "out of order!\n"
 44       return 1
 45     }
 46     # letter = next non-space
 47     skip-chars-matching-whitespace line
 48     var letter/eax: byte <- read-byte line
 49     # skip some stuff
 50     {
 51       var colon/eax: byte <- read-byte line  # skip ':'
 52     }
 53     skip-chars-matching-whitespace line
 54     # now check the rest of the line
 55     var valid?/eax: boolean <- valid? pos1, pos2, letter, line
 56     compare valid?, 0/false
 57     {
 58       break-if-=
 59       print-string 0, "valid!\n"
 60       valid-password-count <- increment
 61     }
 62     loop
 63   }
 64   print-int32-decimal 0, valid-password-count
 65   print-string 0, "\n"
 66   return 0
 67 }
 68 
 69 # ideally password would be a random-access array
 70 # we'll just track an index
 71 # one benefit: we can easily start at 1
 72 fn valid? pos1: int, pos2: int, letter: byte, password: (addr stream byte) -> _/eax: boolean {
 73   var i/esi: int <- copy 1
 74   var letter-count/edi: int <- copy 0
 75   # while password stream isn't empty
 76   #   c = read byte from password
 77   #   if (c == letter)
 78   #     if (i == pos1)
 79   #       ++letter-count
 80   #     if (i == pos2)
 81   #       ++letter-count
 82   #     ++i
 83   {
 84 #?     print-string 0, "  "
 85 #?     print-int32-decimal 0, i
 86 #?     print-string 0, "\n"
 87     var done?/eax: boolean <- stream-empty? password
 88     compare done?, 0/false
 89     break-if-!=
 90     var c/eax: byte <- read-byte password
 91 #?     {
 92 #?       var c2/eax: int <- copy c
 93 #?       print-int32-decimal 0, c2
 94 #?       print-string 0, "\n"
 95 #?     }
 96     compare c, letter
 97     {
 98       break-if-!=
 99       compare i, pos1
100       {
101         break-if-!=
102         letter-count <- increment
103 #?         print-string 0, "  hit\n"
104       }
105       compare i, pos2
106       {
107         break-if-!=
108         letter-count <- increment
109 #?         print-string 0, "  hit\n"
110       }
111     }
112     i <- increment
113     loop
114   }
115   # return (letter-count == 1)
116   compare letter-count, 1
117   {
118     break-if-!=
119     return 1/true
120   }
121   return 0/false
122 }