diff --git a/js/react-scrolling/package-lock.json b/js/react-scrolling/package-lock.json index 2d2a680..0a335f7 100644 --- a/js/react-scrolling/package-lock.json +++ b/js/react-scrolling/package-lock.json @@ -5591,7 +5591,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -5609,11 +5610,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5626,15 +5629,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5737,7 +5743,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5747,6 +5754,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5759,17 +5767,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5786,6 +5797,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5858,7 +5870,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5868,6 +5881,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5943,7 +5957,8 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -5973,6 +5988,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5990,6 +6006,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6028,11 +6045,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.2", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -13256,6 +13275,8 @@ }, "react-scripts": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-2.1.3.tgz", + "integrity": "sha512-JASD0QVVgSVleVhA9TeA+UBx+shq887hm/L+09qjZLrqIUvJZHZU+oOnhMFGot02Yop+LKfkvf9KSsTNlu/Rwg==", "requires": { "@babel/core": "7.1.6", "@svgr/webpack": "2.4.1", @@ -15400,9 +15421,9 @@ } }, "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" }, "to-arraybuffer": { "version": "1.0.1", diff --git a/js/react-scrolling/yarn.lock b/js/react-scrolling/yarn.lock index 0014d4b..b33b92a 100644 --- a/js/react-scrolling/yarn.lock +++ b/js/react-scrolling/yarn.lock @@ -6872,14 +6872,14 @@ react-dev-utils@^7.0.1: strip-ansi "4.0.0" text-table "0.2.0" -react-dom@16.7.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.7.0.tgz#a17b2a7ca89ee7390bc1ed5eb81783c7461748b8" +react-dom@^16.7.0: + version "16.14.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" - scheduler "^0.12.0" + scheduler "^0.19.1" react-error-overlay@^5.1.2: version "5.1.2" @@ -6939,14 +6939,13 @@ react-scripts@2.1.3: optionalDependencies: fsevents "1.2.4" -react@16.7.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.7.0.tgz#b674ec396b0a5715873b350446f7ea0802ab6381" +react@^16.7.0: + version "16.14.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" - scheduler "^0.12.0" read-pkg-up@^1.0.1: version "1.0.1" @@ -7346,9 +7345,9 @@ saxes@^3.1.4: dependencies: xmlchars "^1.3.1" -scheduler@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.12.0.tgz#8ab17699939c0aedc5a196a657743c496538647b" +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -7996,8 +7995,8 @@ tmp@^0.0.33: os-tmpdir "~1.0.2" tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" to-arraybuffer@^1.0.0: version "1.0.1" diff --git a/py/advent-of-code-2017/common/knot_hash.py b/py/advent-of-code-2017/common/knot_hash.py new file mode 100644 index 0000000..c3cf119 --- /dev/null +++ b/py/advent-of-code-2017/common/knot_hash.py @@ -0,0 +1,65 @@ +from functools import reduce +from operator import xor +from typing import Iterable, List + + +class Circle: + def __init__(self, values: Iterable[int]): + self.__values = list(values) + + def normalize_index(self, index: int) -> int: + return index % len(self.__values) + + def swap(self, i: int, j: int) -> None: + i = self.normalize_index(i) + j = self.normalize_index(j) + self.__values[i], self.__values[j] = self.__values[j], self.__values[i] + + def __getitem__(self, item: int) -> int: + return self.__values[self.normalize_index(item)] + + def __str__(self): + return str(self.__values) + + def values(self) -> List[int]: + return self.__values.copy() + + +def reverse(circle: Circle, start: int, length: int) -> None: + end = circle.normalize_index(start + length - 1) + for i in range(length // 2): + circle.swap(start + i, end - i) + + +def hash_round(circle: Circle, lengths: List[int], position: int = 0, skip: int = 0) -> tuple[int, int]: + for length in lengths: + reverse(circle, position, length) + position = circle.normalize_index(position + length + skip) + skip += 1 + return position, skip + + +def hash_blocks(values: List[int]) -> List[int]: + result = [0] * 16 + + for i in range(16): + start, end = i * 16, (i + 1) * 16 + result[i] = reduce(xor, values[start:end]) + + return result + + +def hexify(x: int) -> str: + hexed = hex(x)[2:] + return hexed if len(hexed) == 2 else '0' + hexed + + +def get_knot_hash(s: str) -> str: + circle = Circle(range(256)) + lengths = [ord(c) for c in s] + [17, 31, 73, 47, 23] + position, skip = 0, 0 + for _ in range(64): + position, skip = hash_round(circle, lengths, position, skip) + + hashed_blocks = hash_blocks(circle.values()) + return ''.join(map(hexify, hashed_blocks)) \ No newline at end of file diff --git a/py/advent-of-code-2017/day10.py b/py/advent-of-code-2017/day10.py index 3d119fa..422124c 100644 --- a/py/advent-of-code-2017/day10.py +++ b/py/advent-of-code-2017/day10.py @@ -1,42 +1,6 @@ -from typing import List, Iterable -from functools import reduce -from operator import xor +from typing import List - -class Circle: - def __init__(self, values: Iterable[int]): - self.__values = list(values) - - def normalize_index(self, index: int) -> int: - return index % len(self.__values) - - def swap(self, i: int, j: int) -> None: - i = self.normalize_index(i) - j = self.normalize_index(j) - self.__values[i], self.__values[j] = self.__values[j], self.__values[i] - - def __getitem__(self, item: int) -> int: - return self.__values[self.normalize_index(item)] - - def __str__(self): - return str(self.__values) - - def values(self) -> List[int]: - return self.__values.copy() - - -def reverse(circle: Circle, start: int, length: int) -> None: - end = circle.normalize_index(start + length - 1) - for i in range(length // 2): - circle.swap(start + i, end - i) - - -def hash_round(circle: Circle, lengths: List[int], position: int = 0, skip: int = 0) -> tuple[int, int]: - for length in lengths: - reverse(circle, position, length) - position = circle.normalize_index(position + length + skip) - skip += 1 - return position, skip +from common.knot_hash import Circle, hash_round, get_knot_hash def part1(circle: Circle, lengths: List[int]) -> int: @@ -44,30 +8,9 @@ def part1(circle: Circle, lengths: List[int]) -> int: return circle[0] * circle[1] -def hash_blocks(values: List[int]) -> List[int]: - result = [0] * 16 - - for i in range(16): - start, end = i * 16, (i + 1) * 16 - result[i] = reduce(xor, values[start:end]) - - return result - - -def hexify(x: int) -> str: - hexed = hex(x)[2:] - return hexed if len(hexed) == 2 else '0' + hexed - - -def part2(circle: Circle, lengths_string: str): - lengths = [ord(c) for c in lengths_string] + [17, 31, 73, 47, 23] - position, skip = 0, 0 - for _ in range(64): - position, skip = hash_round(circle, lengths, position, skip) - - hashed_blocks = hash_blocks(circle.values()) - return ''.join(map(hexify, hashed_blocks)) +def part2(lengths_string: str): + return get_knot_hash(lengths_string) print(part1(Circle(range(256)), [129, 154, 49, 198, 200, 133, 97, 254, 41, 6, 2, 1, 255, 0, 191, 108])) -print(part2(Circle(range(256)), '129,154,49,198,200,133,97,254,41,6,2,1,255,0,191,108')) +print(part2('129,154,49,198,200,133,97,254,41,6,2,1,255,0,191,108')) diff --git a/py/advent-of-code-2017/day14.py b/py/advent-of-code-2017/day14.py new file mode 100644 index 0000000..77480f7 --- /dev/null +++ b/py/advent-of-code-2017/day14.py @@ -0,0 +1,93 @@ +from typing import List, Generator +from common.knot_hash import get_knot_hash + + +SIZE = 128 + + +class DSU: + def __init__(self): + self.__parents = [] + + def create_new(self): + x = len(self.__parents) + self.__parents.append(x) + return x + + def root_of(self, x: int) -> int: + current = x + while self.__parents[current] != current: + current = self.__parents[current] + return current + + def merge(self, x: int, y: int) -> int: + y_root = self.root_of(y) + x_root = self.root_of(x) + if y_root != x_root: + self.__parents[y_root] = x_root + return x_root + + def disjoint_count(self): + count = 0 + for i in range(len(self.__parents)): + if self.__parents[i] == i: + count += 1 + return count + + def __str__(self): + return str(self.__parents) + + +def adjacent_before(i: int, j: int) -> Generator[tuple[int, int], None, None]: + if i > 0: + yield i - 1, j + if j > 0: + yield i, j - 1 + + +def get_row_binary(prefix: str, row: int) -> str: + s = f'{prefix}-{row}' + knot_hash = get_knot_hash(s) + return ''.join(format(x, '08b') for x in bytes.fromhex(knot_hash)) + + +def count_ones(s: str) -> int: + return len(list(filter(lambda c: c == '1', s))) + + +def create_grid(prefix: str) -> List[str]: + return [get_row_binary(prefix, row) for row in range(SIZE)] + + +def part1(grid: List[str]): + return sum(map(count_ones, grid)) + + +def part2(grid: List[str]): + components = [] + dsu = DSU() + for i in range(len(grid)): + components.append([-1] * SIZE) + for j in range(len(grid[i])): + if grid[i][j] == '1': + adjacent_components = set(components[adj_i][adj_j] + for adj_i, adj_j in adjacent_before(i, j) + if grid[adj_i][adj_j] == '1') + if len(adjacent_components) == 0: + components[i][j] = dsu.create_new() + elif len(adjacent_components) == 1: + components[i][j] = adjacent_components.pop() + else: + [c1, c2] = list(adjacent_components) + components[i][j] = dsu.merge(c1, c2) + + return dsu.disjoint_count() + + +puzzle_input = 'jxqlasbh' +# puzzle_input = 'flqrgnkx' + +grid = create_grid(puzzle_input) + +print('Part 1:', part1(grid)) +print('Part 2:', part2(grid)) diff --git a/py/advent-of-code-2017/day15.py b/py/advent-of-code-2017/day15.py new file mode 100644 index 0000000..1245fa4 --- /dev/null +++ b/py/advent-of-code-2017/day15.py @@ -0,0 +1,41 @@ +from typing import Generator + +MASK = int('1' * 16, 2) + + +def generator(initial: int, factor: int, multiple: int = 1) -> Generator[int, None, None]: + prev = initial + while True: + next_val = prev * factor % 2147483647 + if next_val % multiple == 0: + yield next_val + prev = next_val + + +def count_matches(a_start: int, a_mult: int, b_start: int, b_mult: int, count: int) -> int: + A = generator(a_start, 16807, a_mult) + B = generator(b_start, 48271, b_mult) + matched = 0 + + for i in range(count): + a = next(A) + b = next(B) + if a & MASK == b & MASK: + matched += 1 + + if i % 1000000 == 0: + print('Iteration', i) + + return matched + + +def part1(a_start: int, b_start: int) -> int: + return count_matches(a_start, 1, b_start, 1, int(4 * 1E7)) + + +def part2(a_start: int, b_start: int) -> int: + return count_matches(a_start, 4, b_start, 8, int(5 * 1E6)) + + +print('Part 1:', part1(618, 814)) +print('Part 2:', part2(618, 814)) diff --git a/py/advent-of-code-2017/day16.py b/py/advent-of-code-2017/day16.py new file mode 100644 index 0000000..fc7a2fc --- /dev/null +++ b/py/advent-of-code-2017/day16.py @@ -0,0 +1,144 @@ +from typing import List, Union +import functools + +PROGRAMS_COUNT = 16 + +Move = tuple[str, Union[int, tuple[int, int], tuple[str, str]]] + + +def parse_input(lines: List[str]) -> List[Move]: + moves = [] + + for line in lines: + if line[0] == 's': + moves.append(('spin', int(line[1:]))) + elif line[0] == 'x': + [x1, x2] = line[1:].split('/') + moves.append(('exchange', (int(x1), int(x2)))) + else: + [x1, x2] = line[1:].split('/') + moves.append(('partner', (x1, x2))) + + return moves + + +def get_programs(count: int) -> List[str]: + a = ord('a') + return [chr(a + x) for x in range(count)] + + +def swap(arr, i, j): + arr[i], arr[j] = arr[j], arr[i] + + +def perform_exchange(programs: List[str], params: tuple[int, int]) -> List[str]: + i, j = params + swap(programs, i, j) + return programs + + +def perform_spin(programs: List[str], spin: int) -> List[str]: + return programs[-spin:] + programs[:-spin] + + +def perform_partner(programs: List[str], params: tuple[str, str]) -> List[str]: + p1, p2 = params + swap(programs, programs.index(p1), programs.index(p2)) + return programs + + +def perform_move(programs: List[str], move: Move) -> List[str]: + type, params = move + if type == 'spin': + return perform_spin(programs, params) + elif type == 'exchange': + return perform_exchange(programs, params) + else: + return perform_partner(programs, params) + + +def dance(programs: List[str], moves: List[Move], times: int = 1) -> List[str]: + def loop(progs: List[str], _) -> List[str]: + return functools.reduce(perform_move, moves, progs) + + return functools.reduce(loop, range(times), programs.copy()) + + +def split_moves(moves: List[Move]) -> tuple[List[Move], List[Move]]: + partners = [] + rest = [] + for move in moves: + dst = partners if move[0] == 'partner' else rest + dst.append(move) + return rest, partners + + +def get_partners_spec(partner_moves: List[Move]) -> dict[str, str]: + programs = get_programs(PROGRAMS_COUNT) + after_partner = dance(programs.copy(), partner_moves) + return dict(zip(programs, after_partner)) + + +def extend_partners_spec(spec: dict[str, str]) -> dict[str, List[str]]: + result = {} + for key in spec: + swaps = [key] + current = spec[key] + while current != key: + swaps.append(current) + current = spec[current] + result[key] = swaps + return result + + +def apply_extended_partner_spec(programs: List[str], spec: dict[str, List[str]], times: int) -> List[str]: + result = programs.copy() + for i in range(len(result)): + swaps = spec[programs[i]] + result[i] = swaps[times % len(swaps)] + return result + + +def get_positional_spec(positional_moves: List[Move]) -> List[int]: + programs = get_programs(PROGRAMS_COUNT) + after_moves = dance(programs.copy(), positional_moves) + return [after_moves.index(c) for c in programs] + + +def apply_extended_positional_spec(programs: List[str], spec: List[List[int]], times: int) -> List[str]: + result = programs.copy() + for i in range(len(programs)): + current_spec = spec[i] + result[current_spec[times % len(current_spec)]] = programs[i] + return result + + +def extend_positional_spec(spec: List[int]) -> List[List[int]]: + results = [] + for i in range(len(spec)): + positions = [i] + current_pos = spec[i] + while current_pos != i: + positions.append(current_pos) + current_pos = spec[current_pos] + results.append(positions) + return results + + +def dance_fast(programs: List[str], extended_positional_spec: List[List[int]], extended_partner_spec: dict[str, List[str]], times: int) -> List[str]: + after_pos = apply_extended_positional_spec(programs, extended_positional_spec, times) + return apply_extended_partner_spec(after_pos, extended_partner_spec, times) + + +moves = parse_input(open('input/day16.txt').read().split(',')) +programs = get_programs(16) + +positional_moves, partner_moves = split_moves(moves) +partner_spec = get_partners_spec(partner_moves) +positional_spec = get_positional_spec(positional_moves) +extended_positional_spec = extend_positional_spec(positional_spec) +extended_partner_spec = extend_partners_spec(partner_spec) + + +print('Part1', ''.join(dance_fast(programs.copy(), extended_positional_spec, extended_partner_spec, 1))) +print('Part2', ''.join(dance_fast(programs.copy(), extended_positional_spec, extended_partner_spec, int(1E9)))) \ No newline at end of file