-
Notifications
You must be signed in to change notification settings - Fork 0
/
day_4.rb
169 lines (128 loc) · 3.5 KB
/
day_4.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
require 'time'
class Record
def self.fill_in_guard(records)
updated_records = []
current_guard = records.first.split(" ")[3]
records.each do |record|
pieces = record.split(" ")
if pieces[2] == "Guard"
current_guard = pieces[3]
else
new_record = pieces.insert(2, current_guard).join(" ")
updated_records << new_record
end
end
updated_records
end
def self.parse(records)
guards = {}
records.each_slice(2) do |asleep, awake|
start_time = Record.parse_time(asleep)
end_time = Record.parse_time(awake)
sleep_log = SleepLog.new(start_time, end_time)
guard_id = Record.parse_guard_id(asleep)
if guards[guard_id]
guards[guard_id].add_sleep(sleep_log)
else
guards[guard_id] = Guard.new(guard_id, sleep_log)
end
end
guards
end
def self.parse_time(record)
pieces = record.split(" ")
Time.parse(pieces[0..1].join(" ")[1..-2])
end
def self.parse_guard_id(record)
record.split(" ")[2].delete("#")
end
end
class Guard
attr_reader :id
attr_accessor :sleep_logs
def initialize(id, sleep_logs=[])
@id = id
@sleep_logs = Array(sleep_logs)
end
def add_sleep(sleep_log)
@sleep_logs << sleep_log
end
def total_sleep
sleep_logs.inject(0) { |sum, log| sum += log.length_in_minutes }
end
def sleepier_than(other_guard)
total_sleep > other_guard.total_sleep
end
def sleepiest_minute
sleeping_minute_frequencies.max_by{ |k,v| v }[0]
end
def sleepiest_minute_count
sleeping_minute_frequencies.max_by{ |k,v| v }[1]
end
def sleeping_minute_frequencies
midnight_hour = Hash.new(0)
sleep_logs.each do |log|
log.minutes_asleep.each { |min| midnight_hour[min] += 1 }
end
midnight_hour
end
end
class SleepLog
attr_reader :start_time, :end_time
def initialize(start_time, end_time)
@start_time = start_time
@end_time = end_time
end
def length_in_seconds
end_time - start_time
end
def length_in_minutes
length_in_seconds/60
end
def minutes_asleep
starting_min = start_time.min
ending_min = end_time.min
minutes_asleep = []
(starting_min...ending_min).each do |min|
minutes_asleep << min
end
minutes_asleep
end
end
class Analysis
attr_reader :guards
def initialize(guards)
@guards = guards
end
def sleepiest_guard
sleepiest_guard = guards[guards.keys.sample]
guards.each do |guard_id, guard|
sleepiest_guard = guard if guard.sleepier_than(sleepiest_guard)
end
sleepiest_guard
end
def sleepiest_guard_sleepiest_minute
guard = sleepiest_guard
sleepiest_minute = guard.sleepiest_minute
guard.id.to_i * sleepiest_minute
end
def most_frequently_asleep_guard
most_frequently_asleep_guard = guards[guards.keys.sample]
guards.each do |guard_id, guard|
if guard.sleepiest_minute_count > most_frequently_asleep_guard.sleepiest_minute_count
most_frequently_asleep_guard = guard
end
end
most_frequently_asleep_guard
end
def most_frequently_asleep_minute
guard = most_frequently_asleep_guard
sleepiest_minute = guard.sleepiest_minute
guard.id.to_i * sleepiest_minute
end
end
raw_records = File.readlines('inputs/day_4.txt').map { |line| line.strip }.sort
records_with_guards = Record.fill_in_guard(raw_records)
guards = Record.parse(records_with_guards)
# puts Analysis.new(guards).sleepiest_guard_sleepiest_minute
puts Analysis.new(guards).most_frequently_asleep_minute