├── day01 ├── day01.test ├── day01.py └── day01.mod ├── day03 ├── day03a.test ├── day03b.test └── day03.lua ├── day02 ├── day02.test └── day02.py ├── day04 ├── day04.test ├── .gitignore ├── Package.swift ├── Sources │ └── main.swift └── day04.mod ├── day06 ├── day06.test └── day06.krk ├── day07 ├── day07.test └── day07.py ├── day05 ├── day05.test └── day05.lua ├── README.md └── COPYING /day01/day01.test: -------------------------------------------------------------------------------- 1 | 3 4 2 | 4 3 3 | 2 5 4 | 1 3 5 | 3 9 6 | 3 3 7 | -------------------------------------------------------------------------------- /day03/day03a.test: -------------------------------------------------------------------------------- 1 | xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5)) 2 | -------------------------------------------------------------------------------- /day03/day03b.test: -------------------------------------------------------------------------------- 1 | xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5)) 2 | -------------------------------------------------------------------------------- /day02/day02.test: -------------------------------------------------------------------------------- 1 | 7 6 4 2 1 2 | 1 2 7 8 9 3 | 9 7 6 2 1 4 | 1 3 2 4 5 5 | 8 6 4 4 1 6 | 1 3 6 7 9 7 | -------------------------------------------------------------------------------- /day04/day04.test: -------------------------------------------------------------------------------- 1 | MMMSXXMASM 2 | MSAMXMSMSA 3 | AMXSXMAAMM 4 | MSAMASMSMX 5 | XMASAMXAMM 6 | XXAMMXXAMA 7 | SMSMSASXSS 8 | SAXAMASAAA 9 | MAMMMXMMMM 10 | MXMXAXMASX 11 | -------------------------------------------------------------------------------- /day06/day06.test: -------------------------------------------------------------------------------- 1 | ....#..... 2 | .........# 3 | .......... 4 | ..#....... 5 | .......#.. 6 | .......... 7 | .#..^..... 8 | ........#. 9 | #......... 10 | ......#... 11 | -------------------------------------------------------------------------------- /day07/day07.test: -------------------------------------------------------------------------------- 1 | 190: 10 19 2 | 3267: 81 40 27 3 | 83: 17 5 4 | 156: 15 6 5 | 7290: 6 8 6 15 6 | 161011: 16 10 13 7 | 192: 17 8 14 8 | 21037: 9 7 18 13 9 | 292: 11 6 16 20 10 | -------------------------------------------------------------------------------- /day04/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /day05/day05.test: -------------------------------------------------------------------------------- 1 | 47|53 2 | 97|13 3 | 97|61 4 | 97|47 5 | 75|29 6 | 61|13 7 | 75|53 8 | 29|13 9 | 97|29 10 | 53|29 11 | 61|53 12 | 97|53 13 | 61|29 14 | 47|13 15 | 75|47 16 | 97|75 17 | 47|61 18 | 75|61 19 | 47|29 20 | 75|13 21 | 53|13 22 | 23 | 75,47,61,53,29 24 | 97,61,53,29,13 25 | 75,29,13 26 | 75,97,47,61,53 27 | 61,13,29 28 | 97,13,75,29,47 29 | -------------------------------------------------------------------------------- /day04/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "day04", 8 | targets: [ 9 | // Targets are the basic building blocks of a package, defining a module or a test suite. 10 | // Targets can depend on other targets in this package and products from dependencies. 11 | .executableTarget( 12 | name: "day04"), 13 | ] 14 | ) 15 | -------------------------------------------------------------------------------- /day02/day02.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | from itertools import pairwise 6 | from functools import reduce 7 | 8 | def is_valid_down_step(valid, step): 9 | return valid and (-3 <= step < 0) 10 | 11 | def is_valid_up_step(valid, step): 12 | return valid and (0 < step <= 3) 13 | 14 | def is_valid_report(items): 15 | steps = map(lambda p: p[0] - p[1], pairwise(items)) 16 | first = next(steps) 17 | if first < 0: 18 | return reduce(is_valid_down_step, steps, is_valid_down_step(True, first)) 19 | if first > 0: 20 | return reduce(is_valid_up_step, steps, is_valid_up_step(True, first)) 21 | return False 22 | 23 | if __name__ == "__main__": 24 | import sys 25 | nvalid = 0 26 | for line in sys.stdin.readlines(): 27 | steps = map(int, line.split()) 28 | if is_valid_report(steps): 29 | nvalid += 1 30 | print(nvalid) 31 | -------------------------------------------------------------------------------- /day07/day07.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # SPDX-License-Identifier: MIT 3 | 4 | from sys import stdin 5 | from operator import add, mul 6 | 7 | def cat(a: int, b: int) -> int: 8 | return int(f"{a:d}{b:d}") 9 | 10 | def solve(operators, val, eqn): 11 | if len(eqn) == 1: 12 | return eqn[0] == val 13 | 14 | for op in operators: 15 | t = op(eqn[0], eqn[1]) 16 | if solve(operators, val, (t,) + eqn[2:]): 17 | return True 18 | 19 | return False 20 | 21 | OPERATORS_PART1 = (add, mul) 22 | OPERATORS_PART2 = (add, mul, cat) 23 | 24 | result1 = 0 25 | result2 = 0 26 | for line in stdin.readlines(): 27 | testval, eqn = line.split(":", maxsplit=1) 28 | testval = int(testval) 29 | eqn = tuple(map(int, eqn.split())) 30 | if solve(OPERATORS_PART1, testval, eqn): 31 | result1 += testval 32 | if solve(OPERATORS_PART2, testval, eqn): 33 | result2 += testval 34 | 35 | print("Part 1:", result1) 36 | print("Part 2:", result2) 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | aoc2024 2 | ======= 3 | 4 | My solutions for [Advent of Code 2024](https://adventofcode.com/2024): 5 | 6 | - This year I am using whatever language feels appropriate for each task, or 7 | just the one I feel like trying out or using at each point—no rules! 8 | - Some days I *might* use something that compiles and runs on either an 9 | Amiga 1200 with a TF1260 accelerator, running AmigaOS 3.2.2; or on a 10 | Panasonic FS-A1WSX MSX2+, running MSX-DOS/Nextor. 11 | 12 | 13 | Languages Used 14 | -------------- 15 | 16 | - [Kuroko](https://kuroko-lang.github.io) (version 1.4.0). 17 | - [Lua](https://lua.org) (version 5.4). 18 | - [Python](https://python.org) (version 3.12). 19 | - [Swift](https://swift.org) (version 6.0.2). 20 | - Turbo Modula-2 for CP/M, running on MSX-DOS/Nextor. Development aided 21 | by [NTVCM](https://github.com/davidly/ntvcm). 22 | 23 | 24 | Licensing 25 | --------- 26 | 27 | Files in this repository without their own license header are distributed 28 | under the terms of the [MIT license](https://opensource.org/licenses/MIT). 29 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Adrian Perez de Castro 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /day05/day05.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- SPDX-License-Identifier: MIT 4 | -- 5 | 6 | local rule_re = [[^(%d+)|(%d+)$]] 7 | 8 | local rules = {} 9 | 10 | local function addrule(prev, next) 11 | local t = rules[prev] 12 | if not t then 13 | t = {} 14 | rules[prev] = t 15 | end 16 | t[#t + 1] = next 17 | end 18 | 19 | for line in io.lines() do 20 | if #line == 0 then 21 | break 22 | end 23 | local prev, next = line:match(rule_re) 24 | addrule(tonumber(prev), tonumber(next)) 25 | end 26 | 27 | local function valid_order(pages) 28 | local seen = {} 29 | for _, num in ipairs(pages) do 30 | local numsAfter = rules[num] or {} 31 | for _, numAfter in ipairs(numsAfter) do 32 | if seen[numAfter] then 33 | return false 34 | end 35 | end 36 | seen[num] = true 37 | end 38 | return true 39 | end 40 | 41 | local result = 0 42 | for line in io.lines() do 43 | local pages = {} 44 | for num in line:gmatch("(%d+),?") do 45 | pages[#pages + 1] = tonumber(num) 46 | end 47 | if valid_order(pages) then 48 | -- Add middle point page number 49 | result = result + pages[#pages // 2 + 1] 50 | end 51 | end 52 | print(result) 53 | -------------------------------------------------------------------------------- /day03/day03.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- 3 | -- SPDX-License-Identifier: MIT 4 | -- 5 | 6 | local mul_re = [[mul%((%d+),(%d+)%)]] 7 | 8 | local function calculate_muls(text) 9 | local result = 0 10 | for a, b in text:gmatch(mul_re) do 11 | result = result + tonumber(a) * tonumber(b) 12 | end 13 | return result 14 | end 15 | 16 | local op_do_str = [[do()]] 17 | local op_dont_str = [[don't()]] 18 | 19 | local function calculate_muls_do_dont(text) 20 | local result = 0 21 | local curpos = 1 22 | local textlen = #text 23 | local extracting = true 24 | while curpos <= textlen do 25 | if extracting then 26 | local b, e = text:find(op_dont_str, curpos, true) 27 | if b then 28 | extracting = false 29 | else 30 | b = textlen 31 | e = textlen 32 | end 33 | result = result + calculate_muls(text:sub(curpos, b - 1)) 34 | curpos = e + 1 35 | else 36 | local b, e = text:find(op_do_str, curpos, true) 37 | if b then 38 | extracting = true 39 | else 40 | b = textlen 41 | e = textlen 42 | end 43 | curpos = e + 1 44 | end 45 | end 46 | return result 47 | end 48 | 49 | local input = io.read("*a") 50 | print("Part 1: ", calculate_muls(input)) 51 | print("Part 2: ", calculate_muls_do_dont(input)) 52 | -------------------------------------------------------------------------------- /day01/day01.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | def parse(fd): 6 | a = [] 7 | b = [] 8 | for line in fd.readlines(): 9 | na, nb = map(int, line.split()) 10 | a.append(na) 11 | b.append(nb) 12 | return a, b 13 | 14 | def calc1(a, b): 15 | d = 0 16 | for na, nb in zip(a, b): 17 | d += abs(na - nb) 18 | return d 19 | 20 | def calc2(a, b): 21 | blen = len(b) 22 | alen = len(a) 23 | d = i = j = 0 24 | while i < alen: 25 | # Current element from the left column 26 | cur = a[i] 27 | 28 | # How many of current elements? 29 | ncur = 0 30 | while i < alen and cur == a[i]: 31 | ncur += 1 32 | i += 1 33 | 34 | # Current element cannot be found, go to the next. 35 | if j >= blen or cur < b[j]: 36 | continue 37 | 38 | # Skip ahead while we don't find the element on the right column. 39 | while j < blen and cur > b[j]: 40 | j += 1 41 | 42 | # Find how many times it's repeated in the right column. 43 | nreps = 0 44 | while j < blen and cur == b[j]: 45 | nreps += 1 46 | j += 1 47 | 48 | d += cur * ncur * nreps 49 | 50 | return d 51 | 52 | if __name__ == "__main__": 53 | import sys 54 | a, b = parse(sys.stdin) 55 | a.sort() 56 | b.sort() 57 | print("Part 1:", calc1(a, b)) 58 | print("Part 2:", calc2(a, b)) 59 | -------------------------------------------------------------------------------- /day06/day06.krk: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env kuroko 2 | # 3 | # SPDX-License-Identifier: MIT 4 | # 5 | 6 | from fileio import stdin 7 | 8 | let rows = 0 9 | let cols = 0 10 | let obstacles = set() 11 | let xstart = 0 12 | let ystart = 0 13 | 14 | for line in stdin.readlines(): 15 | line = line.strip() 16 | if cols != 0: 17 | assert cols == len(line) 18 | else: 19 | cols = len(line) 20 | for col, ch in enumerate(line): 21 | if ch == '#': 22 | obstacles.add((col, rows)) 23 | elif ch == '^': 24 | xstart = col 25 | ystart = rows 26 | rows += 1 27 | 28 | print("Map has", rows, "rows,", cols, "columns,", len(obstacles), "obstacles") 29 | print("Guard starts at row", ystart, "column", xstart) 30 | 31 | let turn = {'^':'>', '>':'v', 'v':'<', '<':'^'} 32 | 33 | def walk(checkloop=False): 34 | let visited = set() 35 | let visitedAndDir = set() 36 | let d = '^' 37 | let x = xstart 38 | let y = ystart 39 | 40 | while True: 41 | if checkloop and (x, y, d) in visitedAndDir: 42 | return visited, True 43 | 44 | visited.add((x, y)) 45 | visitedAndDir.add((x, y, d)) 46 | 47 | let nx = x 48 | let ny = y 49 | 50 | if d == '^': 51 | ny -= 1 52 | if ny < 0: 53 | break 54 | elif d == '<': 55 | nx -= 1 56 | if nx < 0: 57 | break 58 | elif d == '>': 59 | nx += 1 60 | if nx >= cols: 61 | break 62 | elif d == 'v': 63 | ny += 1 64 | if ny >= rows: 65 | break 66 | 67 | if (nx, ny) in obstacles: 68 | d = turn[d] 69 | continue 70 | 71 | x = nx 72 | y = ny 73 | 74 | return visited, False 75 | 76 | let numLoopObstacles = 0 77 | for y in range(rows): 78 | for x in range(cols): 79 | if (x, y) == (xstart, ystart): 80 | continue 81 | if (x, y) in obstacles: 82 | continue 83 | obstacles.add((x, y)) 84 | let _, looped = walk(True) 85 | if looped: 86 | numLoopObstacles += 1 87 | obstacles.remove((x, y)) 88 | 89 | 90 | print("Part 1:", len(walk()[0])) 91 | print("Part 2:", numLoopObstacles) 92 | -------------------------------------------------------------------------------- /day01/day01.mod: -------------------------------------------------------------------------------- 1 | (* 2 | * Build with Turbo Modula 2 for CP/M. 3 | * Tested on MSX-DOS/Nextor. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * vim:ft=modula2: 7 | *) 8 | 9 | MODULE Day01; 10 | 11 | FROM ComLine IMPORT commandLine; 12 | FROM Files IMPORT EndError; 13 | FROM Texts IMPORT TEXT, OpenText, CloseText, Done; 14 | 15 | CONST 16 | NumEntries = 1001; 17 | 18 | VAR 19 | f: TEXT; 20 | inputFileName: ARRAY [0..12] OF CHAR; 21 | a, b: ARRAY [0..NumEntries] OF LONGINT; 22 | n: LONGINT; 23 | i, j: CARDINAL; 24 | 25 | (* 26 | * Naïve, in place insertion sort. 27 | *) 28 | PROCEDURE Sort(VAR numbers: ARRAY OF LONGINT; size: CARDINAL); 29 | VAR 30 | i, j: CARDINAL; 31 | index: LONGINT; 32 | BEGIN 33 | FOR i := 2 TO size - 1 DO 34 | index := numbers[i]; 35 | j := i; 36 | IF i MOD 20 = 0 THEN 37 | Write('.'); 38 | END; 39 | WHILE (j > 1) AND (numbers[j - 1] > index) DO 40 | numbers[j] := numbers[j - 1]; 41 | DEC(j); 42 | END; 43 | numbers[j] := index; 44 | END; 45 | END Sort; 46 | 47 | PROCEDURE Parse; 48 | BEGIN 49 | i := 0; 50 | LOOP 51 | Read(f, n); 52 | IF Done(f) THEN 53 | a[i] := n; 54 | Read(f, n); 55 | IF NOT Done(f) THEN 56 | WriteLn('Could not read second number in the line'); 57 | HALT; 58 | END; 59 | b[i] := n; 60 | INC(i); 61 | IF i >= NumEntries THEN 62 | WriteLn('Tried to read more than ', NumEntries, ' entries'); 63 | HALT; 64 | END; 65 | IF i MOD 20 = 0 THEN 66 | Write('.'); 67 | END; 68 | END; 69 | END; 70 | EXCEPTION 71 | EndError: WriteLn(' ', i:0, ' entries'); 72 | END Parse; 73 | 74 | BEGIN 75 | Read(commandLine, inputFileName); 76 | IF inputFileName = '' THEN 77 | WriteLn('No input file specified'); 78 | HALT; 79 | END; 80 | IF NOT OpenText(f, inputFileName) THEN 81 | WriteLn('Could not open "', inputFileName, '"'); 82 | HALT; 83 | END; 84 | Write('Reading.'); 85 | Parse; 86 | CloseText(f); 87 | 88 | Write('Sorting A'); 89 | Sort(a, i); WriteLn(' Done.'); 90 | Write('Sorting B'); 91 | Sort(b, i); WriteLn(' Done.'); 92 | 93 | Write('Mulling.'); 94 | n := 0L; 95 | FOR j := 0 TO i - 1 DO 96 | n := n + ABS(a[j] - b[j]); 97 | IF j MOD 20 = 0 THEN 98 | Write('.'); 99 | END; 100 | END; 101 | WriteLn(' ', n:0); 102 | END Day01. 103 | -------------------------------------------------------------------------------- /day04/Sources/main.swift: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | var board: [[UInt8]] = [] 4 | 5 | while let line = readLine(strippingNewline: true) { 6 | if line.isEmpty { 7 | break 8 | } 9 | board.append(Array(line.utf8)) 10 | } 11 | 12 | let rows = board.count 13 | let cols = board[0].count 14 | print("Board size: \(rows)x\(cols)") 15 | 16 | let directions = [ 17 | ( 1, 0), // Right 18 | (-1, 0), // Left 19 | ( 0, 1), // Down 20 | ( 0, -1), // Up 21 | ( 1, 1), // Right-Down 22 | (-1, 1), // Left-Down 23 | ( 1, -1), // Right-Up 24 | (-1, -1), // Left-Up 25 | ] 26 | 27 | let asciiX = UInt8(ascii: "X") 28 | let asciiM = UInt8(ascii: "M") 29 | let asciiA = UInt8(ascii: "A") 30 | let asciiS = UInt8(ascii: "S") 31 | 32 | let XMAS: [UInt8] = [ 33 | asciiX, 34 | asciiM, 35 | asciiA, 36 | asciiS, 37 | ] 38 | 39 | @MainActor 40 | func isXMAS(position: (Int, Int), step: (Int, Int)) -> Bool 41 | { 42 | let (col, row) = position 43 | let (sx, sy) = step 44 | 45 | for (di, letter) in XMAS.enumerated() { 46 | let x = col + (di * sx) 47 | let y = row + (di * sy) 48 | 49 | if x < 0 || y < 0 || x >= cols || y >= rows || board[y][x] != letter { 50 | return false 51 | } 52 | } 53 | 54 | return true 55 | } 56 | 57 | // S.M 58 | // .A. 59 | // S.M 60 | let SM_SM = [asciiS, asciiM, asciiS, asciiM] 61 | 62 | // M.S 63 | // .A. 64 | // M.S 65 | let MS_MS = [asciiM, asciiS, asciiM, asciiS] 66 | 67 | // S.S 68 | // .A. 69 | // M.M 70 | let SS_MM = [asciiS, asciiS, asciiM, asciiM] 71 | 72 | // M.M 73 | // .A. 74 | // S.S 75 | let MM_SS = [asciiM, asciiM, asciiS, asciiS] 76 | 77 | let CrossMASCombinations = [SM_SM, MS_MS, SS_MM, MM_SS] 78 | 79 | 80 | @MainActor 81 | func isCrossMAS(position: (Int, Int)) -> Bool 82 | { 83 | let (col, row) = position 84 | 85 | if col < 1 || row < 1 || col >= (cols - 1) || row >= (rows - 1) { 86 | return false 87 | } 88 | 89 | // There must be an "A" always in the middle 90 | if board[row][col] != asciiA { 91 | return false 92 | } 93 | 94 | let thisCombo = [board[row-1][col-1], board[row-1][col+1], 95 | board[row+1][col-1], board[row+1][col+1]] 96 | 97 | for combo in CrossMASCombinations { 98 | if thisCombo == combo { 99 | return true 100 | } 101 | } 102 | 103 | return false 104 | } 105 | 106 | var numXMAS = 0 107 | var numCrossMAS = 0 108 | for row in 0...board.count-1 { 109 | assert(cols == board[row].count) 110 | for col in 0...cols-1 { 111 | for directionStep in directions { 112 | if isXMAS(position: (col, row), step: directionStep) { 113 | numXMAS += 1 114 | } 115 | } 116 | if isCrossMAS(position: (col, row)) { 117 | numCrossMAS += 1 118 | } 119 | } 120 | } 121 | 122 | print("Part 1: \(numXMAS)") 123 | print("Part 2: \(numCrossMAS)") 124 | -------------------------------------------------------------------------------- /day04/day04.mod: -------------------------------------------------------------------------------- 1 | (* 2 | * Build with Turbo Modula 2 for CP/M. 3 | * Tested on MSX-DOS/Nextor. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * vim:ft=modula2: 7 | *) 8 | 9 | MODULE Day04; 10 | 11 | FROM ComLine IMPORT commandLine; 12 | FROM Texts IMPORT TEXT, OpenText, CloseText, Done; 13 | 14 | TYPE 15 | Directions = (Right, Left, Down, Up, RightDown, LeftDown, RightUp, LeftUp); 16 | 17 | CONST 18 | NumRows = 150; 19 | NumCols = 150; 20 | 21 | VAR 22 | inputFileName: ARRAY [0..15] OF CHAR; 23 | result: CARDINAL; 24 | nRows, nCols: CARDINAL; 25 | row, col: CARDINAL; 26 | sx, sy: INTEGER; 27 | d: Directions; 28 | board: ARRAY [0..NumRows],[0..NumCols] OF CHAR; 29 | f: TEXT; 30 | XMAS: ARRAY [0..3] OF CHAR; 31 | 32 | PROCEDURE StepX(d: Directions): INTEGER; 33 | BEGIN 34 | CASE d OF 35 | | Right: RETURN 1 36 | | Left: RETURN -1 37 | | RightDown: RETURN 1 38 | | LeftDown: RETURN -1 39 | | RightUp: RETURN 1 40 | | LeftUp: RETURN -1 41 | ELSE 42 | RETURN 0; 43 | END; 44 | END StepX; 45 | 46 | PROCEDURE StepY(d: Directions): INTEGER; 47 | BEGIN 48 | CASE d OF 49 | | Down: RETURN 1 50 | | Up: RETURN -1 51 | | RightDown: RETURN 1 52 | | LeftDown: RETURN 1 53 | | RightUp: RETURN -1 54 | | LeftUp: RETURN -1 55 | ELSE 56 | RETURN 0; 57 | END; 58 | END StepY; 59 | 60 | PROCEDURE Parse; 61 | VAR 62 | ch: CHAR; 63 | col: CARDINAL; 64 | BEGIN 65 | nRows := 0; 66 | col := 0; 67 | LOOP 68 | Read(f, ch); 69 | 70 | IF ch = CHR(26) THEN 71 | EXIT; 72 | END; 73 | 74 | IF ch = CHR(10) THEN 75 | IF nCols = 0 THEN 76 | nCols := col; 77 | ELSIF nCols <> col THEN 78 | WriteLn; 79 | WriteLn('Expected ', nCols:0, ' columns, got ', col:0); 80 | HALT; 81 | END; 82 | col := 0; 83 | INC(nRows); 84 | IF nRows > NumRows THEN 85 | WriteLn; 86 | WriteLn('Tried to read more than ', NumRows:0, ' lines'); 87 | HALT; 88 | END; 89 | IF nRows MOD 10 = 0 THEN 90 | Write('.'); 91 | END; 92 | ELSE 93 | IF col >= NumCols THEN 94 | WriteLn; 95 | WriteLn('Tried to read more than ', NumCols:0, ' columns'); 96 | END; 97 | board[nRows][col] := ch; 98 | INC(col); 99 | END 100 | END; 101 | WriteLn(' ', nRows:0, 'x', nCols:0, ' entries'); 102 | END Parse; 103 | 104 | PROCEDURE isXMAS(row: CARDINAL; col: CARDINAL; sx: INTEGER; sy: INTEGER): BOOLEAN; 105 | VAR 106 | di: INTEGER; 107 | letter: CHAR; 108 | x, y: INTEGER; 109 | BEGIN 110 | FOR di := 0 TO 3 DO 111 | letter := XMAS[di]; 112 | x := (di * sx); 113 | y := (di * sy); 114 | INC(x, col); 115 | INC(y, row); 116 | 117 | IF (x < 0) OR (y < 0) THEN RETURN FALSE END; 118 | IF (x >= INT(nCols)) THEN RETURN FALSE END; 119 | IF (y >= INT(nRows)) THEN RETURN FALSE END; 120 | IF (board[y][x] <> letter) THEN RETURN FALSE END; 121 | END; 122 | RETURN TRUE; 123 | END isXMAS; 124 | 125 | BEGIN 126 | Read(commandLine, inputFileName); 127 | IF inputFileName = '' THEN 128 | WriteLn('No input file specified'); 129 | HALT; 130 | END; 131 | IF NOT OpenText(f, inputFileName) THEN 132 | WriteLn('Could not open "', inputFileName, '"'); 133 | HALT; 134 | END; 135 | Write('Reading.'); 136 | Parse; 137 | CloseText(f); 138 | 139 | XMAS[0] := 'X'; 140 | XMAS[1] := 'M'; 141 | XMAS[2] := 'A'; 142 | XMAS[3] := 'S'; 143 | 144 | Write('Mulling.'); 145 | result := 0; 146 | FOR row := 0 TO nRows - 1 DO 147 | IF row MOD 10 = 0 THEN Write('.') END; 148 | FOR col := 0 TO nCols - 1 DO 149 | FOR d := MIN(Directions) TO MAX(Directions) DO 150 | sx := StepX(d); 151 | sy := StepY(d); 152 | IF isXMAS(row, col, sx, sy) THEN 153 | INC(result); 154 | END; 155 | END; 156 | END; 157 | END; 158 | WriteLn(' ', result:0); 159 | END Day04. 160 | --------------------------------------------------------------------------------