"Advent of Code 2018" - d3d1rty
about 2 years ago

Advent of Code 2018

This year's Advent of Code event has kicked off, and I will be participating for the first time. Coming off the build and launch of this textboard, I'm hoping that completing the daily challenges will be a good change of pace from Rails development.

The first challenge was fun; here are my solutions for part one and two (in Ruby):

# Part One
frequency = 0
f = File.open('./first_day_input.txt', 'r')

while line=f.gets
  frequency += line.to_i
end

puts frequency

# Part Two
frequency = 0
observed_frequencies = []
found_duplicate = false
while !(found_duplicate)
  f = File.open('./first_day_input.txt', 'r')
  while line=f.gets
    frequency += line.to_i
    if observed_frequencies.include?(frequency)
      found_duplicate = true
      return frequency
    end
    observed_frequencies.push(frequency)
  end
end

puts frequency

I'm sure there are more performant solutions out there, but I'm mostly just shooting for completion of the overall event rather than seeking optimal solutions for each challenge. My rationalization for this is that a low-level of effort is easier to sustain for 25 days than a more deeply-thought out approach. I'm trying to keep it fun.

Is anyone else participating in the Advent of Code event this year? If so, post your solutions and/or thoughts on the challenges.

Anon - #6
about 2 years ago

Replying to: OP

My solution is literally the same. I am just using python.
I switched to a dict, because I thought i was doing something wrong with the array I used before.
But I just didn't read properly and forgot to repeat the offsets. Dunno How long I'll keep at it, but the first problem was neat.

#!/usr/bin/python3

lines  = open("f.txt", "r").readlines()

all_f = {}
curr_f = 0
found = False

while found == False:
    for line in lines:
        if int(curr_f) not in all_f:
            all_f[curr_f] = 1
        else:
            # we've already seen that. end.
            found = True
            break
        curr_f += int(line)

print(curr_f)
Anon - #8
about 2 years ago

Replying to: OP

Meh, pretty ugly solutions for today, but don't have the patience to optimize rn

Part1:

#!/usr/bin/python3

lines  = open("input.txt", "r").readlines()

two = 0
three = 0

for line in lines:
    tmp = {}
    found_two = False
    found_three = False
    for c in line:
        if c not in tmp:
            tmp[c] = 1
        else:
            tmp[c] += 1

    for key, value in tmp.items():
        if found_two == False and value == 2:
            two += 1
            found_two = True
        if found_three == False and value == 3:
            three += 1
            found_three = True

print("two: %d, three: %d" % (two, three))
print(two*three)

Part2:
```python
#!/usr/bin/python3

lines = open("input.txt", "r").readlines()

def comparestring(str1, str2):
diff = 0
diff
index = 0
for i in range(0, len(str1)):
if str1[i] != str2[i]:
diff += 1
diff_index = i

    if diff > 1:
        return -1

return diff_index

final_str = ""

for i in range(0, len(lines)):
for j in range(1, len(lines)):
if i == j:
continue
ret = compare_string(lines[i], lines[j])
if ret != -1:
print("Result: %s" % lines[i][:ret] + lines[i][ret+1:])
exit(0)`

Anon - #9
about 2 years ago

Replying to: #8

Edit part2:

#!/usr/bin/python3

lines  = open("input.txt", "r").readlines()

def compare_string(str1, str2):
    diff = 0
    diff_index = 0
    for i in range(0, len(str1)):
        if str1[i] != str2[i]:
            diff += 1
            diff_index = i

        if diff > 1:
            return -1

    return diff_index

final_str = ""

for i in range(0, len(lines)):
    for j in range(1, len(lines)):
        if i == j:
            continue
        ret = compare_string(lines[i], lines[j])
        if ret != -1:
            print("Result: %s" % lines[i][:ret] + lines[i][ret+1:])
            exit(0)



Anon - #10
about 2 years ago

Replying to: OP

python : second one find my lagging a bit ;)

from itertools import cycle

def returnData(filename):

data = []

with open(filename) as payload_file:
    for line in payload_file:
        data.append(int(line))

return data

def answerFirstStep(filename):
frequency = 0

for variation in returnData(filename):
    frequency += variation

return frequency

def answerSecondStep(filename):

frequency = 0
ledger = [0]

payload = returnData(filename)

data_pool = cycle(payload)

for variation in payload:
    frequency += variation
    ledger.append(frequency)

    if (len(ledger) != len(set(ledger))):
        return(frequency)

print(answerSecondStep('inputdayone.txt'))

d3d1rty - #11
about 2 years ago

Replying to: #10

