求解 Advent of Code 第7天:Splitting Tachyon Beams

发布: (2025年12月17日 GMT+8 13:00)
6 min read
原文: Dev.to

Source: Dev.to

我最初在我的博客上发布了这篇文章。

今年,我在跟随 Advent of Code。我给自己设定了写“函数式-ish”解法的挑战。这是我最喜欢的谜题之一。

第 7 天的 Advent of Code 中,我们在研究快子光束,同时被困在传送器里。

我们被困在传送器里是因为我们一直在帮助精灵们进行所有的圣诞准备。但每一步都让情况更加复杂,简直是不可能完成的任务。我感觉自己像是《曼达洛人》的一集。不过,回到代码…

我把这个谜题想象成一个游戏,每一次迭代都让光束移动,直到它到达流形的尽头。

Source:

移动光束

Beam 是在给定迭代中位于流形(manifold)上的位置列表。

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

流形是一个字符串的二维数组。每个单元格可以是空格或分光器,例如:

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);

剩下的工作就是统计分裂次数并将光束移动到终点。

计数分裂

我们让光束自行移动,直到它到达流形的底部:

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

下一步是统计光束何时分裂。我在 Move() 中完成此操作。

完整解决方案(示例输入已硬编码)

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);

我曾以为 “tachyon”(快子)是个杜撰的词,直到我去谷歌搜索。 今天我才了解快子到底是什么。

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。有些会出现在多个条件语句中。我以前做过,我有信心能做到……

回文检查器

什么是回文?回文是一种单词、短语、数字或其他字符序列,无论正读还是倒读都相同,忽略空格、标点和大小写。