def read_grid(filename): with open(filename, 'r') as f: return [line.strip() for line in f.readlines()] def get_word_at(grid, x, y, dx, dy, length): if not (0 <= x + (length-1)*dx < len(grid[0]) and 0 <= y + (length-1)*dy < len(grid)): return "" return ''.join(grid[y + i*dy][x + i*dx] for i in range(length)) def count_xmas(grid): directions = [ (1,0), (0,1), (1,1), (-1,1), # right, down, diagonal-right, diagonal-left (-1,0), (0,-1), (-1,-1), (1,-1) # left, up, diagonal-left-up, diagonal-right-up ] count = 0 for y in range(len(grid)): for x in range(len(grid[0])): for dx, dy in directions: if get_word_at(grid, x, y, dx, dy, 4) == "XMAS": count += 1 return count def check_xmas_pattern(grid, x, y): # Check both diagonals for MAS or SAM patterns = 0 diagonals = [ [(x-1, y-1), (x, y), (x+1, y+1)], # top-left to bottom-right [(x+1, y-1), (x, y), (x-1, y+1)] # top-right to bottom-left ] def is_valid_pos(pos): return 0 <= pos[0] < len(grid[0]) and 0 <= pos[1] < len(grid) def get_string(positions): if not all(is_valid_pos(pos) for pos in positions): return "" return ''.join(grid[y][x] for x, y in positions) for d1 in diagonals: for d2 in diagonals: if d1 == d2: continue s1 = get_string(d1) s2 = get_string(d2) if ((s1 == "MAS" or s1 == "SAM") and (s2 == "MAS" or s2 == "SAM")): patterns += 1 return patterns // 2 # Each valid pattern is counted twice due to diagonal combinations def count_xmas_patterns(grid): total = 0 for y in range(len(grid)): for x in range(len(grid[0])): total += check_xmas_pattern(grid, x, y) return total # Read input and solve both parts grid = read_grid("input.txt") # Part 1 print(str(count_xmas(grid))) # Part 2 print(str(count_xmas_patterns(grid)))