Advent of Code Day 7 풀이: 타키온 빔 분할

발행: (2025년 12월 17일 오후 02:00 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

원래 이 글은 제 블로그에 올렸습니다.

올해는 Advent of Code를 따라가고 있습니다. 저는 스스로에게 “functionalish” 솔루션을 작성하도록 도전했습니다. 제가 가장 좋아한 퍼즐 중 하나를 소개합니다.

Advent of Code의 Day 7에서, 우리는 텔레포터에 갇힌 채로 타키온 빔을 연구하고 있습니다.

우리는 모든 크리스마스 준비를 돕기 위해 엘프들을 도우려다 텔레포터에 갇혔습니다. 하지만 매 단계마다 상황이 더 복잡해져서 불가능한 임무가 되었습니다. 마치 The Mandalorian의 한 에피소드에 나오는 느낌이죠. 어쨌든, 코드를 다시 보겠습니다…

저는 이 퍼즐을 매 반복마다 빔을 이동시켜 매니폴드의 끝에 닿을 때까지 진행되는 게임으로 상상합니다.

빔 이동

Beam은 주어진 반복 단계에서 매니폴드 안에 있는 위치들의 리스트입니다.

record Position(int X, int Y);
record Beam(IEnumerable<Location> Locations);

매니폴드는 문자열의 2차원 배열입니다. 각 셀은 빈 공간이거나 스플리터일 수 있습니다. 예시:

var manifold = new string[][]
{
    new[] { ".", ".", "S", ".", "." },
    new[] { ".", ".", ".", ".", "." },
    new[] { ".", ".", "^", ".", "." },
    new[] { ".", ".", ".", ".", "." }
};

빔을 이동시키는 메서드

static Beam Move(string[][] manifold, Beam beam)
{
    var newLocations = new HashSet<Position>();

    foreach (var current in beam.Locations)
    {
        var downward = manifold[current.X + 1][current.Y];
        if (downward == ".")
        {
            newLocations.Add(new Position(current.X + 1, current.Y));
        }
        else if (downward == "^")
        {
            // split the beam left and right
            newLocations.Add(new Position(current.X + 1, current.Y - 1));
            newLocations.Add(new Position(current.X + 1, current.Y + 1));
        }
    }

    return new Beam(newLocations);
}

시작 위치 찾기

static Beam Start(string[][] manifold)
{
    for (int i = 0; i ());
}

위 두 메서드를 사용하면 빔을 생성하고 아래쪽으로 이동시킬 수 있습니다:

var start       = Start(manifold);
var newPosition = Move(manifold, start);
newPosition     = Move(manifold, newPosition);

이제 남은 일은 스플릿 횟수를 세고 빔을 끝까지 이동시키는 것입니다.

Counting splits

우리는 빔이 자체적으로 움직여서 매니폴드의 바닥에 도달할 때까지 진행시킵니다:

var beam = Start(manifold);
while (!HasReachedTheEnd(manifold, beam))
{
    beam = Move(manifold, beam);
}

다음 단계는 빔이 갈라지는 순간을 세는 것입니다. 이를 Move() 안에서 수행합니다.

Full solution (sample input is hard‑coded)

var manifold = new string[][]
{
    new[] { ".", ".", ".", ".", ".", ".", ".", "S", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", "^", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", "^", ".", "^", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", "^", ".", "^", ".", "^", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", "^", ".", "^", ".", ".", ".", "^", ".", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", ".", "^", ".", "^", ".", ".", ".", "^", ".", "^", ".", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", ".", "^", ".", ".", ".", "^", ".", ".", ".", ".", ".", "^", ".", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." },
    new[] { ".", "^", ".", "^", ".", "^", ".", "^", ".", "^", ".", ".", ".", "^", "." },
    new[] { ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." }
};

var beam = Start(manifold);
while (!HasReachedTheEnd(manifold, beam))
{
    beam = Move(manifold, beam);
}

Console.WriteLine(beam.SplitCount);
Console.ReadLine();

static Beam Start(string[][] manifold)
{
    for (int i = 0; i ());
}

static bool HasReachedTheEnd(string[][] manifold, Beam beam)
{
    var anyBeam = beam.Locations.First();
    return anyBeam.X >= manifold.Length - 1;
}

static Beam Move(string[][] manifold, Beam beam)
{
    var splits       = 0;
    var newLocations = new HashSet<Position>();

    foreach (var current in beam.Locations)
    {
        var downward = manifold[current.X + 1][current.Y];
        if (downward == ".")
        {
            newLocations.Add(new Position(current.X + 1, current.Y));
        }
        else if (downward == "^")
        {
            splits++;
            newLocations.Add(new Position(current.X + 1, current.Y - 1));
            newLocations.Add(new Position(current.X + 1, current.Y + 1));
        }
    }

    return new Beam(beam.SplitCount + splits, newLocations);
}

record Position(int X, int Y);
record Beam(int SplitCount, IEnumerable<Position> Locations);

나는 “타키온”이란 단어가 만들어낸 말이라고 생각했는데 구글링을 해보니 실제 존재한다는 것을 알게 되었습니다. 타키온이 정확히 무엇인지 이제 알게 되었네요.

A tachyon is. Win‑win.

Et voilà!

Advent of Code sharpens your coding skills. But coding is more than typing symbols fast. It's also about teamwork, collaboration, and many skills I share in my book, *Street‑Smart Coding: 30 Ways to Get Better at Coding.* That's the roadmap I wish I'd known from day one.

**[Get your copy of Street‑Smart Coding here](https://imcsarag.gumroad.com/l/streetsmartcoding/?utm_source=devto&utm_medium=post&utm_campaign=advent-2025-7)**
Back to Blog

관련 글

더 보기 »

원숭이 시장

파트 1 또 다른 math gauntlet, 나는 여러 math operations를 프로그래밍하게 된다. 일부는 여러 conditionals의 일부가 될 것이다. 나는 이전에 해본 적이 있다. 나는 자신 있다.

팰린드롬 검사기

팔린드롬이란 무엇인가? 팔린드롬은 단어, 구절, 숫자 또는 기타 문자 시퀀스로, 공백, 구두점 및 대소문자를 무시하고 앞뒤가 동일하게 읽히는 것을 말한다.