| @@ -0,0 +1,231 @@ | |||
| import logging | |||
| import random | |||
| import re | |||
| from enum import IntEnum | |||
| from sys import stdout | |||
| from typing import List, Tuple | |||
| # As the search for the Chief continues, a small Elf who lives on the | |||
| # station tugs on your shirt; she'd like to know if you could help her | |||
| # with her word search (your puzzle input). She only has to find one word: | |||
| # XMAS. | |||
| # This word search allows words to be horizontal, vertical, diagonal, | |||
| # written backwards, or even overlapping other words. It's a little unusual, | |||
| # though, as you don't merely need to find one instance of XMAS - you need to | |||
| # find all of them. | |||
| LOG_FILENAME = "./day04-1.log" | |||
| INPUT_FILENAME = "./input04.txt" | |||
| logger = logging.Logger(__name__) | |||
| formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s') | |||
| sh = logging.StreamHandler(stdout) | |||
| sh.setLevel(logging.INFO) | |||
| sh.setFormatter(formatter) | |||
| fh = logging.FileHandler(LOG_FILENAME, mode="w", encoding="utf-8") | |||
| fh.setLevel(logging.DEBUG) | |||
| fh.setFormatter(formatter) | |||
| logger.addHandler(sh) | |||
| logger.addHandler(fh) | |||
| class LetterValues(IntEnum): | |||
| X = 1 | |||
| M = 2 | |||
| A = 4 | |||
| S = 8 | |||
| def get_word_value(word): | |||
| total = 0 | |||
| for i, letter in enumerate(word): | |||
| total += ((3**i) * LetterValues[letter]) | |||
| return total | |||
| XMAS_VALUE = get_word_value("XMAS") | |||
| SAMX_VALUE = get_word_value("SAMX") | |||
| TEST_LINES = """MMMSXXMASM | |||
| MSAMXMSMSA | |||
| AMXSXMAAMM | |||
| MSAMASMSMX | |||
| XMASAMXAMM | |||
| XXAMMXXAMA | |||
| SMSMSASXSS | |||
| SAXAMASAAA | |||
| MAMMMXMMMM | |||
| MXMXAXMASX""" | |||
| class WSGrid: | |||
| def __init__(self, lines: List[List[str]], word: str, print_intermediate_grids: bool=False): | |||
| self.grid = [list(line) for line in lines] | |||
| self.width = len(self.grid[0]) | |||
| self.height = len(self.grid) | |||
| self.final_grid = [['.' for _ in range(self.width)] for _ in range(self.height)] | |||
| self.word = word | |||
| self.words_found = 0 | |||
| self.found_positions = [] | |||
| self.print_intermediate_grids = print_intermediate_grids | |||
| self.width | |||
| def add_found_position(self: object, position: Tuple[int,int], direction: str) -> None: | |||
| self.found_positions.append((position, direction)) | |||
| logger.info(f"Found a match for {self.word} at {position} going {direction}.") | |||
| if self.print_intermediate_grids: | |||
| print("\n".join(["".join(line) for line in self.final_grid])) | |||
| def search_east(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if (self.width - x) < len(self.word): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y][x+i] for i in range(4)]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.words_found += 1 | |||
| for i, char in enumerate(self.word): | |||
| self.final_grid[y][x+i] = char | |||
| self.add_found_position(position, "east") | |||
| return found_word == self.word | |||
| def search_west(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if x+1 < len(self.word): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y][x-i] for i in range(4)]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.words_found += 1 | |||
| for i, char in enumerate(self.word): | |||
| self.final_grid[y][x-i] = char | |||
| self.add_found_position(position, "west") | |||
| return True | |||
| return False | |||
| def search_south(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if (self.height - y) < len(self.word): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y+i][x] for i in range(4)]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.words_found += 1 | |||
| for i, char in enumerate(self.word): | |||
| self.final_grid[y+i][x] = char | |||
| self.add_found_position(position, "south") | |||
| return found_word == self.word | |||
| def search_north(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if y+1 < len(self.word): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y-i][x] for i in range(4)]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.words_found += 1 | |||
| for i, char in enumerate(self.word): | |||
| self.final_grid[y-i][x] = char | |||
| self.add_found_position(position, "north") | |||
| return found_word == self.word | |||
| def search_northwest(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if y+1 < len(self.word) or x+1 < len(self.word): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y-i][x-i] for i in range(4)]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.words_found += 1 | |||
| for i, char in enumerate(self.word): | |||
| self.final_grid[y-i][x-i] = char | |||
| self.add_found_position(position, "northwest") | |||
| return found_word == self.word | |||
| def search_northeast(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if y+1 < len(self.word) or (self.width - x) < len(self.word): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y-i][x+i] for i in range(4)]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.words_found += 1 | |||
| for i, char in enumerate(self.word): | |||
| self.final_grid[y-i][x+i] = char | |||
| self.add_found_position(position, "northeast") | |||
| return found_word == self.word | |||
| def search_southwest(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if (self.height - y)+1 < len(self.word) or x+1 < len(self.word): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y+i][x-i] for i in range(4)]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.words_found += 1 | |||
| for i, char in enumerate(self.word): | |||
| self.final_grid[y+i][x-i] = char | |||
| self.add_found_position(position, "southwest") | |||
| return found_word == self.word | |||
| def search_southeast(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if (self.height - y)+1 < len(self.word) or (self.width - x) < len(self.word): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y+i][x+i] for i in range(4)]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.words_found += 1 | |||
| for i, char in enumerate(self.word): | |||
| self.final_grid[y+i][x+i] = char | |||
| self.add_found_position(position, "southeast") | |||
| return found_word == self.word | |||
| def find_word_at_position(self: object, position: Tuple[int,int]) -> int: | |||
| return sum([ | |||
| 1 if self.search_north(position) else 0, | |||
| 1 if self.search_south(position) else 0, | |||
| 1 if self.search_east(position) else 0, | |||
| 1 if self.search_west(position) else 0, | |||
| 1 if self.search_northwest(position) else 0, | |||
| 1 if self.search_northeast(position) else 0, | |||
| 1 if self.search_southwest(position) else 0, | |||
| 1 if self.search_southeast(position) else 0 | |||
| ]) | |||
| def find_all_words(self: object) -> int: | |||
| for y in range(len(self.grid)): | |||
| for x in range(len(self.grid[0])): | |||
| self.words_found += self.find_word_at_position((x,y)) | |||
| return self.words_found | |||
| def main041(run_test=False, print_intermediate_grids=False, print_final_grid=False): | |||
| SEARCH_WORD = "XMAS" | |||
| if run_test: | |||
| lines = TEST_LINES.split("\n") | |||
| else: | |||
| with open("./input04.txt", "r", encoding="utf-8") as f: | |||
| lines = [l.strip() for l in f.readlines()] | |||
| finder = WSGrid(lines, SEARCH_WORD, print_intermediate_grids) | |||
| total_found = finder.find_all_words() | |||
| logger.info(f"Found {total_found} instances of {SEARCH_WORD}.") | |||
| if print_final_grid: | |||
| print("\n".join(["".join(line) for line in finder.final_grid])) | |||
| if __name__ == "__main__": | |||
| main041(run_test=False, print_intermediate_grids=False, print_final_grid=False) | |||
| @@ -0,0 +1,302 @@ | |||
| import logging | |||
| import random | |||
| import re | |||
| from enum import IntEnum | |||
| from sys import stdout | |||
| from typing import List, Tuple | |||
| # As the search for the Chief continues, a small Elf who lives on the | |||
| # station tugs on your shirt; she'd like to know if you could help her | |||
| # with her word search (your puzzle input). She only has to find one word: | |||
| # XMAS. | |||
| # This word search allows words to be horizontal, vertical, diagonal, | |||
| # written backwards, or even overlapping other words. It's a little unusual, | |||
| # though, as you don't merely need to find one instance of XMAS - you need to | |||
| # find all of them. | |||
| LOG_FILENAME = "./day04-1.log" | |||
| INPUT_FILENAME = "./input04.txt" | |||
| logger = logging.Logger(__name__) | |||
| formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s') | |||
| sh = logging.StreamHandler(stdout) | |||
| sh.setLevel(logging.INFO) | |||
| sh.setFormatter(formatter) | |||
| fh = logging.FileHandler(LOG_FILENAME, mode="w", encoding="utf-8") | |||
| fh.setLevel(logging.DEBUG) | |||
| fh.setFormatter(formatter) | |||
| logger.addHandler(sh) | |||
| logger.addHandler(fh) | |||
| class LetterValues(IntEnum): | |||
| X = 1 | |||
| M = 2 | |||
| A = 4 | |||
| S = 8 | |||
| def get_word_value(word): | |||
| total = 0 | |||
| for i, letter in enumerate(word): | |||
| total += ((3**i) * LetterValues[letter]) | |||
| return total | |||
| XMAS_VALUE = get_word_value("XMAS") | |||
| SAMX_VALUE = get_word_value("SAMX") | |||
| TEST_LINES = """MMMSXXMASM | |||
| MSAMXMSMSA | |||
| AMXSXMAAMM | |||
| MSAMASMSMX | |||
| XMASAMXAMM | |||
| XXAMMXXAMA | |||
| SMSMSASXSS | |||
| SAXAMASAAA | |||
| MAMMMXMMMM | |||
| MXMXAXMASX""" | |||
| class WSGrid: | |||
| def __init__(self, lines: List[List[str]], word: str, print_intermediate_grids: bool=False): | |||
| self.grid = [list(line) for line in lines] | |||
| self.width = len(self.grid[0]) | |||
| self.height = len(self.grid) | |||
| self.final_grid = [['.' for _ in range(self.width)] for _ in range(self.height)] | |||
| self.word = word | |||
| self.word_edges = (0-(len(self.word)//2), len(self.word)//2+1) | |||
| self.words_found = 0 | |||
| self.found_positions = [] | |||
| self.print_intermediate_grids = print_intermediate_grids | |||
| self.width | |||
| def add_found_position(self: object, position: Tuple[int,int], direction: str) -> None: | |||
| self.found_positions.append((position, direction)) | |||
| logger.info(f"Found a match for {self.word} at {position} going {direction}.") | |||
| if self.print_intermediate_grids: | |||
| print("\n".join(["".join(line) for line in self.final_grid])) | |||
| def check_edges(self: object, x: int, y: int) -> bool: | |||
| # x and y can never be along the edge; they have to be at least 1 away | |||
| return not ( | |||
| x > self.width-2 | |||
| or x < 1 | |||
| or y < 1 | |||
| or y > self.height-2 | |||
| ) | |||
| def search_east(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if not self.check_edges(x, y): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y][x+i] for i in range(self.word_edges[0],self.word_edges[1])]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.add_found_position(position, "east") | |||
| return found_word == self.word | |||
| def search_west(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if not self.check_edges(x, y): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y][x-i] for i in range(self.word_edges[0],self.word_edges[1])]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.add_found_position(position, "west") | |||
| return True | |||
| return False | |||
| def search_south(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if not self.check_edges(x, y): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y+i][x] for i in range(self.word_edges[0],self.word_edges[1])]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.add_found_position(position, "south") | |||
| return found_word == self.word | |||
| def search_north(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if not self.check_edges(x, y): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y-i][x] for i in range(self.word_edges[0],self.word_edges[1])]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.add_found_position(position, "north") | |||
| return found_word == self.word | |||
| def search_northwest(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if not self.check_edges(x, y): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y-i][x-i] for i in range(self.word_edges[0],self.word_edges[1])]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.add_found_position(position, "northwest") | |||
| return found_word == self.word | |||
| def search_northeast(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if not self.check_edges(x, y): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y-i][x+i] for i in range(self.word_edges[0],self.word_edges[1])]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.add_found_position(position, "northeast") | |||
| return found_word == self.word | |||
| def search_southwest(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if not self.check_edges(x, y): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y+i][x-i] for i in range(self.word_edges[0],self.word_edges[1])]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.add_found_position(position, "southwest") | |||
| return found_word == self.word | |||
| def search_southeast(self: object, position: Tuple[int,int]) -> bool: | |||
| x, y = position | |||
| if not self.check_edges(x, y): | |||
| return False | |||
| try: | |||
| found_word = "".join([self.grid[y+i][x+i] for i in range(self.word_edges[0],self.word_edges[1])]) | |||
| except IndexError: | |||
| return False | |||
| if found_word == self.word: | |||
| self.add_found_position(position, "southeast") | |||
| return found_word == self.word | |||
| def check_left(self: object, x: int, y: int, letter: str) -> bool: | |||
| return ( | |||
| self.grid[y-1][x-1] == letter | |||
| and self.grid[y+1][x-1] == letter | |||
| ) | |||
| def check_top(self: object, x: int, y: int, letter: str) -> bool: | |||
| return ( | |||
| self.grid[y-1][x-1] == letter | |||
| and self.grid[y-1][x+1] == letter | |||
| ) | |||
| def check_right(self: object, x: int, y: int, letter: str) -> bool: | |||
| return ( | |||
| self.grid[y-1][x+1] == letter | |||
| and self.grid[y+1][x+1] == letter | |||
| ) | |||
| def check_bottom(self: object, x: int, y: int, letter: str) -> bool: | |||
| return ( | |||
| self.grid[y+1][x-1] == letter | |||
| and self.grid[y+1][x+1] == letter | |||
| ) | |||
| def set_fg_mas(self: object, x: int, y: int, start_dir: str) -> bool: | |||
| def logit(): | |||
| logger.info(f"Found a match for {self.word} at {(x,y)} starting from the {start_dir}.") | |||
| match start_dir: | |||
| case "left": | |||
| self.final_grid[y][x] = "A" | |||
| self.final_grid[y-1][x-1] = "M" | |||
| self.final_grid[y+1][x-1] = "M" | |||
| self.final_grid[y-1][x+1] = "S" | |||
| self.final_grid[y+1][x+1] = "S" | |||
| logit() | |||
| case "top": | |||
| self.final_grid[y][x] = "A" | |||
| self.final_grid[y-1][x-1] = "M" | |||
| self.final_grid[y-1][x+1] = "M" | |||
| self.final_grid[y+1][x-1] = "S" | |||
| self.final_grid[y+1][x+1] = "S" | |||
| logit() | |||
| case "right": | |||
| self.final_grid[y][x] = "A" | |||
| self.final_grid[y-1][x+1] = "M" | |||
| self.final_grid[y+1][x+1] = "M" | |||
| self.final_grid[y-1][x-1] = "S" | |||
| self.final_grid[y+1][x-1] = "S" | |||
| logit() | |||
| case "bottom": | |||
| self.final_grid[y][x] = "A" | |||
| self.final_grid[y+1][x+1] = "M" | |||
| self.final_grid[y+1][x-1] = "M" | |||
| self.final_grid[y-1][x+1] = "S" | |||
| self.final_grid[y-1][x-1] = "S" | |||
| logit() | |||
| case _: | |||
| logger.warning(f"dir was not a valid value: {start_dir}") | |||
| if self.print_intermediate_grids: | |||
| print("\n".join(["".join(line) for line in self.final_grid])) | |||
| def find_word_at_position(self: object, position: Tuple[int,int]) -> int: | |||
| x, y = position | |||
| # fuck it | |||
| if self.grid[y][x] != "A": | |||
| return | |||
| if ( | |||
| self.check_left(x, y, "M") | |||
| and self.check_right(x, y, "S") | |||
| ): | |||
| self.words_found += 1 | |||
| self.set_fg_mas(x, y, "left") | |||
| if ( | |||
| self.check_right(x, y, "M") | |||
| and self.check_left(x, y, "S") | |||
| ): | |||
| self.words_found += 1 | |||
| self.set_fg_mas(x, y, "right") | |||
| if ( | |||
| self.check_top(x, y, "M") | |||
| and self.check_bottom(x, y, "S") | |||
| ): | |||
| self.words_found += 1 | |||
| self.set_fg_mas(x, y, "top") | |||
| if ( | |||
| self.check_bottom(x, y, "M") | |||
| and self.check_top(x, y, "S") | |||
| ): | |||
| self.words_found += 1 | |||
| self.set_fg_mas(x, y, "bottom") | |||
| def find_all_words(self: object) -> int: | |||
| for y in range(1,len(self.grid)-1): | |||
| for x in range(1,len(self.grid[0])-1): | |||
| self.find_word_at_position((x,y)) | |||
| return self.words_found | |||
| def main042(run_test=False, print_intermediate_grids=False, print_final_grid=False): | |||
| SEARCH_WORD = "MAS" | |||
| if run_test: | |||
| lines = TEST_LINES.split("\n") | |||
| else: | |||
| with open("./input04.txt", "r", encoding="utf-8") as f: | |||
| lines = [l.strip() for l in f.readlines()] | |||
| finder = WSGrid(lines, SEARCH_WORD, print_intermediate_grids) | |||
| total_found = finder.find_all_words() | |||
| logger.info(f"Found {total_found} instances of {SEARCH_WORD}.") | |||
| if print_final_grid: | |||
| print("\n".join(["".join(line) for line in finder.final_grid])) | |||
| if __name__ == "__main__": | |||
| main042( | |||
| run_test=False, | |||
| print_intermediate_grids=False, | |||
| print_final_grid=False | |||
| ) | |||
| @@ -0,0 +1,42 @@ | |||
| # The first section specifies the page ordering rules, one per line. | |||
| # The first rule, 47|53, means that if an update includes both | |||
| # page number 47 and page number 53, then page number 47 must be | |||
| # printed at some point before page number 53. (47 doesn't necessarily | |||
| # need to be immediately before 53; other pages are allowed to be | |||
| # between them.) | |||
| # The second section specifies the page numbers of each update. | |||
| # Because most safety manuals are different, the pages needed in the | |||
| # updates are different too. The first update, 75,47,61,53,29, means | |||
| # that the update consists of page numbers 75, 47, 61, 53, and 29. | |||
| def main051(): | |||
| with open("./input05.txt", "r", encoding="utf-8") as f: | |||
| lines = [l.strip() for l in f.readlines()] | |||
| rules = [] | |||
| updates = [] | |||
| for i, line in enumerate(lines): | |||
| if "|" not in line: | |||
| first_update = i + 1 | |||
| break | |||
| rules.append([int(x) for x in line.split("|")]) | |||
| for i, line in enumerate(lines[first_update:]): | |||
| updates.append([int(x) for x in line.split(",")]) | |||
| valid_updates = [] | |||
| total_vu = 0 | |||
| for u in updates: | |||
| relevant_rules = [r for r in rules if all([x in u for x in r])] | |||
| if all([u.index(rule[0]) < u.index(rule[1]) for rule in relevant_rules]): | |||
| valid_updates.append(u) | |||
| total_vu += u[(len(u)-1)//2] | |||
| print(total_vu) | |||
| if __name__ == "__main__": | |||
| main051() | |||
| @@ -0,0 +1,85 @@ | |||
| import logging | |||
| from sys import stdout | |||
| # The first section specifies the page ordering rules, one per line. | |||
| # The first rule, 47|53, means that if an update includes both | |||
| # page number 47 and page number 53, then page number 47 must be | |||
| # printed at some point before page number 53. (47 doesn't necessarily | |||
| # need to be immediately before 53; other pages are allowed to be | |||
| # between them.) | |||
| # The second section specifies the page numbers of each update. | |||
| # Because most safety manuals are different, the pages needed in the | |||
| # updates are different too. The first update, 75,47,61,53,29, means | |||
| # that the update consists of page numbers 75, 47, 61, 53, and 29. | |||
| # For each of the incorrectly-ordered updates, use the page ordering | |||
| # rules to put the page numbers in the right order. | |||
| # Find the updates which are not in the correct order. What do you get | |||
| # if you add up the middle page numbers after correctly ordering | |||
| # just those updates? | |||
| LOG_FILENAME = "./day04-1.log" | |||
| INPUT_FILENAME = "./input04.txt" | |||
| logger = logging.Logger(__name__) | |||
| formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s') | |||
| sh = logging.StreamHandler(stdout) | |||
| sh.setLevel(logging.INFO) | |||
| sh.setFormatter(formatter) | |||
| fh = logging.FileHandler(LOG_FILENAME, mode="w", encoding="utf-8") | |||
| fh.setLevel(logging.DEBUG) | |||
| fh.setFormatter(formatter) | |||
| logger.addHandler(sh) | |||
| logger.addHandler(fh) | |||
| def main052(): | |||
| with open("./input05.txt", "r", encoding="utf-8") as f: | |||
| lines = [l.strip() for l in f.readlines()] | |||
| rules = [] | |||
| updates = [] | |||
| for i, line in enumerate(lines): | |||
| if "|" not in line: | |||
| first_update = i + 1 | |||
| break | |||
| rules.append([int(x) for x in line.split("|")]) | |||
| for i, line in enumerate(lines[first_update:]): | |||
| updates.append([int(x) for x in line.split(",")]) | |||
| valid_updates = [] | |||
| invalid_updates = [] | |||
| new_invalid_updates = [] | |||
| total_vu = 0 | |||
| total_iu = 0 | |||
| for u in updates: | |||
| relevant_rules = [r for r in rules if all([x in u for x in r])] | |||
| all_valid = all([u.index(rule[0]) < u.index(rule[1]) for rule in relevant_rules]) | |||
| if all_valid: | |||
| valid_updates.append(u) | |||
| total_vu += u[(len(u)-1)//2] | |||
| else: | |||
| invalid_updates.append(u) | |||
| logger.info(f"Applying rules to {u}...") | |||
| while not all_valid: | |||
| logger.info(f"{u} still doesn't meet all the rules.") | |||
| for rule in relevant_rules: | |||
| i1 = u.index(rule[0]) | |||
| i2 = u.index(rule[1]) | |||
| if i1 > i2: | |||
| u[i1] = rule[1] | |||
| u[i2] = rule[0] | |||
| logger.info(f"Swapping {rule[0]} and {rule[1]}, u is now {u}.") | |||
| all_valid = all([u.index(rule[0]) < u.index(rule[1]) for rule in relevant_rules]) | |||
| new_invalid_updates.append(u) | |||
| middle_val = u[(len(u)-1)//2] | |||
| logger.info(f"Adding {middle_val} to {total_iu} to get {total_iu + middle_val}.") | |||
| total_iu += middle_val | |||
| print(total_vu) | |||
| logger.info(f"Total of invalid update centers is {total_iu}.") | |||
| if __name__ == "__main__": | |||
| main052() | |||