Gyrfalcon's recent activity

  1. Comment on A not-so-modest proposal to nationalize the defense industry in ~misc

    Gyrfalcon
    Link Parent
    Plus there's tools like the Ghost Gunner, which currently only finish 80% lower receivers, but I don't see why a similar tool could not be used to produce a relatively large quantity of high...

    Plus there's tools like the Ghost Gunner, which currently only finish 80% lower receivers, but I don't see why a similar tool could not be used to produce a relatively large quantity of high quality parts for an underground arms industry.

    4 votes
  2. Comment on A not-so-modest proposal to nationalize the defense industry in ~misc

    Gyrfalcon
    Link Parent
    That speech is one of the things that gives me great respect for Eisenhower and the political climate after the Second World War. Personally my favorite part of the speech is this:

    That speech is one of the things that gives me great respect for Eisenhower and the political climate after the Second World War. Personally my favorite part of the speech is this:

    The fruit of success in all these tasks would present the world with the greatest task—and the greatest opportunity—of all. It is this: the dedication of the energies, the resources, and the imaginations of all peaceful nations to a new kind of war. This would be a declared, total war, not upon any human enemy, but upon the brute forces of poverty and need.

    4 votes
  3. Comment on Do you love me? in ~tech

    Gyrfalcon
    Link Parent
    I thought the same, not because of what the robots are doing but because of the lighting. I think the lighting is just exceptionally even, which lends it to looking a bit like a render.

    I thought the same, not because of what the robots are doing but because of the lighting. I think the lighting is just exceptionally even, which lends it to looking a bit like a render.

    5 votes
  4. Comment on Do you carry a knife with with you? If so, what type/company? in ~hobbies

    Gyrfalcon
    Link
    I carry a Leatherman Wingman with me pretty much every time I leave the house, and I use it regularly at home. Most prized and used feature is the package opener, which is not only the...

    I carry a Leatherman Wingman with me pretty much every time I leave the house, and I use it regularly at home. Most prized and used feature is the package opener, which is not only the easier/safer tool for opening packages IMHO, but it also keeps the blade nice and clean. Since as a kid I managed to completely gum up a Swiss Army knife opening packages and not taking enough care of the blade, I decided that would be good to have. I have used pretty much everything on there except maybe the wire stripper and the ruler, the wire stripper because I forgot it was there until I found the product page, and the ruler because if I measure something that small I probably want the precision of calipers. The scissors do leave a lot to be desired, though.

    2 votes
  5. Comment on Goodreads is dead. What now? in ~books

    Gyrfalcon
    Link Parent
    I think it's interesting that the recommendation algorithm is the most important to you of all the features. For me the opposite is true, if the site never recommends me a book I will probably...

    I think it's interesting that the recommendation algorithm is the most important to you of all the features. For me the opposite is true, if the site never recommends me a book I will probably still have plenty to read, since my discovery is mostly done while I'm reading online or in another book. Then again, that's mostly nonfiction, and I have no idea how discovery works for fiction titles.

    5 votes
  6. Comment on Day 20: Jurassic Jigsaw in ~comp

    Gyrfalcon
    Link
    Well, I got part 1 much faster than I thought I would. Unfortunately, part 2 negates my shortcut for part 1, so I'll have to come back to this. Part 1 Ignoring the need to actually make the image...

    Well, I got part 1 much faster than I thought I would. Unfortunately, part 2 negates my shortcut for part 1, so I'll have to come back to this.

    Part 1

    Ignoring the need to actually make the image seemed like the move here. Part 2 is making me regret this lol.

    function main()
    
        input = []
        open("Day20/input.txt") do fp
            input = split(readchomp(fp), "\n\n")
        end
    
        tiles = Dict()
        for tile in input
            rows = split(tile, '\n')
            id = parse(Int, rows[1][6:end-1])
            tile = hcat([[val == '#' for val in row] for row in rows[2:end]]...)'
            tiles[id] = tile
            
        end
    
        all_possible_edges = Dict([key => get_edge_permutations(value) for (key, value) in tiles])
        
        shared_edges = Dict()
        for (id,edges) in all_possible_edges
            for (other_id, other_edges) in all_possible_edges
                if other_id != id
                    if length(intersect(edges, other_edges)) == 2
                        if !(id in keys(shared_edges))
                            shared_edges[id] = [other_id]
                        else
                            push!(shared_edges[id], other_id)
                        end
                    end
                end
            end
        end
    
        println(prod(key for (key,value) in shared_edges if length(value) == 2))
    end
    
    function get_edges(tile)
        top = Tuple(collect(tile[1,idx] for idx in 1:10))
        bottom = Tuple(collect(tile[10,idx] for idx in 1:10))
        left = Tuple(collect(tile[idx,1] for idx in 1:10))
        right = Tuple(collect(tile[idx,10] for idx in 1:10))
        return [top, bottom, left, right]
    end
    
    function get_edge_permutations(tile)
        return [get_edges(tile)..., collect(reverse(edge) for edge in get_edges(tile))...]
    end
    
    main()
    
    2 votes
  7. Comment on How and why I stopped buying new laptops in ~tech

    Gyrfalcon
    Link
    Solar mirror I think another thing to consider here is that for a good chunk of individual users, if you don't need a laptop, you can get a small desktop. Access to the performance level you need...

    Solar mirror

    I think another thing to consider here is that for a good chunk of individual users, if you don't need a laptop, you can get a small desktop. Access to the performance level you need will be cheaper, at the cost of higher power consumption and loss of portability. But, when things break, it is easy to replace components and keep the build working.

    11 votes
  8. Comment on Day 19: Monster Messages in ~comp

    Gyrfalcon
    Link
    I tried to do this one entirely with logical regex, a bold choice given that my familiarity with regex was low to start with. I learned later that it was an especially bold choice because part 2...

    I tried to do this one entirely with logical regex, a bold choice given that my familiarity with regex was low to start with. I learned later that it was an especially bold choice because part 2 is literally impossible to do with a single, pure regular expression, because it's asking for something that's not a regular language! Several disgusting hacks later, I had a solution inspired by some of the others in the thread, but I don't know how many more of these are in my wheelhouse.

    Part 2, and mostly part 1 but I forgot to commit it
    function main()
    
        input = []
        open("Day19/input2.txt") do fp
            input = split(readchomp(fp), "\n\n")
        end
    
        messages = split(input[2], '\n')
        rules = split(input[1], '\n')
    
        rule_dict = Dict()
        for rule in rules
            rule_dict[parse(Int, split(rule, ": ")[1])] = parse_rule(split(rule, ": ")[2])
        end
        
        target1 = Regex("(*NO_JIT)" * construct_regex(rule_dict, 11) * "\$")
        target2 = Regex("^" * construct_regex(rule_dict, 8) * "\$")
        count = 0
        for message in messages
            if match(target1, message) !== nothing
                short_message = message[1:match(target1, message).offset-1]
                if match(target2, short_message) !== nothing
                    println(message)
                    count += 1
                end
            end
        end
        println(count)
        
    end
    
    function parse_rule(rule)
        if match(r"[a-z]", rule) != nothing
            return rule[2]
        elseif contains(rule, "|")
            return [parse.(Int, split(split(rule, " | ")[1], ' ')), 
                    parse.(Int, split(split(rule, " | ")[2], ' '))]
        else
            return parse.(Int, split(rule, ' '))
        end
    end
    
    function construct_regex(rules, start_rule, depth=0)
    
        if isa(rules[start_rule], Array{Int,1})
            return string(collect(construct_regex(rules, start) for start in rules[start_rule])...)
        elseif isa(rules[start_rule], Char)
            return string(rules[start_rule])
        elseif isa(rules[start_rule], Array{Array{Int,1}})
            if start_rule in rules[start_rule][2]
                if length(rules[start_rule][2]) == 2
                    return string(construct_regex(rules, rules[start_rule][1][1]), "+")
                elseif length(rules[start_rule][2]) == 3
                    if depth == 0
                        return string("(", construct_regex(rules, rules[start_rule][1][1]), "(",
                                        construct_regex(rules, 11, depth+1), ")*",
                                        construct_regex(rules, rules[start_rule][1][2]), ")")
                    elseif depth < 16
                        return string("(", construct_regex(rules, rules[start_rule][1][1]), "(",
                                        construct_regex(rules, 11, depth+1), ")*",
                                        construct_regex(rules, rules[start_rule][1][2]), ")*")
                    else
                        return ""
                    end
                else
                    println("AH2") # for emergency use
                end
            else
                return string("(", 
                    collect(construct_regex(rules, start) for start in rules[start_rule][1])...,
                    "|", collect(construct_regex(rules, start) for start in rules[start_rule][2])...,
                    ")")
            end
        else
            return "AH" # for emergency use
        end
    end
    
    main()
    
    2 votes
  9. Comment on Day 18: Operation Order in ~comp

    Gyrfalcon
    (edited )
    Link
    This one was (is?) tough for me. I'm sure it's as textbook as some others have said but my knowledge here is primarily of the informal sort. Either way, I went for a recursive solution for part 1,...

    This one was (is?) tough for me. I'm sure it's as textbook as some others have said but my knowledge here is primarily of the informal sort. Either way, I went for a recursive solution for part 1, but it's getting late, so I'll come back with part 2 tomorrow.

    EDIT: Part 2 was much easier than I thought, but I ended up not able to get to it until today. Playing catch up now!

    Part 1
    function main()
    
        input = []
        open("Day18/input.txt") do fp
            input = clean_input.(readlines(fp))
        end
    
        println(sum(eval_expression.(input)))
    
    end
    
    function clean_input(line)
        return_line = Array{Any}([letter for letter in line if letter != ' '])
        for idx = 1:length(return_line)
            if match(r"[()+*]", string(return_line[idx])) == nothing
                return_line[idx] = parse(Int, return_line[idx])
            end
        end
        return return_line
    end
    
    function eval_expression(line)
        if length(line) < 3
            return line[1]
        elseif line[1] == '('
            close = find_paren_match(line[2:end], 0)
            return eval_expression([eval_expression(line[2:close])...,
                                    line[close+2:end]...])
        elseif line[3] == '('
            close = find_paren_match(line[4:end], 2)
            return eval_expression([line[1:2]...,
                                    eval_expression(line[4:close])...,
                                    line[close+2:end]...])
        elseif line[2] == '+'
            return eval_expression([line[1] + line[3], line[4:end]...])
        elseif line[2] == '*'
            return eval_expression([line[1] * line[3], line[4:end]...])
        end
    end
    
    function find_paren_match(line, offset)
        paren_count = 1
        for (idx,character) in enumerate(line)
            if character == '('
                paren_count += 1
            elseif character == ')'
                paren_count -= 1
            end
    
            if paren_count == 0
                return idx + offset
            end
        end
    end
     
    
    main()
    
    Part 2 Diff
    @@ -7,6 +7,8 @@ function main()
     
         println(sum(eval_expression.(input)))
     
    +    println(sum(eval_expression2.(input)))
    +
     end
     
     function clean_input(line)
    @@ -38,6 +40,27 @@ function eval_expression(line)
         end
     end
     
    +function eval_expression2(line)
    +    if length(line) < 3
    +        return line[1]
    +    elseif line[1] == '('
    +        close = find_paren_match(line[2:end], 0)
    +        return eval_expression2([eval_expression2(line[2:close])...,
    +                                line[close+2:end]...])
    +    elseif line[3] == '('
    +        close = find_paren_match(line[4:end], 2)
    +        return eval_expression2([line[1:2]...,
    +                                eval_expression2(line[4:close])...,
    +                                line[close+2:end]...])
    +    elseif line[2] == '+'
    +        return eval_expression2([line[1] + line[3], line[4:end]...])
    +    elseif line[2] == '*' && length(line) >= 4 && line[4] != '+'
    +        return eval_expression2([line[1] * line[3], line[4:end]...])
    +    else
    +        return line[1] * eval_expression2(line[3:end])
    +    end
    +end
    +
     function find_paren_match(line, offset)
         paren_count = 1
         for (idx,character) in enumerate(line)
    
    1 vote
  10. Comment on Day 17: Conway Cubes in ~comp

    Gyrfalcon
    Link
    Language: Julia Repository This one was neat. Using some careful typing I was able to reuse the majority of my code from part 1, and along with memoization, keep the run time very short. A first...

    This one was neat. Using some careful typing I was able to reuse the majority of my code from part 1, and along with memoization, keep the run time very short. A first run including compilation is about 8 seconds, with subsequent timed runs taking advantage of the cache completing in about half a second. I chose to use a dictionary to connect the locations with their values, which I think made things much easier, no worrying about preventing negative values or allocating extra space.

    Part 1
    using Memoize
    
    function main()
    
        input = []
        open("Day17/input.txt") do fp
            input = readlines(fp)
        end
    
        map = Dict{Tuple{Int,Int,Int}, Int}()
        for (idx, row) in enumerate(input)
            for (jdx, char) in enumerate(row)
                if char == '#'
                    map[(jdx, idx, 0)] = 1
                end
            end
        end
    
        simulate!(map, 6)
        println(sum(values(map)))
    
    end
    
    @memoize function nearest_neighbors(location)
    
        return ((i,j,k) for i in location[1]-1:location[1]+1
                        for j in location[2]-1:location[2]+1
                        for k in location[3]-1:location[3]+1
                        if (i, j, k) != location)
    end
    
    function num_active_neighbors(neighbors, map)
        return sum([get(map, neighbor, 0) for neighbor in neighbors])
    end
    
    function simulate!(map, rounds)
    
        for round in 1:rounds
    
            changes = Dict() # To minimize deepcopying
            curr_active = (key for (key, value) in map if value == 1)
            active_neighbors = Set((location for active in curr_active for location in nearest_neighbors(active)))
            
            for active in curr_active
                if !(1 < num_active_neighbors(nearest_neighbors(active), map) < 4)
                    changes[active] = 0
                end
            end
    
            for neighbor in active_neighbors
                if num_active_neighbors(nearest_neighbors(neighbor), map) == 3
                    changes[neighbor] = 1
                end
            end
    
            apply_changes!(map, changes)
        end
    end
    
    function apply_changes!(map, changes)
        for (location, change) in changes
            map[location] = change
        end
    end
    
    main()
    
    Part 2 diff
    @@ -7,7 +7,7 @@ function main()
             input = readlines(fp)
         end
     
    -    map = Dict{Tuple{Int,Int,Int}, Int}()
    +    map = Dict{NTuple{3,Int}, Int}()
         for (idx, row) in enumerate(input)
             for (jdx, char) in enumerate(row)
                 if char == '#'
    @@ -19,9 +19,21 @@ function main()
         simulate!(map, 6)
         println(sum(values(map)))
     
    +    map_4d = Dict{NTuple{4,Int}, Int}()
    +    for (idx, row) in enumerate(input)
    +        for (jdx, char) in enumerate(row)
    +            if char == '#'
    +                map_4d[(jdx, idx, 0, 0)] = 1
    +            end
    +        end
    +    end
    +
    +    simulate!(map_4d, 6)
    +    println(sum(values(map_4d)))
    +
     end
     
    -@memoize function nearest_neighbors(location)
    +@memoize function nearest_neighbors(location::NTuple{3,Int})
     
         return ((i,j,k) for i in location[1]-1:location[1]+1
                         for j in location[2]-1:location[2]+1
    @@ -29,15 +41,25 @@ end
                         if (i, j, k) != location)
     end
     
    +# There's gotta be a better way to do this lol
    +@memoize function nearest_neighbors(location::NTuple{4,Int})
    +
    +    return ((i,j,k, l) for i in location[1]-1:location[1]+1
    +                       for j in location[2]-1:location[2]+1
    +                       for k in location[3]-1:location[3]+1
    +                       for l in location[4]-1:location[4]+1
    +                       if (i, j, k, l) != location)
    +end
    +
     function num_active_neighbors(neighbors, map)
         return sum([get(map, neighbor, 0) for neighbor in neighbors])
     end
     
    -function simulate!(map, rounds)
    +function simulate!(map::Dict{T,Int}, rounds) where T <: NTuple
     
         for round in 1:rounds
     
    -        changes = Dict() # To minimize deepcopying
    +        changes = Dict{T,Int}() # To minimize deepcopying
             curr_active = (key for (key, value) in map if value == 1)
             active_neighbors = Set((location for active in curr_active for location in nearest_neighbors(active)))
    
    2 votes
  11. Comment on Day 16: Ticket Translation in ~comp

    Gyrfalcon
    Link
    Language: Julia Repository This one took a little longer than I had hoped, partly because I was overcomplicating the second part into a sudoku like mess, and partly because I took the shortcut of...

    This one took a little longer than I had hoped, partly because I was overcomplicating the second part into a sudoku like mess, and partly because I took the shortcut of just returning the offending value in part 1. That meant that even though I had a working algorithm in part 2, I was passing in invalid data and getting confused when it didn't work out!

    Part 1
    function main()
    
        input = []
        open("Day16/input.txt") do fp
            input = split(readchomp(fp), "\n\n")
        end
    
        input_fields = split.(split(input[1], '\n'), ": ")
        fields = Dict()
        for field in input_fields
            values = split.(split(field[2], " or "), '-')
            fields[field[1]] = parse.(Int, [values[1][1], values[1][2],
                                            values[2][1], values[2][2]])
        end
        
        my_ticket = split.(split(input[2], '\n')[2], ',')
        my_ticket = [parse(Int, val) for val in my_ticket]
        
        nearby_tickets = split.(split(input[3], '\n')[2:end], ',')
        nearby_tickets = [[parse(Int, val) for val in ticket] for ticket in nearby_tickets]
    
        error_rate = 0
        for ticket in nearby_tickets
            error_rate += basic_validation(ticket, fields)
        end
    
        println(error_rate)
    
    end
    
    function basic_validation(ticket, fields)
        for value in ticket
            valid = false
            for bounds in values(fields)
                if (bounds[1] <= value <= bounds[2]) || (bounds[3] <= value <= bounds[4])
                    valid = true
                end
            end
            if !valid
                return value
            end
        end
        return 0
    end
    
    main()
    
    Part 2 diff
    @@ -21,11 +21,23 @@ function main()
     
         error_rate = 0
         for ticket in nearby_tickets
    -        error_rate += basic_validation(ticket, fields)
    +        error_rate += basic_validation(ticket, fields)[1]
         end
     
         println(error_rate)
     
    +    for idx in length(nearby_tickets):-1:1
    +        if basic_validation(nearby_tickets[idx], fields)[2]
    +            deleteat!(nearby_tickets, idx)
    +        end
    +    end
    +
    +    ordered_fields = find_fields(nearby_tickets, fields)
    +
    +    departure_fields = [value for (key, value) in ordered_fields if startswith(key, "departure")]
    +
    +    println(prod(my_ticket[departure_fields]))
    +
     end
     
     function basic_validation(ticket, fields)
    @@ -37,10 +49,46 @@ function basic_validation(ticket, fields)
                 end
             end
             if !valid
    -            return value
    +            return (value, true)
    +        end
    +    end
    +    return (0, false)
    +end
    +
    +function find_fields(tickets, fields)
    +    field_order = Dict()
    +    possibilities = Dict()
    +    for (name, bounds) in fields
    +        for row in 1:length(tickets[1])
    +            values = [ticket[row] for ticket in tickets]
    +            if all(((bounds[1] .<= values) .& (values .<= bounds[2]))
    +                    .| ((bounds[3] .<= values) .& (values .<= bounds[4])))
    +                if name in keys(possibilities)
    +                    push!(possibilities[name], row)
    +                else
    +                    possibilities[name] = Set([row])
    +                end
    +            end
             end
         end
    -    return 0
    +
    +    while true
    +        
    +        singletons = [name for (name, value) in possibilities if length(value) == 1]
    +        single_val = possibilities[singletons[1]]
    +        delete!(possibilities, singletons[1])
    +        field_order[singletons[1]] = collect(single_val)[1]
    +
    +        if length(possibilities) < 1
    +            break
    +        end
    +
    +        for key in collect(keys(possibilities))
    +            setdiff!(possibilities[key], single_val)
    +        end
    +    end
    +
    +    return field_order
     end
     
     main()
    
    2 votes
  12. Comment on Day 15: Rambunctious Recitation in ~comp

    Gyrfalcon
    Link
    Language: Julia Repository This was a nice simple one I thought. Interesting performance note, I originally did not type the dictionary that I use to store the game state, which was fine in part...

    This was a nice simple one I thought. Interesting performance note, I originally did not type the dictionary that I use to store the game state, which was fine in part 1, but was noticeable in part 2. By adding that type, runtime was cut from a little over 21 seconds down to 8.5, of which about one eighth was memory allocation. After looking at some of the solutions here, I decided to tweak a little more, and by not saving every value in the history, switching to an immutable type to store the values, and typing down my numbers, I was able to get the time down even further to a ~2.7 seconds. Not the fastest here, but pretty good I think!

    Parts 1 and 2
    function main()
    
        input = []
        open("Day15/input.txt") do fp
            input = parse.(Int32, split(readchomp(fp), ','))
        end
    
        game = Dict{Int32, Tuple{Int32, Int32}}()
    
        for (idx, num) in enumerate(input)
            add_num!(game, idx, num)
        end
    
        result_1 = play_game!(deepcopy(game), 2020, input[end])
        println(result_1)
    
        result_2 = play_game!(deepcopy(game), 30_000_000, input[end])
        println(result_2)
    
    end
    
    function add_num!(game, turn, num)
        if !(num in keys(game))
            game[num] = (0, turn)
        else
            game[num] = (game[num][2], turn)
        end
    end
    
    function play_game!(game, last_turn, first_num)
        first_turn = length(game) + 1
        prev_num = first_num
        for turn = first_turn:last_turn
            prev_num = advance_game!(game, prev_num, turn)
        end
        return prev_num
    end
    
    function advance_game!(game, prev_num, turn)
        if game[prev_num][1] == 0
            add_num!(game, turn, 0)
            new_num = 0
        else
            new_num = game[prev_num][2] - game[prev_num][1]
            add_num!(game, turn, new_num)
        end
        return new_num
    end
    
    main()
    
    3 votes
  13. Comment on Day 14: Docking Data in ~comp

    Gyrfalcon
    Link
    Language: Julia Repository This one was a little tough to grok at first, but turned out not as bad as yesterday for me. I think my solution is decent, especially since as far as I can tell, Julia...

    This one was a little tough to grok at first, but turned out not as bad as yesterday for me. I think my solution is decent, especially since as far as I can tell, Julia is woefully underequipped for bitwise operations, so I did pretty much everything with strings. I guess that makes sense as a young language focused on scientific computing, but I wasn't happy about it today lol. It's still pretty quick though, both parts take about half a second, and I think the vast majority of that time is spent in the recursive function I defined for figuring out the memory locations in part 2. It seems like I have a knack for writing recursive functions that really hit the weak points of Julia's memory management.

    Part 1
    function main()
    
        input = []
        open("Day14/input.txt") do fp
            input = split.(readlines(fp), ' ')
        end
    
        lines = translate_lines(input)
        result_1 = map_memory_sum(lines)
    
        println(result_1)
    
    end
    
    function map_memory_sum(lines)
    
        memory = Dict()
        mask = nothing
        for line in lines
            if line[1] == 'm'
                mask = line[2]
            else
                value = apply_mask(line[3], mask)
                memory[line[2]] = parse(Int, reverse(value), base = 2)
            end
        end
        return sum(values(memory))
    end
    
    
    function translate_lines(lines)
    
        output = []
        for line in lines
    
            if line[1] == "mask"
                push!(output, ('m', translate_mask(line[3])))
            else
                location = parse(Int, line[1][5:end-1])
                value = reverse(bitstring(parse(Int, line[3])))
                push!(output, ('a', location, value))
            end
        end
        return output
    end
    
    function translate_mask(mask)
        mask = reverse(mask) # little endian time
        output = Dict()
        for (index, char) in enumerate(mask)
            if char == '1' || char == '0'
                output[index] = string(char)
            end
        end
        return output
    end
    
    function apply_mask(value, mask)
        for (location, mask_val) in mask
            value = value[1:location-1] * mask_val * value[location+1:end]
        end
        return value
    end
    
    
    
    main()
    
    Part 2 diff
    @@ -10,6 +10,11 @@ function main()
     
         println(result_1)
     
    +    lines_2 = translate_lines2(input)
    +    result_2 = map_memory_sum2(lines_2)
    +
    +    println(result_2)
    +
     end
     
     function map_memory_sum(lines)
    @@ -27,6 +32,24 @@ function map_memory_sum(lines)
         return sum(values(memory))
     end
     
    +function map_memory_sum2(lines)
    +
    :...skipping...
    diff --git a/Day14/main.jl b/Day14/main.jl
    index ecdf018..de3c538 100644
    --- a/Day14/main.jl
    +++ b/Day14/main.jl
    @@ -10,6 +10,11 @@ function main()
     
         println(result_1)
     
    +    lines_2 = translate_lines2(input)
    +    result_2 = map_memory_sum2(lines_2)
    +
    +    println(result_2)
    +
     end
     
     function map_memory_sum(lines)
    @@ -27,6 +32,24 @@ function map_memory_sum(lines)
         return sum(values(memory))
     end
     
    +function map_memory_sum2(lines)
    +
    +    memory = Dict()
    +    mask = nothing
    +    for line in lines
    +        if line[1] == 'm'
    +            mask = line[2]
    +        else
    +            # TODO: Make this work
    +            locations = location_mask(mask, line[2])
    +            for location in locations
    +                memory[location] = line[3]
    +            end
    +        end
    +    end
    +    return sum(values(memory))
    +end
    +
     
     function translate_lines(lines)
     
    @@ -44,6 +67,36 @@ function translate_lines(lines)
         return output
     end
     
    +function translate_lines2(lines)
    +
    +    output = []
    +    for line in lines
    +
    +        if line[1] == "mask"
    +            push!(output, ('m', reverse(line[3])))
    +        else
    +            location = reverse(bitstring(parse(Int, line[1][5:end-1])))
    +            value = parse(Int, line[3])
    +            push!(output, ('a', location, value))
    +        end
    +    end
    +    return output
    +end
    +
    +function location_mask(mask, location, trailing="")
    +
    +    if length(mask) == 0
    +        return parse(Int, reverse(trailing * location), base = 2)
    +    elseif mask[1] == '0'
    +        return [location_mask(mask[2:end], location[2:end], trailing * location[1])...]
    +    elseif mask[1] == '1'
    +        return [location_mask(mask[2:end], location[2:end], trailing * "1")...]
    +    elseif mask[1] == 'X'
    +        return [location_mask(mask[2:end], location[2:end], trailing * "1")...,
    +                location_mask(mask[2:end], location[2:end], trailing * "0")...]
    +    end
    +end
    +
     function translate_mask(mask)
         mask = reverse(mask) # little endian time
         output = Dict()
    
    3 votes
  14. Comment on The Tildes' Make Something Month (Timasomo) 2020 Reflection Thread in ~talk

    Gyrfalcon
    Link Parent
    I think as long as any novel writers are on board, I would prefer it. I didn't see any novels showing up in the updates/exhibition, so I guess there aren't many?

    I think as long as any novel writers are on board, I would prefer it. I didn't see any novels showing up in the updates/exhibition, so I guess there aren't many?

    2 votes
  15. Comment on Day 13: Shuttle Search in ~comp

    Gyrfalcon
    Link
    Language: Julia Repository This one was a doozy. Part 1 was not bad but part 2 I tried several things that did not work. I looked at it as linear algebra, as a linear optimization problem, as...

    This one was a doozy. Part 1 was not bad but part 2 I tried several things that did not work. I looked at it as linear algebra, as a linear optimization problem, as something I could do recursively with a simpler method, and eventually got close based on hints from @PapaNachos, and then just had to look at a solution to get over the last hump. My final solution is pretty speedy (mean time of 380.573 μs over 10,000 samples) but wow I would not have gotten there on my own.

    Part 1
    function main()
    
        input = []
        open("Day13/input.txt") do fp
            input = readlines(fp)
        end
    
        current_time = parse(Int, input[1])
        bus_ids = tryparse.(Int, split(input[2], ','))
    
        # filter out out of service buses
        bus_ids = Array{Int}(bus_ids[bus_ids .!= nothing])
    
        earliest_times = earliest_time.(current_time, bus_ids)
    
        min_time, min_index = findmin(earliest_times)
    
        result_1 = (min_time - current_time) * bus_ids[min_index]
    
        println(result_1)
    
    end
    
    function earliest_time(current_time, bus_time)
        return Int(ceil(current_time / bus_time) * bus_time)
    end
    
    main()
    
    Part 2 diff

    I had originally sorted the bus IDs to get the biggest ones first, in the hope that would get a larger step size early on and lead to faster runtime. In the end it was actually a bit slower so I left them as is.

    @@ -8,8 +8,14 @@ function main()
         current_time = parse(Int, input[1])
         bus_ids = tryparse.(Int, split(input[2], ','))
     
    +    # Grab minute offsets
    +    offsets = findall(bus_ids .!= nothing)
    +
         # filter out out of service buses
    -    bus_ids = Array{Int}(bus_ids[bus_ids .!= nothing])
    +    bus_ids = Array{Int}(bus_ids[offsets])
    +
    +    # Adjust offset for indexing at 1
    +    offsets = offsets .- 1
     
         earliest_times = earliest_time.(current_time, bus_ids)
     
    @@ -19,8 +25,32 @@ function main()
     
         println(result_1)
     
    +    # Credit to @PapaNachos on Tildes for their hints/code
    +    not_found = true
    +    step = 1
    +    time = 1
    +    constraint = 1
    +    while not_found
    +        not_found = false
    +
    +        # apply constraint
    +        if mod(time + offsets[constraint], bus_ids[constraint]) != 0
    +            time += step
    +            not_found = true
    +        end
    +
    +        # Check to see if we have applied all constraints, if not, add another and keep going
    +        if !not_found && constraint < length(bus_ids)
    +            step *= bus_ids[constraint]
    +            constraint += 1
    +            not_found = true
    +        end
    +    end
    +    println(time)
    +
     end
    
    2 votes
  16. Comment on The Tildes' Make Something Month (Timasomo) 2020 Showcase Thread in ~talk

    Gyrfalcon
    Link Parent
    I'm so glad you liked it! And I'm surprised that there weren't any other return submitters. The real question now is can I go for the threepeat??

    I'm so glad you liked it! And I'm surprised that there weren't any other return submitters. The real question now is can I go for the threepeat??

    4 votes
  17. Comment on Day 12: Rain Risk in ~comp

    Gyrfalcon
    Link
    Language: Julia Repository This was a pretty simple one, though I did forget that turns could be more than 90 degrees at first. Actually ended up using trig functions in part 2 because I think...

    This was a pretty simple one, though I did forget that turns could be more than 90 degrees at first. Actually ended up using trig functions in part 2 because I think that ended up being the least work. Had to look up how that rotation works though because this year has made it feel like an eternity since I thought about trig!

    Part 1
    function main()
    
        input = []
        open("Day12/input.txt") do fp
            input = readlines(fp)
        end
    
        input = map(x -> (x[1], parse(Int, x[2:end])), input)
    
        result_1 = manhattan_distance(input)
    
        println(result_1)
    
    end
    
    function manhattan_distance(directions)
        east = 0
        north = 0
        heading = 0
        for instruction in directions
            if instruction[1] == 'N'
                north += instruction[2]
            elseif instruction[1] == 'S'
                north -= instruction[2]
            elseif instruction[1] == 'E'
                east += instruction[2]
            elseif instruction[1] == 'W'
                east -= instruction[2]
            elseif instruction[1] == 'R'
                heading = mod(heading + instruction[2], 360)
            elseif instruction[1] == 'L'
                heading = mod(heading - instruction[2], 360)
            else
                if heading == 0
                    east += instruction[2]
                elseif heading == 90
                    north -= instruction[2]
                elseif heading == 180
                    east -= instruction[2]
                else
                    north += instruction[2]
                end
                
            end
        end
        return abs(east) + abs(north)
    end
    
    
    
    main()
    
    Part 2 diff
    @@ -11,6 +11,10 @@ function main()
     
         println(result_1)
     
    +    result_2 = waypoint_distance(input)
    +
    +    println(result_2)
    +
     end
     
     function manhattan_distance(directions)
    @@ -46,6 +50,35 @@ function manhattan_distance(directions)
         return abs(east) + abs(north)
     end
     
    +function waypoint_distance(directions)
    +    waypoint = [10, 1] # East, north
    +    ship = [0, 0] # East, north
    +
    +    for instruction in directions
    +
    +        if instruction[1] == 'N'
    +            waypoint[2] += instruction[2]
    +        elseif instruction[1] == 'S'
    +            waypoint[2] -= instruction[2]
    +        elseif instruction[1] == 'E'
    +            waypoint[1] += instruction[2]
    +        elseif instruction[1] == 'W'
    +            waypoint[1] -= instruction[2]
    +        elseif instruction[1] == 'R'
    +            theta = instruction[2]
    +            waypoint = [waypoint[1] * cosd(theta) + waypoint[2] * sind(theta),
    +                        -waypoint[1] * sind(theta) + waypoint[2] * cosd(theta)]
    +        elseif instruction[1] == 'L'
    +            theta = -instruction[2]
    +            waypoint = [waypoint[1] * cosd(theta) + waypoint[2] * sind(theta),
    +                        -waypoint[1] * sind(theta) + waypoint[2] * cosd(theta)]
    +        else
    +            ship = ship .+ (waypoint .* instruction[2])
    +        end
    +    end
    +
    +    return sum(abs.(ship))
    +end
     
    +main()
     
    -main()
    
    2 votes
  18. Comment on Day 11: Seating System in ~comp

    Gyrfalcon
    (edited )
    Link
    Language: Julia Repository Messy solution for this one, but part 2 was not as bad as I initially thought. Part 1 using Memoize function main() input = [] open("Day11/input.txt") do fp input =...

    Messy solution for this one, but part 2 was not as bad as I initially thought.

    Part 1
    using Memoize
    
    function main()
    
        input = []
        open("Day11/input.txt") do fp
            input = readlines(fp)
        end
        seats = []
        for row in input
            seat_row = []
            for char in row
                push!(seat_row, seat_type(char))
            end
            push!(seats, seat_row)
        end
    
        result_1 = simulate(seats)
    
        println(result_1)
        
    end
    
    function seat_type(seat_code)
        if seat_code == 'L'
            # Empty, can be filled
            return (false, true)
        else
            # Empty, can't be filled
            return (false, false)
        end
    end
    
    @memoize function valid_neighbors(location, max)
        y = location[1] .+ [1, 0, -1]
        x = location[2] .+ [1, 0, -1]
        y = y[max[1] .>= y .> 0]
        x = x[max[2] .>= x .> 0]
        return [(y_val, x_val) for x_val in x for y_val in y]
    end
    
    function simulate(seats)
    
        max = (length(seats), length(seats[1]))
        changed_seats = 1
        new_seats = deepcopy(seats)
        while changed_seats > 0
            changed_seats = 0
            for ydx = 1:max[1]
                for xdx = 1:max[2]
                    if seats[ydx][xdx][2] == false
                        continue
                    elseif seats[ydx][xdx][1] == false
                        neighbors = valid_neighbors((ydx,xdx), max)
                        adjacent = 0
                        for neighbor in neighbors
                            if neighbor == (ydx, xdx)
                                continue
                            end
                            adjacent += seats[neighbor[1]][neighbor[2]][1]
                        end
                        if adjacent == 0
                            new_seats[ydx][xdx] = (true, true)
                            changed_seats += 1
                        else
                            continue
                        end
                    elseif seats[ydx][xdx][1] == true
                        neighbors = valid_neighbors((ydx,xdx), max)
                        adjacent = 0
                        for neighbor in neighbors
                            if neighbor == (ydx, xdx)
                                continue
                            end
                            adjacent += seats[neighbor[1]][neighbor[2]][1]
                        end
                        if adjacent >= 4
                            new_seats[ydx][xdx] = (false, true)
                            changed_seats += 1
                        else
                            continue
                        end
                    end
                end
            end
            seats = deepcopy(new_seats)
        end
    
        return count([seat[1] for row in seats for seat in row])
    
    end
    
    main()
    

    Decided to do memoization again since my nearest neighbor lookup is slow, will probably do it again for the second part since that looks to be even more expensive for my not so great design pattern.

    Part 2 additions
    @memoize function valid_neighbors2(location, seats, max)
        neighbors = []
        directions = [(1,1), (1,0), (1,-1), (0,1), (0,-1), (-1, 1), (-1,0), (-1,-1)]
        multiplier = 1
        while length(directions) > 0
            for idx = length(directions):-1:1
                neighbor = location .+ (directions[idx] .* multiplier)
                if any(neighbor .> max) || any(neighbor .< 1)
                    deleteat!(directions, idx)
                elseif seats[neighbor[1]][neighbor[2]][2] == true
                     push!(neighbors, neighbor)
                     deleteat!(directions, idx)
                end
            end
            multiplier += 1
        end
        return neighbors
    end
    
    function simulate2(seats)
    
        max = (length(seats), length(seats[1]))
        changed_seats = 1
        new_seats = deepcopy(seats)
        while changed_seats > 0
            changed_seats = 0
            for ydx = 1:max[1]
                for xdx = 1:max[2]
                    if seats[ydx][xdx][2] == false
                        continue
                    elseif seats[ydx][xdx][1] == false
                        neighbors = valid_neighbors2((ydx,xdx), seats, max)
                        adjacent = 0
                        for neighbor in neighbors
                            if neighbor == (ydx, xdx)
                                continue
                            end
                            adjacent += seats[neighbor[1]][neighbor[2]][1]
                        end
                        if adjacent == 0
                            new_seats[ydx][xdx] = (true, true)
                            changed_seats += 1
                        else
                            continue
                        end
                    elseif seats[ydx][xdx][1] == true
                        neighbors = valid_neighbors2((ydx,xdx), seats, max)
                        adjacent = 0
                        for neighbor in neighbors
                            if neighbor == (ydx, xdx)
                                continue
                            end
                            adjacent += seats[neighbor[1]][neighbor[2]][1]
                        end
                        if adjacent >= 5
                            new_seats[ydx][xdx] = (false, true)
                            changed_seats += 1
                        else
                            continue
                        end
                    end
                end
            end
            seats = deepcopy(new_seats)
        end
    
        return count([seat[1] for row in seats for seat in row])
    
    end
    

    Part 2 was actually not too bad since I had split out the neighbor finding code in part 1.

    2 votes
  19. Comment on Day 10: Adapter Array in ~comp

    Gyrfalcon
    Link
    Language: Julia Repository The first part seemed too easy, the second part I will admit I didn't have a good way to get the runtime down until I let myself follow in the footsteps of @weemadarthur...

    The first part seemed too easy, the second part I will admit I didn't have a good way to get the runtime down until I let myself follow in the footsteps of @weemadarthur and implemented memoization. I did try to parallelize first but I definitely did it wrong and spawned so many processes my computer locked up!

    Part 1
    function main()
    
        adapters = []
        open("Day10/input.txt") do fp
            adapters = parse.(Int, readlines(fp))
        end
    
        # Is this as easy as I think it is?
        adapters = [0, adapters..., maximum(adapters) + 3]
        sort!(adapters)
        differences = diff(adapters)
        numOnes = count(differences .== 1)
        numThrees = count(differences .== 3)
    
        result_1 = numOnes * numThrees
    
        # It is
        println("Result 1 is ", result_1)
    
    end
    
    main()
    
    Part 2 diff
    @@ -1,3 +1,5 @@
    +using Memoize
    +
     function main()
     
         adapters = []
    @@ -17,6 +19,29 @@ function main()
         # It is
         println("Result 1 is ", result_1)
     
    +    result_2 = arrange_adapters(Tuple(adapters))
    +
    +    println("Result 2 is ", result_2)
    +
     end
     
    -main()
    \ No newline at end of file
    +# Just do this recursively and cache, math is hard
    +@memoize function arrange_adapters(adapters)
    +    if length(adapters) == 1
    +        return 1
    +    elseif length(adapters) < 4
    +        num_ways = 0
    +        next_steps = sum(adapters[2:end] .<= adapters[1] + 3)
    +        for idx = (1:next_steps) .+ 1
    +            num_ways += arrange_adapters(adapters[idx:end])
    +        end
    +        return num_ways
    +    else
    +        num_ways = 0
    +        next_steps = sum(adapters[2:4] .<= adapters[1] + 3)
    +        for idx = (1:next_steps) .+ 1
    +            num_ways += arrange_adapters(adapters[idx:end])
    +        end
    +        return num_ways
    +    end
    +end
    

    I don't think I'll keep up with the performance comparisons, as I don't think they do much interesting. This one does chug a little bit though, I get the sense that my penchant for loops in recursive functions does a number on the Julia compiler. Either way, they are easy to come up with and perform well enough here.

    4 votes