שלושה פתרונות ראשונים ל Advent Of Code 2025

06/12/2025

עוד שנה נגמרת וכמו בכל דצמבר אריק ווסטל מפרסם שוב סט חידות תכנות חדש באתר Advent Of Code. הפעם מספר החידות ירד ל 12, בעיקר כי הוא קצת התעייף אבל אני חייב להודות שכמו עם העוגות של שמו, גם פה ההקטנה היא לטובה. כבר כמה שנים שלא הצלחתי למצוא זמן לסיים את כל הסט ואולי הפעם עם 12 חידות אוכל למצוא את המוטיבציה והזמן להתמיד.

בינתיים אני לא בקצב ואני מסיים את השבוע הראשון עם 3 חידות פתורות מתוך 5 שפורסמו. תכף החידות והפתרונות שלי אבל קודם הבהרה - אני מפרסם את הפתרונות האלה לא בתור פתרונות בית ספר שצריך ללמוד מהם (את זה אפשר לקבל מ ChatGPT שאלוף בחידות מהסוג הזה) אלא כדי לתת גם לכם מוטיבציה לנסות ולפתור. זה אולי לא מושלם, לא מספיק מהיר וקצת מסורבל אבל גם זה חלק מהקסם של לפתור לבד ולהתבלבל באינדקסים. בואו נראה את הקוד.

1. יום 1 - הכספת

התרגיל כאן:

https://adventofcode.com/2025/day/1

מאיזושהי סיבה כשהתחלתי את המשחק חשבתי שפייתון היא השפה המושלמת אז פתרתי בה. אל דאגה מהר מאוד חזרתי לרובי. יום ראשון חלק 1:

def move_dial(old_value, line):
    count = int(line[1:])

    if line.startswith("L"):
        return (old_value - count) % 100
    elif line.startswith("R"):
        return (old_value + count) % 100
    else:
        raise Exception(f"Line {line}")

dial = 50
zero_count = 0

with open('input.txt', encoding='utf-8') as f:
    for line in f:
        dial = move_dial(dial, line)
        if dial == 0:
            zero_count += 1

print(f"{zero_count=}")

חלק 2 - ארוך מדי וטעויות טפשיות בחשבון אבל בסוף זה עבד:

def dial_diff(line):
    count = int(line[1:])

    if line.startswith("L"):
        return -count
    elif line.startswith("R"):
        return count
    else:
        raise Exception(f"Line {line}")

dial = 50
zero_count = 0

with open('input.txt', encoding='utf-8') as f:
    for line in f:
        count = dial_diff(line)
        full_rounds = abs(count) // 100

        if count > 0:
            # move right
            next_dial = (dial + count) % 100
            if (next_dial < dial and next_dial != 0):
                full_rounds += 1

        elif count < 0:
            next_dial = (dial + count) % 100
            if (next_dial > dial and next_dial != 0 and dial != 0):
                full_rounds += 1

        dial = next_dial
        zero_count += full_rounds
        if dial == 0:
            zero_count += 1

print(zero_count)

2. יום 2 - חנות מתנות

התרגיל כאן

https://adventofcode.com/2025/day/2

חלק ראשון חזרתי לרובי וכבר נשמתי לרווחה. את החלק הראשון עוד פתרתי בלי ביטויים רגולאריים אבל בחלק השני קיצרתי את החישובים ונתתי למנוע הביטויים הרגולאריים לעבוד בשבילי:

class Aoc2025Day2
  def initialize(input_file_name)
    @ranges = parse(input_file_name)
  end

  def parse(input_file_name)
    File
      .read(input_file_name)
      .split(',')
      .map {|r| r.split('-') }
      .map {|a, b| a.to_i..b.to_i }
  end

  def part1
    @ranges.flat_map {|r| r.filter {|id| valid?(id) } }.sum
  end

  def part2
    @ranges.flat_map {|r| r.filter {|id| id.to_s.match(/^(\w+)\1+$/) } }.sum
  end

  def valid?(id)
    ids = id.to_s
    ids[0...ids.length / 2] == ids[ids.length / 2...]
  end
end

if __FILE__ == $PROGRAM_NAME
  a = Aoc2025Day2.new("input.txt")
  puts a.part1
  puts a.part2
end

3. יום 3 - לובי

התרגיל כאן

https://adventofcode.com/2025/day/3

הייתי שמח לכתוב פתרון יותר יעיל שסורק את המערך רק פעם אחת אבל index ו max כבר בנויים ברובי ואצל מתכנתים העצלות לפעמים מנצחת. לפחות הצלחתי לחתוך את המחרוזת בלי להתבלבל יותר מדי באינדקסים. זה הקוד:

class Day3
  attr_accessor :banks

  def parse(input_file_name)
    @banks = File
      .read(input_file_name)
      .lines
      .map {|l| l.strip.split('') }
      .map {|bank| bank.map(&:to_i) }
  end

  def part1
    values = banks.map {|b| iterate_bank(b, 2) }
    puts values.sum
  end

  def part2
    values = banks.map {|b| iterate_bank(b, 12) }
    puts values.sum
  end

  def iterate_bank(bank, num_batteries)
    value = 0
    next_digit_index = 0

    num_batteries.times do |i|
      options = bank[next_digit_index..-(num_batteries - i)]
      next_digit = options.max
      next_digit_index += options.index(next_digit) + 1
      value += next_digit * (10 ** (num_batteries - 1 - i))
    end

    value
  end
end

if $PROGRAM_NAME == __FILE__
  d = Day3.new
  d.parse("input.txt")
  d.part1
  d.part2
end