def iterate(grid, use_surroundings): threshold = 4 if use_surroundings else 5 changed = False copy = [[None] * len(grid[0]) for _ in range(len(grid))] for row in range(len(grid)): for col in range(len(grid[0])): # Use one of our two counting functions if use_surroundings: count = count_surrounding(grid, row, col) else: count = count_visibility(grid, row, col) if grid[row][col] == '.': copy[row][col] = '.' elif grid[row][col] == 'L': if count == 0: copy[row][col] = '#' changed = True else: copy[row][col] = 'L' elif grid[row][col] == '#': if count >= threshold: copy[row][col] = 'L' changed = True else: copy[row][col] = '#' else: log(f'PROBLEM CHARACTER: {grid[row][col]}') return copy, changed
def part_1(): x, y, dir = 0, 0, 'E' log(f"({x}, {y}, {dir})") for instr_str in get_strings_by_lines('12.txt'): x, y, dir = handle_instruction(x, y, dir, instr_str) log(f"({x}, {y}, {dir})") return abs(x) + abs(y)
def part_2(): x, y, wx, wy = 0, 0, 10, 1 log(f"({x}, {y}), ({wx}, {wy})") for instr_str in get_strings_by_lines('12.txt'): x, y, wx, wy = handle_instruction_with_waypoint( x, y, wx, wy, instr_str) log(f"({x}, {y}), ({wx}, {wy})") return abs(x) + abs(y)
def onScreensaverActivated(self): if __addon__.getSetting("at_ss_start") == "true": delay = int(__addon__.getSetting("at_ss_start_delay")) log("Screensaver activated, scheduling projector shutdown") self._ss_activation_timer_ = threading.Timer( delay, lib.commands.stop) self._last_power_command_ = datetime.datetime.now( ) + datetime.timedelta(seconds=delay) self._ss_activation_timer_.start()
def count_trees(rows, slope): dx, dy = slope x = 0 tree_count = 0 for y in range(0, len(rows), dy): log(f"coordinate: ({x}, {y}) Tree: {rows[y][x]}") tree_count += 1 if rows[y][x] == "#" else 0 x = (x + dx) % len(rows[0]) return tree_count
def part_1(): groups = get_input('6.txt').split('\n\n') grouped_people = [group.split('\n') for group in groups] count = 0 for group in grouped_people: pset = ''.join(set(''.join(group))) log(pset) count += len(pset) return count
def part_1(): earliest, bus_list = get_strings_by_lines('13.txt') current_time = int(earliest) busses = [ int(bus) for bus in bus_list.split(',') if bus and bus != 'x'] while True: log(f'Testing: {current_time}') for bus in busses: if current_time % bus == 0: log('FOUND IT') return (current_time - int(earliest)) * bus current_time += 1
def part_2(): input_arr = get_ints_by_lines('1.txt') for x in range(0, len(input_arr)): for y in range(x + 1, len(input_arr)): for z in range(y + 1, len(input_arr)): val1, val2, val3 = input_arr[x], input_arr[y], input_arr[z] if val1 + val2 + val3 == 2020: log(f"{val1} + {val2} + {val3} = {val1 + val2 + val3}") return val1 * val2 * val3 log('No solution')
def part_1(): input_arr = get_ints_by_lines('1.txt') # Loop through every pair in the array for x in range(0, len(input_arr)): for y in range(x + 1, len(input_arr)): val1, val2 = input_arr[x], input_arr[y] if val1 + val2 == 2020: log(f"{val1} + {val2} = {val1 + val2} (returning {val1 * val2})" ) return val1 * val2 log('No solution')
def part_2(): grid = [[char for char in line] for line in get_strings_by_lines('11.txt')] changed = True iterations = 0 print_grid(grid) while changed: grid, changed = iterate(grid, False) iterations += 1 log(f"iterated {iterations} times") print_grid(grid) return count_grid(grid)
def part_1(): jolts = [0] + sorted(get_ints_by_lines('10.txt')) jolts += [jolts[-1] + 3] log(jolts) diffs = [0, 0, 0, 0] for idx in range(1, len(jolts)): d = jolts[idx] - jolts[idx - 1] diffs[d] += 1 log(diffs) return diffs[1] * diffs[3]
def part_2(): instructions = get_strings_by_lines('8.txt') for idx in range(len(instructions)): # Copy the instructions copy = [] + instructions log(f'trying flipping instruction {idx}') if instructions[idx][:3] == 'jmp': copy[idx] = 'nop' + instructions[idx][3:] elif instructions[idx][:3] == 'nop': copy[idx] = 'jmp' + instructions[idx][3:] else: log('skipping instr: ' + instructions[idx]) acc, pointer = 0, 0 already_run = set() while pointer not in already_run: instr = copy[pointer] already_run.add(pointer) acc, pointer = run_instr(instr, acc, pointer) if pointer == len(instructions): log(f'found it flipping idx {idx}') return acc log('Failed idx {idx}') return None
def set_register(memory, address, value, and_mask, or_mask): log(f'value: {format(value, "036b")}') log(f'and_mask: {format(and_mask, "036b")}') log(f'or_mask: {format(or_mask, "036b")}') log(f'result: {format(((value & and_mask) | or_mask), "036b")}') memory[address] = (value & and_mask) | or_mask return memory
def part_1(): instructions = get_strings_by_lines('14.txt') memory = {} and_mask, or_mask = 0, 0 for inst in instructions: if inst[:4] == 'mask': (new_mask, ) = parse('mask = {}', inst) and_mask, or_mask = set_bitmask(new_mask) else: address, value = parse('mem[{:d}] = {:d}', inst) memory = set_register(memory, address, value, and_mask, or_mask) log(memory) return sum(memory.values())
def part_2(): instructions = get_strings_by_lines('14.txt') memory = {} mask = '' for inst in instructions: if inst[:4] == 'mask': (mask, ) = parse('mask = {}', inst) log(f"set mask to {mask}") else: address, value = parse('mem[{:d}] = {:d}', inst) memory = write_value_to_decoded_registers(memory, address, mask, value) log(memory) return sum(memory.values())
def part_2(): boarding_passes = get_strings_by_lines('5.txt') ids = [] for bp in boarding_passes: row = bin_search(127, bp[:7]) col = bin_search(8, bp[7:]) ids += [(row * 8) + col] ids.sort() log(ids) for idx in range(1, len(ids)): # Did we skip a number? if ids[idx] - ids[idx - 1] != 1: return ids[idx] - 1 # Return the skipped number return None
def part_2(): rows = get_strings_by_lines('3.txt') x = 0 tree_counts = [ count_trees(rows, slope) for slope in [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)] ] log(tree_counts) # return functools.reduce(lambda x, y: x*y, tree_counts) # Yeah, Robin, I know how to reduce stuff too product = 1 for count in tree_counts: product *= count return product
def part_1(): parse_tree() root = tree['shiny gold'] possible_containers = set() queue = [] + list(root.parents) while len(queue) != 0: log(queue) curr_str = queue.pop(0) curr_node = tree[curr_str] possible_containers.add(curr_str) for parent in list(curr_node.parents): if parent not in possible_containers: queue.append(parent) return len(list(possible_containers))
def part_2(): code = get_ints_by_lines('9.txt') goal = part_1() for idx in range(len(code)): list = [] sub_idx = idx total = 0 while total < goal and sub_idx < len(code): total += code[sub_idx] list += [code[sub_idx]] sub_idx += 1 if total == goal: log('FOUND IT') log(list) return min(list) + max(list) return None
def handle_instruction(x, y, dir, instr_str): instr, amount = instr_str[0], int(instr_str[1:]) log(instr) log(amount) if instr == 'E': x += amount elif instr == 'N': y += amount elif instr == 'W': x -= amount elif instr == 'S': y -= amount elif instr == 'R': dir = rotate(dir, amount) elif instr == 'L': dir = rotate(dir, -1 * amount) elif instr == 'F': x, y, dir = handle_instruction(x, y, dir, dir + str(amount)) return x, y, dir
def part_2(): earliest, bus_list = get_strings_by_lines('13.txt') busses = [ bus for bus in bus_list.split(',') if bus ] # Fulfill the constraints one at a time - Once you find a number satisfying # Two divisors, future values must be a multiple of that value. # AKA for divisors w,x,y,z the minimum value satisfying y must be # <the minimum value satisfying w,x> + (w * x) # And then the minimum value satisfying z must be # <the minimum value satisfying w,x,y> + (w * x * y) # ETC. current_time = 0 inc = 1 for idx in range(len(busses)): if busses[idx] == 'x': log(f'Skipping idx {idx}') continue curr_bus = int(busses[idx]) while (current_time + idx) % curr_bus != 0: current_time += inc log(f'constraint fulfilled! {curr_bus}') inc *= curr_bus log(f'New Inc: {inc}') return current_time
def _send_command(self, cmd_str): """Send command to the projector. :param cmd_str: Full raw command string to send to the projector """ ret = None try: self.serial.write("{}\r".format(cmd_str)) except OSError as e: raise lib.errors.ProjectorError( "Error when Sending command '{}' to projector: {}".\ format(cmd_str, e) ) return ret if cmd_str.endswith('?'): ret = self._read_response() while "=" not in ret and ret != 'ERR': ret = self._read_response() if ret == 'ERR': log("Projector responded with Error!") return None log("Command sent successfully") ret = ret.split('=', 1)[1] if ret == "01": ret = True elif ret == "00": ret = False elif ret in [ _valid_sources_[self.model][x] for x in _valid_sources_[self.model] ]: ret = [ x for x in _valid_sources_[self.model] if _valid_sources_[self.model][x] == ret ][0] return ret
def _read_response(self): """Read response from projector""" read = "" res = "" while not read.endswith(":"): r, w, x = select.select([self.serial.fileno()], [], [], self.timeout) if len(r) == 0: raise lib.errors.ProjectorError( "Timeout when reading response from projector") for f in r: try: read = os.read(f, 256) res += read except OSError as e: raise lib.errors.ProjectorError( "Error when reading response from projector: {}". format(e), ) return None part = res.split('\r', 1) log("projector responded: '{}'".format(part[0])) return part[0]
def send_command(self, command, **kwargs): """Send command to the projector. :param command: A valid command from lib :param **kwargs: Optional parameters to the command. For Epson the only valid keyword is "source_id" on CMD_SRC_SET. :return: True or False on CMD_PWR_QUERY, a source string on CMD_SRC_QUERY, otherwise None. """ if not command in _command_mapping_: raise lib.errors.InvalidCommandError( "Command {} not supported".format(command)) if command == lib.CMD_SRC_SET: cmd_str = _command_mapping_[command].format(**kwargs) else: cmd_str = _command_mapping_[command] log("sending command '{}'".format(cmd_str)) res = self._send_command(cmd_str) log("send_command returned {}".format(res)) return res
def in_preamble(search_arr, value): log(search_arr) log(value) for i in range(len(search_arr) - 1): for j in range(i + 1, len(search_arr)): if search_arr[i] + search_arr[j] == value: log(f'found: {search_arr[i]}, {search_arr[j]}') return True return False
def _read_response(self): """Read response from projector""" read = "" res = "" # Match either (PWR0) or (LMP?)(0-65535,2344) while not re.match('(\([^?]*\)|\(.*\?\)\([-0-9]*,[0-9]*\))', res): r, w, x = select.select([self.serial.fileno()], [], [], self.timeout) if len(r) == 0: raise lib.errors.ProjectorError( "Timeout when reading response from projector") for f in r: try: read = os.read(f, 256) res += read except OSError as e: raise lib.errors.ProjectorError( "Error when reading response from projector: {}". format(e), ) return None part = res.split('\n', 1) log("projector responded: '{}'".format(part[0])) return part[0]
def part_1(): code = get_ints_by_lines('9.txt') log(code) for idx in range(PREAMBLE_LEN, len(code)): log(f"checking {idx}") if not in_preamble(code[idx - PREAMBLE_LEN:idx], code[idx]): log(f"Found {code[idx]} at idx {idx}") return code[idx] return None
def onScreensaverDeactivated(self): if self._ss_activation_timer_: log("Screensaver deactivated, aborting any scheduled projector shutdown" ) self._ss_activation_timer_.cancel() if __addon__.getSetting("at_ss_shutdown") == "true": min_turnaround = int(__addon__.getSetting("min_turnaround")) time_since_stop = datetime.datetime.now( ) - self._last_power_command_ if time_since_stop.days == 0 and time_since_stop.seconds < min_turnaround: log("Screensaver deactivated too soon, will sleep a while before starting projector" ) xbmc.sleep((min_turnaround - time_since_stop.seconds) * 1000) log("Screensaver deactivated, starting projector") lib.commands.start()
def part_1(): input_arr = get_strings_by_lines('2.txt') valid_count = 0 # Loop through every pair in the array for input in input_arr: min, max, char, password = parse('{:d}-{:d} {:l}: {:w}', input) count = password.count(char) log(f"Testing {password} for {min} to {max} {char}'s") if min <= count <= max: log(f"\tYES") valid_count += 1 else: log(f"\tNO") return valid_count
def _send_command(self, cmd_str): """Send command to the projector. :param cmd_str: Full raw command string to send to the projector """ ret = None try: self.serial.write("{}\n".format(cmd_str)) except OSError as e: raise lib.errors.ProjectorError( "Error when Sending command '{}' to projector: {}".\ format(cmd_str, e) ) return ret ret = self._read_response() while ")" not in ret and ret != '?': ret = self._read_response() if ret == '?': log("Error, command not understood by projector!") return None log("Command sent successfully!") if cmd_str.endswith('?)'): r = re.match('\(.+\)\(([-\d]+),(\d+)\)', ret) ret = r.group(2) if cmd_str in _boolean_commands: if int(ret) == 1: ret = True elif int(ret) == 0: ret = False else: log("Error, unable to parse boolean value!") return None elif ret in [ _valid_sources_[self.model][x] for x in _valid_sources_[self.model] ]: ret = [ x for x in _valid_sources_[self.model] if _valid_sources_[self.model][x] == ret ][0] return ret else: return None