Nice, Anon! I've added "Generate a Preview" functionality in the card footer for replies and posts, in case you find that useful. I was about to get started on my day 2, but the police are raiding one of my neighbors which is prime-time entertainment!

d3d1rty - #12
about 2 years ago

Replying to: #11

Here's my day 2 solution. For a second, I thought I wasn't going to get it.

Part 1:

#! /bin/bash ruby
f = File.open('day02/second_day_input.txt', 'r')
box_ids_for_dubs = 0
box_ids_for_trips = 0

# Part One
while line=f.gets
  tally = {}
  line.each_char do |c|
    if tally[c]
      tally[c] += 1
    else
      tally[c] = 1
    end
  end

  found_dubs = false
  found_trips = false
  tally.each do |key, value|
    found_dubs = true if value == 2
    found_trips = true if value == 3
  end
  box_ids_for_dubs += 1 if found_dubs == true
  box_ids_for_trips += 1 if found_trips == true
  found_dubs = false
  found_trips = false
end

checksum = box_ids_for_dubs * box_ids_for_trips
puts checksum
d3d1rty - #13
about 2 years ago

Replying to: #12

Part 2:

# Part Two
f = File.open('day02/second_day_input.txt', 'r')
line_str_maps = []
target_boxes = []
while line=f.gets
  string_arr = []
  line.chomp.each_char do |c|
    string_arr.push(c)
  end
  line_str_maps.push(string_arr)
end

line_str_maps.each_with_index do |str_arr, index|
  str_arr.each_with_index do |char, str_index|
    line_str_maps.each_with_index do |compare_arr, i|
      num_diff = 0
      diff_index = 0
      next if i == index
      compare_arr.each_with_index do |c, c_str_index|
        num_diff += 1 unless str_arr[c_str_index] == compare_arr[c_str_index]
        break if num_diff > 1
        diff_index = c_str_index if str_arr[c_str_index] == compare_arr[c_str_index]
      end
      if num_diff == 1 && str_index == diff_index
          target_boxes.push(str_arr.join.to_s)
          target_boxes.push(compare_arr.join.to_s)
      end
    end
  end
end

boxes = target_boxes.uniq

chars = boxes.first.length
diff_index = 0

chars.times do |i|
  next if boxes.first[i] == boxes.last[i]
  diff_index = i
end

puts boxes.first.slice(0..diff_index-1) + boxes.first.slice(diff_index+1..-1)
d3d1rty - #14
almost 2 years ago

Replying to: OP

Day 3

I'll be honest: from reading the challenge, I didn't think I was going to get this one. Turned out to be way easier than I thought, and this time I actually defined methods to simplify it a bit.

Part One

##
# Initialize 2d array to represent fabric.
def draw_board(x, y)
  x_arr = []
  x.times do
    y_arr = []
    y.times do
      y_arr.push('.')
    end
    x_arr.push(y_arr)
  end
  x_arr
end

##
# Draws a pattern on the fabric.
def draw_pattern(board, id, start_x, x_mod, start_y, y_mod)
  y_mod.times do |i|
    x_mod.times do |index|
      if board[start_y+i][start_x+index] == '.'
        board[start_y+i][start_x+index] = id
      else
        board[start_y+i][start_x+index] = '#'
      end
    end
  end
  board
end

f = File.open('third_day_input.txt', 'r')
board = draw_board(1000,1000)

while line=f.gets
  args = line.scan(/\d+/)
  board = draw_pattern(board, args[0], args[1].to_i, args[3].to_i, args[2].to_i, args[4].to_i)
end

overlapped_inches = 0
board.each do |row|
  row.each do |inch|
    overlapped_inches += 1 if inch == '#'
  end
end

puts overlapped_inches

Part 2

##
# Checks if a pattern is overlapped with another.
def is_overlapped?(board, id, start_x, x_mod, start_y, y_mod)
  found_overlap = false
  y_mod.times do |i|
    x_mod.times do |index|
      found_overlap = true unless board[start_y+i][start_x+index] == id
      end
    end
  found_overlap
end

f = File.open('third_day_input.txt', 'r')
no_overlaps = ''

while line=f.gets
  args = line.scan(/\d+/)
  no_overlaps = args[0] unless is_overlapped?(board, args[0], args[1].to_i, args[3].to_i, args[2].to_i, args[4].to_i)
end

puts no_overlaps
Anon - #30
almost 2 years ago

Replying to: OP

Here is my solution for day4.
It feels like this is a super ugly solution, but it worked out. So many fucking loops. My solutions for part1 and 2 are basically the same, so here is just the one for part2:

#!/usr/bin/python3

from datetime import datetime
import re
import operator

lines  = open("input", "r").readlines()

