require 'set'
class Fabric
attr_accessor :fabric
def initialize
@fabric = {}
@clean_claims = Set.new
@fabric.default_proc = proc do |hash, key|
hash[key] = []
end
end
# Example claim: #1 @ 1,3: 4x4
def <<(claim)
_, id, left, top, w, h = *claim.match(/^\#(\d+) @ (\d+),(\d+): (\d+)x(\d+)/).to_a.map(&:to_i)
@clean_claims << id
w.times do |col|
h.times do |row|
pos = [row + top, col + left]
@fabric[pos] << id
if @fabric[pos].length > 1
@fabric[pos].each {|cid| @clean_claims.delete(cid) }
end
end
end
end
def part1
@fabric.values.select {|l| l.length > 1}.count
end
def part2
@clean_claims
end
end
fabric = Fabric.new
ARGF.each_line do |line|
fabric << line.strip
end
puts fabric.part1
puts fabric.part2.first
הרבה פעמים כשאנחנו חושבים על ייצור מטריצות מערך הוא מבנה הנתונים הראשון שקופץ לראש. שווה לציין שלפעמים Hash יהיה יותר נוח, במיוחד כשלא יודעים מראש את הגודל
import re
import numpy as np
MAX = 1010
RE = re.compile(r"^#(\d+) @ (\d+),(\d+): (\d+)x(\d+)$")
def add_blocks(s):
a = np.zeros((MAX, MAX), dtype=int)
for line in s.splitlines():
id, x, y, w, h = [int(x) for x in RE.match(line).groups()]
assert x + w < MAX and y + h < MAX
a[y:y + h, x:x + w] += 1
return a
def f(s):
a = add_blocks(s)
# for fun:
# import matplotlib.pyplot as plt
# plt.imshow(a, cmap=plt.cm.Paired)
# plt.colorbar()
# plt.show()
return (a > 1).sum()
def f2(s):
a = add_blocks(s)
for line in s.splitlines():
id, x, y, w, h = [int(x) for x in RE.match(line).groups()]
if np.all(a[y:y + h, x:x + w] == 1):
yield id
inp = """#1 @ 1,3: 4x4
#2 @ 3,1: 4x4
#3 @ 5,5: 2x2"""
assert f(inp) == 4
print(f(open("day3.txt").read()))
assert list(f2(inp)) == [3]
print(list(f2(open("day3.txt").read())))
כן בחלק מהחידות כאן יש תחושה שהוא כתב את זה עם numpy בראש - עוד משהו שחסר לי ברובי. איך החלטת לבחור דווקא את 1010 כמקסימום? לא עדיף להוסיף לולאת איתחול שעוברת על הקלט לחפש את הגדלים?
אני גם התחלתי עם מטריצה של מערכים, ועברתי ל Hash כשהבנתי שרצתי מהר מדי לפתרון ה"אינטואיטיבי". מצרף פיתרון ב Go שמשתמש ב struct נוספים כדי לפרסר את הקלט
type fabric map[point]int
// add new claim to fabric
func (f fabric) addClaim(c *claim) {
var p point
for row := c.leftEdge; row < c.leftEdge+c.width; row++ {
for col := c.topEdge; col < c.topEdge+c.height; col++ {
p = point{x: row, y: col}
if _, ok := f[p]; !ok {
f[p] = 1
} else {
f[p]++
}
}
}
}
// count square inches of fabric within two or more claims
func (f fabric) countClaims() int {
var counter int
for _, n := range f {
if n > 1 {
counter++
}
}
return counter
}
// return true if claim doesn't overlap with any other claims
func (f fabric) isOverlap(c *claim) bool {
var p point
for row := c.leftEdge; row < c.leftEdge+c.width; row++ {
for col := c.topEdge; col < c.topEdge+c.height; col++ {
p = point{x: row, y: col}
if f[p] != 1 {
return true
}
}
}
return false
}
type point struct {
x int
y int
}
type claim struct {
id string
topEdge int
leftEdge int
width int
height int
}