פיתרון Advent Of Code 2024 יום 4 בשפת Ruby
את התרגיל הזה קלוד לא הצליח לפתור, לפחות לא עם הפרומפט הפשוט שהדבקתי לו, לכן כבר הרגשתי שמח כשפתרתי אותו לבד. בסיפור שלנו היום אנחנו מקבלים קלט בצורה של מטריצה עם כל מיני אותיות למשל:
..X...
.SAMX.
.A..A.
XMAS.S
.X....
בחלק הראשון עלינו למצוא את כל המופעים של המילה XMAS בקלט אבל בכל הכיוונים (כולל אלכסונים והפוך), כמו בתפזורת מילים. בחלק השני צריך לחפש רק מופעים של MAS שמגיעים בצורת X כלומר:
M.S
.A.
M.S
וגם הם יכולים להיות הפוכים.
התרגיל המקורי נמצא בעמוד שלהם כאן: https://adventofcode.com/2024/day/4
1. פיתרון חלק 1
בשביל שני החלקים היה לי נוח לשמור את הקלט במילון, כשהמפתח הוא אינדקס והערך הוא התו שנמצא באינדקס הזה. בתרגילים של AoC למדתי שיותר קל לעבוד עם מילונים כאלה מאשר עם מערכים דו מימדיים. זה הקוד שיוצר את המילון ברובי:
$matrix = File.read('input.txt').lines.each_with_index.flat_map do |line, line_index|
line.split('').each_with_index.map do |char, column_index|
{[line_index, column_index] => char }
end
end.reduce({}) {|acc, val| acc.merge(val) }
קצת ארוך אבל עובד. אם יש לכם רעיונות יותר קצרים אפשר לשתף בתגובות.
הפונקציה הבאה שכתבתי היתה go שפשוט מתקדמת מספר צעדים בכיוון מסוים. הכיוון הכללי לפיתרון היה לרוץ על כל האינדקסים במילון, מכל אינדקס להתקדם 4 צעדים לכל 8 הכיוונים ולראות אם כתובה שם המילה XMAS. הפונקציה go נראית כך:
def go(start, direction, steps = 4)
Enumerator.produce(start) { |r, c| [r + direction[0], c + direction[1]] }.take(steps)
end
והפונקציה המרכזית של הפיתרון היא count_words_around
שלוקחת נקודה ומריצה את go לכל 8 הכיוונים ואז סופרת כמה מהכיוונים האלה מכילים את המילה XMAS:
def count_words_around(point)
indexes = [[0, 1],
[1, 1],
[1, 0],
[1, -1],
[0, -1],
[-1, -1],
[-1, 0],
[-1, 1]].map { |direction| go(point, direction, 4) }
indexes.count { |path| $matrix.slice(*path).values.join('') == 'XMAS' }
end
pp $matrix.keys.map {|point| count_words_around(point) }.sum
2. חלק 2
בחלק השני יצרתי מטריצה באותו אופן אבל על הפונקציה go כבר וויתרתי. במקום ללכת 4 צעדים מספיק לקחת את ה X שמסביב לנקודה ולבדוק אם כתוב בו MAS או SAM. זה הקוד:
def count_words_around(point)
return 0 if $matrix[point] != 'A'
around = [
[-1, -1],
[0, 0],
[1, 1],
[-1, 1],
[0, 0],
[1, -1]
].map { |direction| [point[0] + direction[0], point[1] + direction[1]] }
.map {|i| $matrix[i] }.join('')
if %w[MASMAS MASSAM SAMMAS SAMSAM].include?(around)
1
else
0
end
end
pp $matrix.keys.map {|point| count_words_around(point) }.sum