events = []
# gather all events
for line in lines:
    event = {}
    datestr = re.match(r"[^[]*\[([^]]*)\]", line).groups()[0]
    date = datetime.strptime(datestr, "%Y-%m-%d %H:%M")
    action = line.split(']')[1].lstrip().rstrip()

    event['time'] = date
    if action == "falls asleep":
        event['action'] = "sleep"
    elif action == "wakes up":
        event['action'] = "wake"
    else:
        regex = re.compile(r"#[\d]+")
        matches = regex.search(line)
        event['action'] = matches.group()
    events.append(event)

#sort them by time
sorted_events = sorted(events, key=lambda k: k['time'])

# find out when they were asleep and count up total minutes
guards = {}
curr_guardid = ""
last_sleep = 0
for event in sorted_events:
    if event['action'] == "sleep":
        last_sleep = event['time'].minute
    elif event['action'] == "wake":
        wake_minute = event['time'].minute
        guards[curr_guardid]['ranges'].append(range(last_sleep, wake_minute))
        guards[curr_guardid]['minutes'] += abs(last_sleep - wake_minute)
        last_sleep = 0
    else:
        if event['action'] not in guards:
            guards[event['action']] = {}
            guards[event['action']]['ranges'] = []
            guards[event['action']]['minutes'] = 0
        curr_guardid = event['action']


# this is for part 1 only. Find the guard with the most minutes asleep
max_guard = {}
max_value = 0
for guard in guards:
    if guards[guard]['minutes'] > max_value:
        max_value = guards[guard]['minutes']
        max_guard = guard

# find out which is the most occuring minute
#part1 doesnt need this loop: for id, g in guards.items():

g = guards[max_guard]
id = max_guard
all_max = {}
for id, g in guards.items():
    times_asleep = {}
    for i in range(0, len(g['ranges'])):
        for j in range(i+1, len(g['ranges'])):
            a = g['ranges'][i]
            b = g['ranges'][j]
            if a == b:
                continue
            print("a: %s, b: %s" % (a, b))
            xs = set(a)
            intersect = xs.intersection(b)
            for k in intersect:
                if k not in times_asleep:
                    times_asleep[k] = 1
                else:
                    times_asleep[k] += 1


    max_minute = 0
    max_count = 0
    for key, val in times_asleep.items():
        if val > max_count:
            max_minute = key
            max_count = val
    all_max[id] = (max_minute, max_count)

# evalute part2 prefered minute
print(all_max)
max_minute = 0
max_count = 0
max_id = ""
for key, val in all_max.items():
    minute, count = val
    if count >= max_count:
        max_count = count
        max_minute = minute
        max_id = key

print(max_id)
print(max_minute)
d3d1rty - #32
almost 2 years ago

Replying to: #30

I think your solution looks way better than mine; my solution is a pile of hot garbage:

require 'time'

f = File.open('fourth_day_input.txt', 'r')

unparsed_lines = []

while line=f.gets
  unparsed_lines.push(line.chomp)
end

unparsed_lines.sort!

# parse each line into hash; collect guard ids for later use
parsed_lines = []
guard_ids = []
unparsed_lines.each do |line|
  guard_hash = {}
  guard_hash[:datetime] = Time.parse(line.slice(0,18))
  guard_hash[:action] = line.slice(19..-1)
  guard_hash[:guard_id] = guard_hash[:action].scan(/\d+/).first
  guard_ids.push(guard_hash[:guard_id]) unless guard_hash[:guard_id].nil?
  parsed_lines.push(guard_hash)
end

# Set guard ids for each line
guard_id = parsed_lines[0][:guard_id]
parsed_lines.each do |hash|
  if hash[:guard_id].nil?
    hash[:guard_id] = guard_id
  else
    guard_id = hash[:guard_id]
  end
end

# initialize array of guard sleep minutes
sleep_times = []
guard_ids.uniq.each do |id|
  sleep_times.push({ guard_id: id, total_sleep_time: 0, minutes_asleep: [], minute_indices: [] })
end

# Populate sleep information by guard
parsed_lines.each_with_index do |line, index|
  if line[:action] == 'falls asleep'
    sleep_times.each do |hash|
      if hash[:guard_id] == line[:guard_id]
        snooze_duration = (parsed_lines[index+1][:datetime] - line[:datetime])/60
        hash[:minutes_asleep].push(snooze_duration)
        hash[:total_sleep_time] = hash[:minutes_asleep].sum
        snooze_duration.to_i.times do |count|
          hash[:minute_indices].push(line[:datetime].min + count)
        end
        break
      end
    end
  end
end

