Nuolong's recent activity

  1. Comment on Day 17: Conway Cubes in ~comp

    Nuolong
    Link
    Python Repo Link I really didn't feel like doing this problem at first, but it was nice to get through it without much debugging at all. The hardest part was starting, though something even harder...

    Python
    Repo Link

    I really didn't feel like doing this problem at first, but it was nice to get through it without much debugging at all. The hardest part was starting, though something even harder would be writing faster code! Behold my beautiful nested for loop code! Part 1 runs in about a second, while Part 2 runs in ~2 minutes.

    Part 2 Part 1 can be seen in my repo link. Didn't post it because it would be redundant. I just made a dictionary where key values were tuples of the coordinates, and values were either inactive ('.') or active ('#'). That's how I inserted the input. For the function I just brute force iterated through all coordinates to find each of their neighbor counts and change their values accordingly to the rules. For the hard-coded ranges (-15 to 15), I was just too lazy to do the math to find the most appropriate bounds. So I picked a high-enough number that would simulate the infinite bounds given the number of cycles we had to run.

    Overall there's clearly a faster + smarter way to go about it. Like keeping track of only active cubes and their respective numbers of active neighbors, instead of iterating through all coordinates where I'm doing a lot of unnecessary comparisons. However, I just wanted to be done with this problem :)

    import sys
    from collections import defaultdict
    import copy
    
    def neighbors(space):
        new_space = copy.deepcopy(space)
    
        for x in range(-15, 15):
            for y in range(-15, 15):
                for z in range(-15, 15):
                    for w in range(-15, 15):
                        count = 0
                        for dx in (-1, 0, 1):
                            for dy in (-1, 0, 1):
                                for dz in (-1, 0, 1):
                                    for dw in (-1, 0, 1):
                                        if (dx or dy or dz or dw) and space.get((x + dx, y + dy, z + dz, w + dw), '.') == '#':
                                            count += 1
                        if space.get((x, y, z, w), '.') == '#' and not (2 <= count <= 3):
                            new_space[(x, y, z, w)] = '.'
                        elif space.get((x, y, z, w), '.') == '.' and count == 3:
                            new_space[(x, y, z, w)] = '#'
    
        return new_space
    
    def main():
        space = defaultdict(str)
    
        for idx_1, line in enumerate(sys.stdin):
            for idx_2, val in enumerate(line.strip()):
                space[(idx_1, idx_2, 0, 0)] = val
    
        for x in range(6):
            space = neighbors(space)
    
        num = 0
        for s in space.values():
            if s == '#':
                num += 1
    
        print(num)
    
    
    if __name__ == '__main__':
        main()
    
    4 votes
  2. Comment on Day 12: Rain Risk in ~comp

    Nuolong
    Link
    Python Repo Link In short, I think I overcomplicated this relatively simple problem. I ended up using a dictionary to mark the ship/waypoint coordinates. I realized it would have been easier to...

    Python
    Repo Link

    In short, I think I overcomplicated this relatively simple problem. I ended up using a dictionary to mark the ship/waypoint coordinates. I realized it would have been easier to just use cartesian coordinates but I decided to go this route anyway.

    Part 1 I used a `pointing` variable to keep track of which direction the ship was facing. For moving the ship, I would add the value to the appropriate direction and subtract the value from the opposite. In the end, I was only interested in the absolute `E` and `N` values (which would be analogous to the `x` and `y` in a normal approach.
    #!/usr/bin/env python3
    
    import sys
    
    DIRECTIONS = ['E', 'S', 'W', 'N']
    
    def travel(dir_lst):
        status = {'E' : 0, 'S' : 0, 'W' : 0, 'N' : 0}
        pointing = 0 # East
    
        for dir in dir_lst:
            if dir[0] in DIRECTIONS:
                status[dir[0]] += dir[1]
                opposite = (DIRECTIONS.index(dir[0]) + 2) % len(DIRECTIONS)
                status[DIRECTIONS[opposite]] -= dir[1]
            elif dir[0] == 'L':
                pointing -= (dir[1] // 90) % len(DIRECTIONS)
                pointing %= len(DIRECTIONS)
            elif dir[0] == 'R':
                pointing += (dir[1] // 90) % len(DIRECTIONS)
                pointing %= len(DIRECTIONS)
            elif dir[0] == 'F':
                status[DIRECTIONS[pointing]] += dir[1]
                opposite = (pointing + 2) % len(DIRECTIONS)
                status[DIRECTIONS[opposite]] -= dir[1]
    
        print(abs(status['E']) + abs(status['N']))
    
    
    def main():
        dir_lst = []
        for dir in sys.stdin:
            dir_lst.append((dir[0], int(dir[1:])))
    
        travel(dir_lst)
    
    
    if __name__ == '__main__':
        main()
    
    Part 2 I used a similar approach as part 1. As for rotating the waypoint, I just rotated the values of my dictionary manually.
    #!/usr/bin/env python3
    
    import sys
    
    DIRECTIONS = ['E', 'S', 'W', 'N']
    
    def travel(dir_lst):
        status = {'E' : 0, 'S' : 0, 'W' : 0, 'N' : 0}
        waypoint = {'E' : 10, 'S' : -1, 'W' : -10, 'N' : 1}
    
        for dir in dir_lst:
            if dir[0] in DIRECTIONS:
                waypoint[dir[0]] += dir[1]
                opposite = (DIRECTIONS.index(dir[0]) + 2) % len(DIRECTIONS)
                waypoint[DIRECTIONS[opposite]] -= dir[1]
            elif dir[0] == 'L':
                for _ in range(dir[1] // 90):
                    temp_1 = waypoint['E']
                    waypoint['E'] = waypoint['S']
                    waypoint['S'] = waypoint['W']
                    waypoint['W'] = waypoint['N']
                    waypoint['N'] = temp_1
            elif dir[0] == 'R':
                for _ in range(dir[1] // 90):
                    temp_1 = waypoint['E']
                    waypoint['E'] = waypoint['N']
                    waypoint['N'] = waypoint['W']
                    waypoint['W'] = waypoint['S']
                    waypoint['S'] = temp_1
            elif dir[0] == 'F':
                status['E'] += waypoint['E'] * dir[1]
                status['S'] += waypoint['S'] * dir[1]
                status['W'] += waypoint['W'] * dir[1]
                status['N'] += waypoint['N'] * dir[1]
    
        print(abs(status['E']) + abs(status['N']))
    
    def main():
        dir_lst = []
        for dir in sys.stdin:
            dir_lst.append((dir[0], int(dir[1:])))
    
        travel(dir_lst)
    
    
    if __name__ == '__main__':
        main()
    
    3 votes
  3. Comment on Day 11: Seating System in ~comp

    Nuolong
    Link
    Python I wasn't a big fan of this problem! My solutions are admittedly not the best, but they worked out in the end and they're easy for me to understand. Will definitely look forward to seeing...

    Python
    I wasn't a big fan of this problem! My solutions are admittedly not the best, but they worked out in the end and they're easy for me to understand. Will definitely look forward to seeing others' better solutions. It was especially difficult for me to debug the program (in one instance, I was missing a critical rule in part B, like @PapaNachos wrote). My incompetent reading strikes again!

    Repo link

    Part 1 I padded the entire seating matrix with floors, just because I didn't want to have to deal with special cases for the edge seats. Though there probably is just be an entirely easier way to solve this problem, I decided to go with this. Then I used a boolean flag so that I could keep running my function until equilibrium.
    #!/usr/bin/env python3
    
    import sys
    
    INPUT_COLS = 92
    INPUT_ROWS = 99
    
    # calculates new matrix of seats. marks if any changes were made
    def adjacents(seats):
        adj_mat = [['.' for _ in range(INPUT_COLS + 2)]]
        changed = False
        for i in range(1, INPUT_ROWS + 1):
            row = []
            for j in range(1, INPUT_COLS + 1):
                count = 0
    
                if seats[i-1][j-1] == '#':
                    count += 1
                if seats[i+1][j] == '#':
                    count += 1
                if seats[i+1][j-1] == '#':
                    count += 1
                if seats[i][j-1] == '#':
                    count += 1
                if seats[i][j+1] == '#':
                    count += 1
                if seats[i-1][j] == '#':
                    count += 1
                if seats[i-1][j+1] == '#':
                    count += 1
                if seats[i+1][j+1] == '#':
                    count += 1
    
                if seats[i][j] == 'L' and not count:
                    row.append('#')
                    changed = True
                elif seats[i][j] == '#' and count >= 4:
                    row.append('L')
                    changed = True
                else:
                    row.append(seats[i][j])
    
            adj_mat.append(["."] + row + ["."])
    
        adj_mat.append(['.' for _ in range(INPUT_COLS + 2)])
    
        return adj_mat, changed
    
    # count num of occupied seats
    def count_occ(seats):
        count = 0
        for i in range(1, INPUT_ROWS + 1):
            for j in range(1, INPUT_COLS + 1):
                if seats[i][j] == '#':
                    count += 1
    
        return count
    
    def main():
    
        # read input into 2D matrix, pad it with "floor"
        seats = [['.' for _ in range(INPUT_COLS + 2)]]
    
        for _ in range(INPUT_ROWS):
            seats.append(["."] + list(sys.stdin.readline().strip()) + ["."])
    
        seats.append(['.' for _ in range(INPUT_COLS + 2)])
    
        # flag
        changed = True
        while changed:
            seats, changed = adjacents(seats)
    
        print(count_occ(seats))
    
    if __name__ == '__main__':
        main()
    
    Part 2 A similar approach to part 1 with padding and a flag system for handling the equilibrium. The important rule I missed was in regards to how an empty seat blocks off the sight of an occupied seat. As a result, I wasted time trying to debug my program.
    #!/usr/bin/env python3
    
    import sys
    
    INPUT_COLS = 92
    INPUT_ROWS = 99
    
    # calculates new matrix of seats. marks if any changes were made
    def sights(seats):
        adj_mat = [['.' for _ in range(INPUT_COLS + 2)]]
        changed = False
        for i in range(1, INPUT_ROWS + 1):
            row = []
            for j in range(1, INPUT_COLS + 1):
                count = 0
    
                # nw
                x = i - 1
                y = j - 1
                while x and y:
                    if seats[x][y] == "L":
                        break
                    elif seats[x][y] == "#":
                        count += 1
                        break
                    x -= 1
                    y -= 1
    
                # n
                x = i - 1
                y = j
                while x:
                    if seats[x][y] == "L":
                        break
                    elif seats[x][y] == "#":
                        count += 1
                        break
                    x -= 1
    
                # ne
                x = i - 1
                y = j + 1
                while x and y != INPUT_COLS + 1:
                    if seats[x][y] == "L":
                        break
                    elif seats[x][y] == "#":
                        count += 1
                        break
                    x -= 1
                    y += 1
    
                # e
                x = i
                y = j + 1
                while y != INPUT_COLS + 1:
                    if seats[x][y] == "L":
                        break
                    elif seats[x][y] == "#":
                        count += 1
                        break
                    y += 1
    
                # se
                x = i + 1
                y = j + 1
                while x != INPUT_ROWS + 1 and y != INPUT_COLS + 1:
                    if seats[x][y] == "L":
                        break
                    elif seats[x][y] == "#":
                        count += 1
                        break
                    x += 1
                    y += 1
    
                # s
                x = i + 1
                y = j
                while x != INPUT_ROWS + 1:
                    if seats[x][y] == "L":
                        break
                    elif seats[x][y] == "#":
                        count += 1
                        break
                    x += 1
    
                # sw
                x = i + 1
                y = j - 1
                while x != INPUT_ROWS + 1 and y:
                    if seats[x][y] == "L":
                        break
                    elif seats[x][y] == "#":
                        count += 1
                        break
                    x += 1
                    y -= 1
    
                # w
                x = i
                y = j - 1
                while y:
                    if seats[x][y] == "L":
                        break
                    elif seats[x][y] == "#":
                        count += 1
                        break
                    y -= 1
    
                if seats[i][j] == 'L' and not count:
                    row.append('#')
                    changed = True
                elif seats[i][j] == '#' and count >= 5:
                    row.append('L')
                    changed = True
                else:
                    row.append(seats[i][j])
    
            adj_mat.append(["."] + row + ["."])
    
        adj_mat.append(['.' for _ in range(INPUT_COLS + 2)])
    
        return adj_mat, changed
    
    # count num of occupied seats
    def count_occ(seats):
        count = 0
        for i in range(1, INPUT_ROWS + 1):
            for j in range(1, INPUT_COLS + 1):
                if seats[i][j] == '#':
                    count += 1
    
        return count
    
    def main():
    
        # read input into 2D matrix, pad it with "floor"
        seats = [['.' for _ in range(INPUT_COLS + 2)]]
    
        for _ in range(INPUT_ROWS):
            seats.append(["."] + list(sys.stdin.readline().strip()) + ["."])
    
        seats.append(['.' for _ in range(INPUT_COLS + 2)])
    
        # flag
        changed = True
        while changed:
            seats, changed = sights(seats)
    
        print(count_occ(seats))
    
    if __name__ == '__main__':
        main()
    
    4 votes
  4. Comment on Day 10: Adapter Array in ~comp

    Nuolong
    Link
    This problem was really confusing for me to understand at first, though what it was actually asking wasn't complicated. Shows how much I need to improve my reading comprehension. Repo link Part 1...

    This problem was really confusing for me to understand at first, though what it was actually asking wasn't complicated. Shows how much I need to improve my reading comprehension.

    Repo link

    Part 1 Standard, manual counting
    #!/usr/bin/env python3
    
    import sys
    
    def find_jolts(nums):
        diff_1 = 0
        diff_3 = 1  # for last-to built-in joltage
        start = 0
    
        while nums:
            curr = nums.pop(0)
            if start + 1 == curr:
                diff_1 += 1
                start = curr
            elif start + 3 == curr:
                diff_3 += 1
                start = curr
    
        return diff_1 * diff_3
    
    
    def main():
        nums = []
        for num in sys.stdin:
            nums.append(int(num))
    
        nums.sort()
        print(find_jolts(nums))
    
    if __name__ == '__main__':
        main()
    
    Part 2 Solution using memoization.
    #!/usr/bin/env python3
    
    import sys
    
    def count_seq(n, nums):
        mem = [0] * (n + 1)
        mem[0] = 1
    
        for i in nums:
            mem[i] = mem[i - 1] + mem[i - 2] + mem[i - 3]
    
        return mem[n]
    
    def main():
        nums = []
        for num in sys.stdin:
            nums.append(int(num))
    
        nums.sort()
        print(count_seq(max(nums), nums))
    
    if __name__ == '__main__':
        main()
    
    3 votes
  5. Comment on Day 9: Encoding Error in ~comp

    Nuolong
    (edited )
    Link
    Python The problem was a little boring in my opinion today... but backstory made it interesting nonetheless! Repo Link Part 2 #!/usr/bin/env python3 import sys def find_ctg(window, invalid_num):...

    Python
    The problem was a little boring in my opinion today... but backstory made it interesting nonetheless!

    Repo Link

    Part 2
    #!/usr/bin/env python3
    
    import sys
    
    def find_ctg(window, invalid_num):
        curr_sum = window[0]
        start = 0
        end = 1
    
        while end < len(window) - 1:
            # front window value is removed from window
            while curr_sum > invalid_num and start < end:
                curr_sum -= window[start]
                start += 1
    
            # contiguous subarray found
            if curr_sum == invalid_num:
                sub_arr = window[start:end+1]
                return max(sub_arr) + min(sub_arr)
            # new value added to end of window
            else:
                curr_sum += window[end]
                end += 1
    
    
    def abide(window, n):
        for i, w_n in enumerate(window):
            diff = n - w_n
            if diff in window[i + 1:]:
                return True
        return False
    
    def find_rulebreaker(nums, preamble_len):
        window = nums[0:preamble_len]
        strt_remain = nums[preamble_len:]
    
        for i, n in enumerate(strt_remain):
            if (abide(window, n)):
                window.append(n)
                window.pop(0)
            else:
                return i, n
    
    def main():
        nums = []
        for num in sys.stdin:
            nums.append(int(num))
    
        i, invalid_num = find_rulebreaker(nums, 25)
        print(find_ctg(nums[:i], invalid_num))
    
    
    if __name__ == '__main__':
        main()
    
    6 votes
  6. Comment on Day 8: Handheld Halting in ~comp

    Nuolong
    Link
    I believe I had really mediocre approaches which led me to make a lot of mistakes on my way to the solution, but I got the solution nevertheless! (That's my holiday spirit) Repo link Part 1 Here I...

    I believe I had really mediocre approaches which led me to make a lot of mistakes on my way to the solution, but I got the solution nevertheless! (That's my holiday spirit)
    Repo link

    Part 1 Here I edited the list's instruction itself to mark that it was already visited. I don't know what made me think of doing it this really odd way, but it messed me up a bit for part 2.
    #!/usr/bin/env python3
    
    import sys
    
    def follow(instr):
        current = 0
        acc = 0
    
        while instr[current][0] != 'DID':
            if instr[current][0] == 'nop':
                instr[current][0] = "DID"
                current += 1
            elif instr[current][0] == 'acc':
                acc += instr[current][1]
                instr[current][0] = "DID"
                current += 1
            elif instr[current][0] == 'jmp':
                instr[current][0] = "DID"
                current += instr[current][1]
    
        return acc
    
    def main():
        instr = []
        for line in sys.stdin:
            instr.append(line.strip().split())
            instr[-1][1] = int(instr[-1][1])
    
        print(follow(instr))
    
    if __name__ == '__main__':
        main()
    
    Part 2 Kind of a mess, but it works. I ran into a problem when I used my part 1 `follow` and realized the program would stop running because it was reusing the same list of instructions that were renamed to mark they were visited on a previous iteration. So I went a simpler route and just marked a list instead for my visited instructions.
    #!/usr/bin/env python3
    
    import sys
    
    def follow(instr):
        visited = []
        current = 0
        acc = 0
    
        while current not in visited:
            if current == len(instr) - 1:
                return acc, current
            if instr[current][0] == 'nop':
                visited.append(current)
                current += 1
            elif instr[current][0] == 'acc':
                acc += instr[current][1]
                visited.append(current)
                current += 1
            elif instr[current][0] == 'jmp':
                visited.append(current)
                current += instr[current][1]
    
        return acc, current
    
    def find_success(instr):
        finish = len(instr) - 1
    
        for i in instr:
            if i[0] == 'nop':
                i[0] = 'jmp'
                acc, fin = follow(instr)
                if fin == finish:
                    return acc
                i[0] = 'nop'
            elif i[0] == 'jmp':
                i[0] = 'nop'
                acc, fin = follow(instr)
                i[0] = 'jmp'
                if fin == finish:
                    return acc
    
    def main():
        instr = []
        for line in sys.stdin:
            instr.append(line.strip().split())
            instr[-1][1] = int(instr[-1][1])
    
        print(find_success(instr))
    
    if __name__ == '__main__':
        main()
    
    4 votes
  7. Comment on Day 7: Handy Haversacks in ~comp

    Nuolong
    Link
    Quite a novice at programming in general, having lots of fun doing this so far! This one was definitely a lot more challenging to me than previous days so far. I should start using defaultdict,...

    Quite a novice at programming in general, having lots of fun doing this so far! This one was definitely a lot more challenging to me than previous days so far. I should start using defaultdict, haha.
    Python
    Repo link

    Part 1
    #!/usr/bin/env python3
    
    import sys
    import re
    
    OUTER_COLOR = r'([a-z]+ [a-z]+) bags contain'
    INNER_COLOR = r'(?: (\d+) ([a-z]+ [a-z]+) bags?[,.])'
    
    has_shiny_gold = set()
    
    def shiny_gold(has_bag, color):
        global has_shiny_gold
        if color in has_bag:
            for clr in has_bag[color]:
                try:
                    has_shiny_gold.add(clr)
                except KeyError:
                    has_shiny_gold = {clr}
                shiny_gold(has_bag, clr)
    
    def main():
        has_bag = {}
        count = 0
    
        for line in sys.stdin:
            outer_color = re.findall(OUTER_COLOR, line)[0]
            for inner_count, inner_color in re.findall(INNER_COLOR, line):
                try:
                    has_bag[inner_color].add(outer_color)
                except KeyError:
                    has_bag[inner_color] = {outer_color}
    
        shiny_gold(has_bag, "shiny gold")
        print(len(has_shiny_gold))
    
    if __name__ == '__main__':
        main()
    
    Part 2
    #!/usr/bin/env python3
    
    import sys
    import re
    
    OUTER_COLOR = r'([a-z]+ [a-z]+) bags contain'
    INNER_COLOR = r'(?: (\d+) ([a-z]+ [a-z]+) bags?[,.])'
    
    
    def bags_needed(bags_inside, color):
        count = 0
        if color in bags_inside:
            for bag, num in bags_inside[color]:
                count += int(num) + (int(num) * bags_needed(bags_inside, bag))
        return count
    
    
    
    def main():
        bags_inside = {}
        count = 0
    
        for line in sys.stdin:
            outer_color = re.findall(OUTER_COLOR, line)[0]
            for inner_count, inner_color in re.findall(INNER_COLOR, line):
                try:
                    bags_inside[outer_color].add((inner_color, inner_count))
                except KeyError:
                    bags_inside[outer_color] = {(inner_color, inner_count)}
    
        print(bags_needed(bags_inside, "shiny gold"))
    
    
    
    if __name__ == '__main__':
        main()
    
    3 votes