diff --git a/day24_point_as_identifier.py b/day24_point_as_identifier.py new file mode 100644 index 0000000..5b0b323 --- /dev/null +++ b/day24_point_as_identifier.py @@ -0,0 +1,93 @@ +from collections import Counter +import time +# import operator + + +def read_moves(): + with open('day24/input') as reader: + return reader.read().splitlines() + + +def split_move(move): + split_moves = [] + cur = '' + for c in move: + if cur == '' and c in ('e', 'w'): + split_moves.append(c) + elif c in ('n', 's'): + cur = c + else: + split_moves.append(cur + c) + cur = '' + return split_moves + + +move_set = {'e': (2, 0), 'w': (-2, 0), 'ne': (1, 1), 'nw': (-1, 1), 'se': (1, -1), 'sw': (-1, -1)} + + +def add_move(a, b): + return a[0]+b[0], a[1]+b[1] + # return tuple(map(sum, zip(a, b))) + # return tuple(map(operator.add, a, b)) + + +def reduce_moves(move): + tile = (0, 0) + for m in move: + tile = add_move(tile, move_set[m]) + return tile + + +moves = read_moves() +split_moves = map(split_move, moves) +reduced_moves = map(reduce_moves, split_moves) + +tile_count = Counter(reduced_moves) + +black_tiles = [tile for tile, amount in tile_count.items() if amount % 2 == 1] + +print(len(black_tiles)) + + +# part2 +def black_needs_to_turn_white(adjacents, current_black): + black_adjacent = adjacents.intersection(current_black) + return len(black_adjacent) == 0 or len(black_adjacent) > 2 + + +def white_needs_to_turn_black(white, current_black): + adjacent_to_white = get_adjacents(white) + blacks_adjacent_to_white = adjacent_to_white.intersection(current_black) + return len(blacks_adjacent_to_white) == 2 + + +def get_adjacents(current): + adjacents = set() + for m in move_set.values(): + adjacents.add(add_move(current, m)) + return adjacents + + +start = time.time() +previous_black = set(black_tiles) +for i in range(100): + black_next = set() + already_checked = set(previous_black) + + for black in previous_black: + adjacents = get_adjacents(black) + if not black_needs_to_turn_white(adjacents, previous_black): + black_next.add(black) + + for a in adjacents: + if a not in already_checked: + already_checked.add(a) + if white_needs_to_turn_black(a, previous_black): + black_next.add(a) + + if i == 99: + print("Day {}: {}".format(str(i+1), len(black_next))) + previous_black = black_next + +end = time.time() +print(end - start) diff --git a/day24_string_as_identifier.py b/day24_string_as_identifier.py new file mode 100644 index 0000000..7e7ee4a --- /dev/null +++ b/day24_string_as_identifier.py @@ -0,0 +1,126 @@ +from collections import Counter +import time + + +def read_moves(): + with open('day24/input') as reader: + return reader.read().splitlines() + + +def split_move(move): + split_moves = [] + cur = '' + for c in move: + if cur == '' and c in ('e', 'w'): + split_moves.append(c) + elif c in ('n', 's'): + cur = c + else: + split_moves.append(cur + c) + cur = '' + return split_moves + + +all_possibilities = ['e', 'w', 'ne', 'nw', 'se', 'sw'] +simplify_move1 = [('ne', 'se', 'e'), ('nw', 'sw', 'w')] +simplify_move2 = [ + ('w', 'ne', 'nw'), ('w', 'se', 'sw'), + ('e', 'nw', 'ne'), ('e', 'sw', 'se') + ] +opposite_moves = [('e', 'w'), ('se', 'nw'), ('sw', 'ne')] + + +def add_empty(move_count): + for p in all_possibilities: + if p not in move_count: + move_count[p] = 0 + return move_count + + +def simplify_moves(move_count, simplify): + first, second, res = simplify + number_to_simplify = min(move_count[first], move_count[second]) + move_count[first] -= number_to_simplify + move_count[second] -= number_to_simplify + move_count[res] += number_to_simplify + return move_count + + +def reduce_opposite_move(move_count, opposite): + first, second = opposite + if move_count[first] > move_count[second]: + move_count[first] = move_count[first] - move_count[second] + move_count[second] = 0 + else: + move_count[second] = move_count[second] - move_count[first] + move_count[first] = 0 + return move_count + + +def produce_unique_move(move_count): + m = '' + for p in all_possibilities: + if move_count[p] > 0: + m += p * move_count[p] + return m + + +def reduce_moves(move): + global opposite_moves + move_count = Counter(move) + move_count = add_empty(move_count) + for o in opposite_moves: + move_count = reduce_opposite_move(move_count, o) + for s in simplify_move1: + move_count = simplify_moves(move_count, s) + for o in opposite_moves: + move_count = reduce_opposite_move(move_count, o) + for s in simplify_move2: + move_count = simplify_moves(move_count, s) + for o in opposite_moves: + move_count = reduce_opposite_move(move_count, o) + return produce_unique_move(move_count) + + +moves = read_moves() + +split_moves = list(map(split_move, moves)) + +unique_move_count = Counter(map(reduce_moves, split_moves)) +res = sum([v % 2 for v in unique_move_count.values()]) + +print(res) + + +def black_needs_to_turn_white(adjacents, current_black): + black_adjacents = adjacents.intersection(current_black) + return len(black_adjacents) == 0 or len(black_adjacents) > 2 + + +def white_needs_to_turn_black(white, current_black): + adjecent_to_white = set(map(lambda p: reduce_moves(split_move(white + p)), all_possibilities)) + blacks_adjecent_to_white = adjecent_to_white.intersection(current_black) + return len(blacks_adjecent_to_white) == 2 + +start = time.time() +previous_black = set([key for key, value in unique_move_count.items() if value % 2 == 1]) +for i in range(100): + black_next = set() + already_checked = set(previous_black) + + for black in previous_black: + adjacents = set(map(lambda p: reduce_moves(split_move(black + p)), all_possibilities)) + if not black_needs_to_turn_white(adjacents, previous_black): + black_next.add(black) + + for a in adjacents: + if a not in already_checked: + already_checked.add(a) + if white_needs_to_turn_black(a, previous_black): + black_next.add(a) + + print("Day {}: {}".format(str(i+1), len(black_next))) + previous_black = black_next + +end = time.time() +print(end - start)