# Determine which guard sleeps the most
sleepiest_guard = ''
biggest_sleep_time = 0
sleep_time_index = 0
sleep_times.each_with_index do |hash, index|
  if hash[:total_sleep_time] > biggest_sleep_time
    biggest_sleep_time = hash[:total_sleep_time]
    sleepiest_guard = hash[:guard_id]
    sleep_time_index = index
  end
end

minutes = sleep_times[sleep_time_index][:minute_indices]

minute = minutes.max_by { |i| minutes.count(i) }
puts "The sleepiest guard is #{sleepiest_guard} and he slept the most at #{minute} minute."
puts "The solution for Part One is #{sleepiest_guard.to_i * minute}."

min_most_slept_at = 0
times_most_slept_at_min = 0
solution = { guard_id: '', min_most_slept_at: 0, times_most_slept_at_min: 0 }
sleep_times.each do |hash|
  mins = hash[:minute_indices]
  min_most_slept_at = mins.max_by { |i| mins.count(i) }
  times_most_slept_at_min = mins.count(min_most_slept_at)
  if times_most_slept_at_min > solution[:times_most_slept_at_min]
    solution[:guard_id] = hash[:guard_id]
    solution[:min_most_slept_at] = min_most_slept_at
    solution[:times_most_slept_at_min] = times_most_slept_at_min
  end
end

puts "The solution for Part Two is #{solution[:guard_id].to_i * solution[:min_most_slept_at]}."
d3d1rty - #35
almost 2 years ago

Replying to: #32

Day 3

I knocked mine out early this time:

def compare_char(a, b)
  (a.match?(/[A-Z]/) && b.match?(/[a-z]/)) || (a.match?(/[a-z]/) && b.match?(/[A-Z]/))
end

def combust_chain(molecule_arr)
  i = 0
  while (true)
    break if i == molecule_arr.length
    if molecule_arr[i].casecmp?(molecule_arr[i+1])
      if compare_char(molecule_arr[i], molecule_arr[i+1])
        molecule_arr[i] = nil
        molecule_arr[i+1] = nil
        molecule_arr.compact!
        next if i == 0
        i -= 1
      else
        i += 1
      end
    else
      i += 1
      next
    end
  end
  molecule_arr
end

f = File.open('./fifth_day_input.txt', 'r')

polymer_chain = ''
while line=f.gets
  polymer_chain = line
end

molecule_arr = combust_chain(polymer_chain.split(//))

puts "The solution to Part One is: #{molecule_arr.length-1}"

results = []
'ABCDEFGHJKLMNOPQRSTUVWXYZ'.each_char do |char|
  temp_chain = polymer_chain.split(//)
  temp_chain.delete(char.upcase)
  temp_chain.delete(char.downcase)
  result = combust_chain(temp_chain)
  results.push(result.length-1)
end

puts "The solution to Part Two is: #{results.sort.first}"
Anon - #36
almost 2 years ago

Replying to: OP

Day 5 was quite easy tbqh.
My initial recursive try didn't work out, but iterative worked just fine.
Dunno why I had to substract one from the resulting string length, but whatever.

Here's my solution:

#!/usr/bin/python3

lines  = open("input", "r").read()

def parse(input):
    prev_c = ""
    i = 0
    #for i in range(0, len(input)):
    while(i < len(input)):
        if prev_c != "" and (ord(prev_c)-32 == ord(input[i]) or ord(prev_c) == ord(input[i])-32):
            input = input[:i-1] + input[i+1:]
            i = 0
            prev_c = ""
        else:
            prev_c = input[i]
            i += 1
    return input

def remove_polymer(input, c):
    i = 0
    while(i < len(input)):
        if input[i] == c or input[i] == c.upper():
            input = input[:i] + input[i+1:]
        else:
            i += 1 # do not increment if removed a char
    return input

min_len = 2**32
for i in range(ord('a'), ord('z')+1):
    print("current char: %c" % chr(i))
    new_polymer = remove_polymer(lines, chr(i))
    erg = parse(new_polymer)
    if len(erg) < min_len:
        min_len = len(erg)
    print("got len of: %d" % len(erg))

print("min_len: %d" % (min_len-1))

Part 1 was basically the first function and part 2 the second. Second part took super super long, but whatever. Maybe ill give the recursive one a shot again tomorrow (depending on the difficulty of the task for tomorrow lol)

Anon - #37
almost 2 years ago

Replying to: #36

Oh, I am a retard. I just realized that I wouldn't have to jump back to index 0 inside the first function after removing a pair. Jumping back index-2 would've been enough since there can't be any new combinations beforehand.

This is the new time on part2:
bash
python3 polymer.py 2,28s user 0,00s system 99% cpu 2,282 total

lol. Before this it took a couple minutes for part 2

New Reply