cem 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/cem.gemspec +2 -2
- data/examples/aoc2018/day1.rb +13 -0
- data/examples/aoc2018/day1_part2.rb +30 -0
- data/examples/aoc2018/day2.rb +20 -0
- data/examples/aoc2018/day2_2.rb +27 -0
- data/examples/aoc2018/day3.rb +71 -0
- data/examples/aoc2018/day4.rb +46 -0
- data/examples/aoc2018/day5.rb +23 -0
- data/examples/aoc2018/day5_part2.rb +29 -0
- data/examples/aoc2018/day6.rb +53 -0
- data/examples/aoc2018/day7.rb +110 -0
- data/examples/aoc2018/day8.rb +39 -0
- data/examples/aoc2018/day8_part2.rb +65 -0
- data/examples/aoc2018/inputs/day1_input.txt +955 -0
- data/examples/aoc2018/inputs/day2_input.txt +250 -0
- data/examples/aoc2018/inputs/day3_input.txt +1233 -0
- data/examples/aoc2018/inputs/day4_input.txt +1140 -0
- data/examples/aoc2018/inputs/day5_input.txt +1 -0
- data/examples/aoc2018/inputs/day6_input.txt +50 -0
- data/examples/aoc2018/inputs/day7_input.txt +101 -0
- data/examples/aoc2018/inputs/day8_input.txt +1 -0
- data/lib/cem/cflame/popen.rb +89 -0
- data/lib/cem/cruzzles.rb +105 -12
- data/lib/cem/version.rb +1 -1
- metadata +28 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a12790b597c9fd5c63fc14b855b964d32aeda5f968d612806e8d80697bbb37c4
|
4
|
+
data.tar.gz: 0acf18fd6f7dafe94553e55dca0e89c3304066b5ec85d1413187eb4afe6d7774
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b8f6e808871a8b4197126f576940ca6a98daff481339ab4f9830316fecf2b4cab2d3bf7000b18ed39276731d2a431408dccfd799fc4ec784ac3901ade4f27eb
|
7
|
+
data.tar.gz: 142741554b2f214d0af5cbffbc0ecb9860ef9e7870697863af38eab01c3a811b3ac459cad093cc1b372962d7ba224beeb8c86a2bd58dc7f96c460e93bcbb4c43
|
data/.gitignore
CHANGED
data/cem.gemspec
CHANGED
@@ -35,8 +35,8 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
36
36
|
spec.require_paths = ["lib"]
|
37
37
|
|
38
|
-
spec.add_development_dependency "bundler", "~> 1.17
|
39
|
-
spec.add_development_dependency "rake", "~> 10.0
|
38
|
+
spec.add_development_dependency "bundler", "~> 2.1" # Was 1.17
|
39
|
+
spec.add_development_dependency "rake", "~> 13.0" # Was: 10.0
|
40
40
|
spec.add_development_dependency "rspec", "~> 3.0"
|
41
41
|
|
42
42
|
spec.add_runtime_dependency 'flammarion', '~> 0.3'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/1 Part 2
|
4
|
+
#
|
5
|
+
# Does not use any cem functions \o/ but did you know:
|
6
|
+
#
|
7
|
+
# - Set provides #[] as a class method: Set[1,2,3] is the same as Set.new() and then Set.add(...)
|
8
|
+
# - Set provides #add?() to add and check if the object added was already in the Set (returns nil in case).
|
9
|
+
#
|
10
|
+
# For example: Set[0,1].add?(1) => nil
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'set'
|
14
|
+
|
15
|
+
cur = 0
|
16
|
+
seen_before = Set[0]
|
17
|
+
|
18
|
+
while true
|
19
|
+
File.read("inputs/day1_input.txt").each_line { |line|
|
20
|
+
|
21
|
+
cur += line.to_i
|
22
|
+
|
23
|
+
if !seen_before.add?(cur)
|
24
|
+
puts cur
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Unreachable!
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/2
|
4
|
+
#
|
5
|
+
# Does not use any cem functions \o/
|
6
|
+
#
|
7
|
+
twice = 0
|
8
|
+
thrice = 0
|
9
|
+
|
10
|
+
chars = [*'a'..'z', *'A'..'Z']
|
11
|
+
|
12
|
+
File.read("inputs/day2_input.txt").each_line { |l|
|
13
|
+
|
14
|
+
twice += 1 if chars.any? { |c| l.count(c) == 2 }
|
15
|
+
thrice += 1 if chars.any? { |c| l.count(c) == 3 }
|
16
|
+
|
17
|
+
}
|
18
|
+
|
19
|
+
puts "1st star: #{twice * thrice}"
|
20
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/2 part 2
|
4
|
+
#
|
5
|
+
# Does not use any cem functions \o/
|
6
|
+
|
7
|
+
previous = ''
|
8
|
+
File.readlines("inputs/day2_input.txt").sort.each { |l|
|
9
|
+
|
10
|
+
mismatch = 0
|
11
|
+
s = ''
|
12
|
+
if previous != ''
|
13
|
+
l.split("").each_with_index { |c, i|
|
14
|
+
if previous[i] != c
|
15
|
+
mismatch += 1
|
16
|
+
else
|
17
|
+
s += c
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
if mismatch == 1
|
23
|
+
puts s
|
24
|
+
end
|
25
|
+
|
26
|
+
previous = l
|
27
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/3 part 1 and 2
|
4
|
+
#
|
5
|
+
# Demonstrates: Point2D, min(a,b), Array::with_progress
|
6
|
+
#
|
7
|
+
# Areas for improvement: Rect intersection
|
8
|
+
|
9
|
+
require 'set'
|
10
|
+
require 'cem'
|
11
|
+
|
12
|
+
claims = []
|
13
|
+
intersections = Set.new
|
14
|
+
doesIntersect = Set.new
|
15
|
+
|
16
|
+
Claim = Struct.new("Claim", :x, :y, :width, :height, :claimId)
|
17
|
+
|
18
|
+
File.readlines("inputs/day3_input.txt").with_progress.each { |l|
|
19
|
+
|
20
|
+
if l =~ /^\#(\d+) \@ (\d+),(\d+)\: (\d+)x(\d+)$/
|
21
|
+
|
22
|
+
claim = Claim.new($2.to_i, $3.to_i, $4.to_i, $5.to_i, $1.to_i)
|
23
|
+
|
24
|
+
claims.each { |other|
|
25
|
+
|
26
|
+
x = claim.x
|
27
|
+
y = claim.y
|
28
|
+
w = claim.width
|
29
|
+
h = claim.height
|
30
|
+
|
31
|
+
x2 = other.x
|
32
|
+
y2 = other.y
|
33
|
+
w2 = other.width
|
34
|
+
h2 = other.height
|
35
|
+
|
36
|
+
if x2 < x
|
37
|
+
x, x2 = x2, x
|
38
|
+
w, w2 = w2, w
|
39
|
+
end
|
40
|
+
|
41
|
+
if y2 < y
|
42
|
+
y, y2 = y2, y
|
43
|
+
h, h2 = h2, h
|
44
|
+
end
|
45
|
+
|
46
|
+
# puts "#{claim} - #{other}"
|
47
|
+
|
48
|
+
if x + w >= x2 && y + h >= y2
|
49
|
+
|
50
|
+
width = min(x2 + w2, x + w)
|
51
|
+
height = min(y2 + h2, y + h)
|
52
|
+
|
53
|
+
doesIntersect.add(other)
|
54
|
+
doesIntersect.add(claim)
|
55
|
+
|
56
|
+
for a in x2...width
|
57
|
+
for b in y2...height
|
58
|
+
# puts "#{a} #{b}"
|
59
|
+
intersections.add(Point2D.new(a,b))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
}
|
65
|
+
|
66
|
+
claims << claim
|
67
|
+
end
|
68
|
+
}
|
69
|
+
|
70
|
+
puts "Part 1: #{intersections.size}"
|
71
|
+
puts "Part 2: #{claims.to_set.subtract(doesIntersect).first.claimId}"
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/4
|
4
|
+
#
|
5
|
+
# Does not use any cem functions \o/
|
6
|
+
|
7
|
+
Guard = Struct.new("Guard", :id, :total, :minutes)
|
8
|
+
|
9
|
+
guards = {}
|
10
|
+
guard = nil
|
11
|
+
asleep = nil
|
12
|
+
|
13
|
+
File.readlines("inputs/day4_input.txt", chomp: true).sort.each { |l|
|
14
|
+
|
15
|
+
if l =~ /Guard \#(\d+) begins shift$/
|
16
|
+
|
17
|
+
id = $1.to_i
|
18
|
+
guard = guards[id] ||= Guard.new(id, 0, [0] * 60)
|
19
|
+
|
20
|
+
elsif / 00:(?<minute>\d+)\] falls asleep$/ =~ l
|
21
|
+
|
22
|
+
asleep = minute.to_i
|
23
|
+
|
24
|
+
elsif l =~ / 00:(\d+)\] wakes up$/
|
25
|
+
|
26
|
+
awake = $1.to_i
|
27
|
+
|
28
|
+
guard.total += awake - asleep
|
29
|
+
(asleep...awake).each { |min|
|
30
|
+
guard.minutes[min] += 1
|
31
|
+
}
|
32
|
+
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
guard = (guards.values.sort_by {|g| g.total}).last
|
37
|
+
puts "Part1: #{guard.id * guard.minutes.each_with_index.max[1]}"
|
38
|
+
|
39
|
+
guard = (guards.values.sort_by {|g| g.minutes.each_with_index.max[0] }).last
|
40
|
+
puts "Part2: #{guard.id * guard.minutes.each_with_index.max[1]}"
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/5 Part 1
|
4
|
+
#
|
5
|
+
# Does not use any cem functions \o/ but did you know:
|
6
|
+
#
|
7
|
+
# - String#swapcase turns "Hello" into "hELLO"?
|
8
|
+
#
|
9
|
+
|
10
|
+
out = []
|
11
|
+
|
12
|
+
File.read("inputs/day5_input.txt").each_char { |c|
|
13
|
+
|
14
|
+
if out.empty? || out.last != c.swapcase
|
15
|
+
out << c
|
16
|
+
else
|
17
|
+
out.pop
|
18
|
+
end
|
19
|
+
|
20
|
+
}
|
21
|
+
|
22
|
+
puts out.join.size
|
23
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/5 Part 2
|
4
|
+
#
|
5
|
+
# Does not use any cem functions \o/ but did you know:
|
6
|
+
#
|
7
|
+
# - String#swapcase turns a Hello into hELLO?
|
8
|
+
# - Regex support 'i' for insensitive matches?
|
9
|
+
#
|
10
|
+
|
11
|
+
File.readlines("inputs/day5_input.txt").each { |line|
|
12
|
+
|
13
|
+
puts [*'a'..'z'].map { |delete|
|
14
|
+
|
15
|
+
out = []
|
16
|
+
|
17
|
+
line.gsub(/#{delete}/i, '').each_char { |c|
|
18
|
+
if out.empty? || out.last != c.swapcase
|
19
|
+
out << c
|
20
|
+
else
|
21
|
+
out.pop
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
out.join.size
|
26
|
+
}.min
|
27
|
+
}
|
28
|
+
|
29
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/6 Part 1 and 2
|
4
|
+
#
|
5
|
+
# Uses Point2D from cem
|
6
|
+
|
7
|
+
require 'cem'
|
8
|
+
|
9
|
+
out = {}
|
10
|
+
points = []
|
11
|
+
largestRegion = 0
|
12
|
+
|
13
|
+
File.readlines("inputs/day6_input.txt", chomp: true).each { |line|
|
14
|
+
if line =~ /^(\d+), (\d+)$/
|
15
|
+
v1 = $1.to_i
|
16
|
+
v2 = $2.to_i
|
17
|
+
|
18
|
+
points << Point2D.new(v1, v2)
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
minX, maxX = points.map { |p| p.x }.minmax
|
23
|
+
minY, maxY = points.map { |p| p.y }.minmax
|
24
|
+
|
25
|
+
(minX..maxX).each { |x|
|
26
|
+
(minY..maxY).each { |y|
|
27
|
+
|
28
|
+
coord = Point2D.new(x,y)
|
29
|
+
|
30
|
+
nearest = points.group_by { |p| p.manhattan(coord) }.min_by { |k,v| k }
|
31
|
+
|
32
|
+
# puts nearest.inspect
|
33
|
+
if nearest.last.size == 1
|
34
|
+
(out[nearest.last.first] ||= []) << coord
|
35
|
+
end
|
36
|
+
|
37
|
+
if points.sum { |p| p.manhattan(coord) } < 10000
|
38
|
+
largestRegion += 1
|
39
|
+
end
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
puts "Part 1"
|
44
|
+
puts out.max_by { |k,v|
|
45
|
+
if v.select { |coord| (coord.x == maxX || coord.x == minX || coord.y == maxY || coord.y == minY) }.empty?
|
46
|
+
v.size
|
47
|
+
else
|
48
|
+
0 # don't care about infinite
|
49
|
+
end
|
50
|
+
}.last.size
|
51
|
+
|
52
|
+
puts "Part 2"
|
53
|
+
puts largestRegion
|
@@ -0,0 +1,110 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/7 part 1 and 2
|
4
|
+
#
|
5
|
+
# Does not use any cem functions \o/
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'set'
|
9
|
+
|
10
|
+
Worker = Struct.new("Worker", :readyAt, :workingOn)
|
11
|
+
|
12
|
+
def read
|
13
|
+
input = File.readlines("inputs/day7_input.txt", chomp: true)
|
14
|
+
|
15
|
+
@edges = {}
|
16
|
+
@chars = Set.new
|
17
|
+
|
18
|
+
input.each { |line|
|
19
|
+
|
20
|
+
if line =~ /^Step (.+) must be finished before step (.+) can begin.$/
|
21
|
+
to = $1
|
22
|
+
from = $2
|
23
|
+
|
24
|
+
@chars.add(to)
|
25
|
+
@chars.add(from)
|
26
|
+
|
27
|
+
(@edges[from] ||= []) << to
|
28
|
+
end
|
29
|
+
|
30
|
+
@chars.each { |c| @edges[c] ||= [] }
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def anyWorkerReady
|
35
|
+
return @idleWorkers.size > 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def availableWork
|
39
|
+
return @chars.select { |c| @edges.include?(c) && @edges[c].size == 0 }.sort
|
40
|
+
end
|
41
|
+
|
42
|
+
def anyWorkAvailable
|
43
|
+
return availableWork.size > 0
|
44
|
+
end
|
45
|
+
|
46
|
+
def timeStep
|
47
|
+
|
48
|
+
puts "#{@timeNow}: #{@busyWorkers.inspect}" if $DEBUG
|
49
|
+
|
50
|
+
w = @busyWorkers.min_by { |w| w.readyAt }
|
51
|
+
@timeNow = w.readyAt
|
52
|
+
@busyWorkers -= [w]
|
53
|
+
@idleWorkers += [w]
|
54
|
+
|
55
|
+
c = w.workingOn
|
56
|
+
|
57
|
+
@result += c
|
58
|
+
|
59
|
+
@edges.update(@edges) { |k,v|
|
60
|
+
v - [c]
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def scheduleWork
|
65
|
+
|
66
|
+
nextTask = availableWork.first
|
67
|
+
|
68
|
+
w = @idleWorkers.pop
|
69
|
+
@busyWorkers += [w]
|
70
|
+
w.workingOn = nextTask
|
71
|
+
w.readyAt = @timeNow + 61 + nextTask.ord - 'A'.ord
|
72
|
+
@edges.delete(nextTask)
|
73
|
+
|
74
|
+
puts "Scheduling #{nextTask} to be ready at #{w.readyAt}" if $DEBUG
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def process(parallelism)
|
79
|
+
|
80
|
+
read()
|
81
|
+
|
82
|
+
@timeNow = 0
|
83
|
+
@result = ""
|
84
|
+
|
85
|
+
@busyWorkers = []
|
86
|
+
@idleWorkers = []
|
87
|
+
parallelism.times { @idleWorkers << Worker.new(0, '') }
|
88
|
+
|
89
|
+
loop do
|
90
|
+
|
91
|
+
while (!anyWorkerReady || !anyWorkAvailable) && @busyWorkers.size > 0
|
92
|
+
timeStep
|
93
|
+
end
|
94
|
+
|
95
|
+
if !anyWorkAvailable
|
96
|
+
break
|
97
|
+
end
|
98
|
+
|
99
|
+
scheduleWork
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
puts "Parallelism: #{parallelism}"
|
104
|
+
puts @result
|
105
|
+
puts @timeNow
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
process(1)
|
110
|
+
process(5)
|