Advent Of Code 2022 ํผ์ฆ์ ์๋ฃํ๊ธฐ ์ํ ์ฌ๋ก๊ทธ๋ฅผ ์์ํฉ๋๋ค.
๋ชฉ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ํ์ด์ ์ ํฉํ LINQ ์ฌ์ฉ๋ฒ ์๋ฌ
- ํ์ด ํ ๋ค๋ฅธ ๋ถ์ ํ์ด๋ฅผ ์ดํด๋ณด๋ฉฐ ์ข ๋ ํจ๊ณผ์ ์ธ ์ฝ๋ ์ต๋
Advent Of Code 2022 ํผ์ฆ์ ์๋ฃํ๊ธฐ ์ํ ์ฌ๋ก๊ทธ๋ฅผ ์์ํฉ๋๋ค.
๋ชฉ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ด์ ํ์ด ์ด๋ ฅ
AoC ๋ฌธ์ ์ ํฅ๋ฏธ๋ก์ด ํน์ง์ ๋ฌธ์ ์ ํํ์ด ๊ฐ์กฐ์์ด ์๋ ์์ ์ ์ด๋ฉฐ ์คํ ๋ฆฌ๊ฐ ์์ด์ ๋ง์น ์ฐ๋ฆฌ๊ฐ ํ์ด์ผ ํ๋ ์ผ์ ์ํ์ ๋ฌธ์ ์ฒ๋ผ ๋ณด์ด๊ฒ ํฉ๋๋ค. ์คํ ๋ฆฌ๊ฐ ์์ด์ ์ด๋ค ๋ฉด์์๋ ๋ถํ์ํด ๋ณด์ด๋ ๋ฌธ์ฅ๋ ์์ด ๋ณด์ ๋๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ์์์ ๊ทธ ๋ต์ ์๋ ค์ค์ ์ ๋๋ก ํ๊ณ ์๋์ง ๊ฒํ ํ ์ ์๋๋ก ํฉ๋๋ค.
์ด๋ ๊ฒ ๋ฌธ์ ๋ฅผ ๋ด๋ ์ด์ ๋ ์๋ง๋ ์ผ์์ํ์์ ํด๊ฒฐํด์ผ ํ ๋ฌธ์ ๋ฅผ ์ฌํํ๊ธฐ ์ํ ๊ฒ์ผ์ง ๋ชจ๋ฆ ๋๋ค. ์ฐ๋ฆฌ๋ ๊ทธ ์์์ ํจํด์ ์ฐพ๊ณ ํจํด์ ๊ท์น์ฑ์์ ๊ณต์์ ์ฐพ์ ํ ๊ทธ ๊ณต์์ผ๋ก ์ฝ๋๋ก ๊ตฌํํ๊ธฐ ๋ฉ๋๋ค.
๋ฌธ์์ด ์ค ์ฐ์๋ 4๊ฐ์ ๋ฌธ์๊ฐ ์ค๋ณต๋์ง ์๋ ์์น๋ฅผ ์ฐพ๋ ๋ฌธ์ ์ ๋๋ค.
โbvwbjplbgvbhsrlpgdmjqwftvnczโ
โnppdvjthqldpwncqszvftbrmjlhgโ
โฆ
๋ค์์ ํ์ด์ ๋๋ค.
public static string Solve1(string input)
{
for (var i = 0; i < input.Length; i++)
{
// ์ด 4๊ฐ์ ๋ฌธ์๊ฐ ์ค๋น๋ ๋๊น์ง ์ฒ๋ฆฌํ์ง ์์
if (i < 4)
continue;
var packet = input[(i - 4)..i];
if (IsMarker(packet) is true)
return i.ToString();
}
return (-1).ToString();
bool IsMarker(string packet)
{
return packet.Distinct().SequenceEqual(packet);
}
}
ํจํท ์์ ๋ง์ปค๊ฐ ์๋ ๋ฉ์์ง ํจํท ๋ง์ปค๋ฅผ ์ฐป๋ ๋ฌธ์ ๋ก 4๊ฐ๊ฐ ์๋ 14๊ฐ์ ์ฐ์๋ ๊ฐ๋ณ๋ฌธ์์ฌ์ผ ํฉ๋๋ค. ์์ ์ฝ๋์์ ์ฝ๊ฐ์ ์์ ์ผ๋ก ๋ต์ ์ ์ ์์ต๋๋ค.
public static string Solve2(string input)
{
for (var i = 0; i < input.Length; i++)
{
// ์ด 14๊ฐ์ ๋ฌธ์๊ฐ ์ค๋น๋ ๋๊น์ง ์ฒ๋ฆฌํ์ง ์์
if (i < 14)
continue;
var packet = input[(i - 14)..i];
if (IsMarker(packet) is true)
return i.ToString();
}
return (-1).ToString();
bool IsMarker(string packet)
{
return packet.Distinct().SequenceEqual(packet);
}
}
๋ค๋ฅธ ๋ถ๋ค์ ํ์ด๊ฐ ๊ถ๊ธํฉ๋๋ค.
Andrea Angella๋์ ํ์ด์ ๋๋ค. ์ ๋ ๊ฐ์ ํ์ด์ ํ๊ฐ์ง ๋ a-z ๋งํผ์ int ๋ฐฐ์ด์ ๋ง๋ค๊ณ ๊ฐ ์๋ฆฌ๊ฐ ๋ฐ์ํ ๋ ๊ฐ์ ์ฆ๊ฐ์ํด์ผ๋ก์จ ๋ง์ปค์ ์ค๋ณต๋ ๋ฌธ์๊ฐ ์๋์ง๋ฅผ ์ฒดํฌํ๋ ์ฝ๋๋ ํ์ธํ ์ ์์ต๋๋ค.
[TestCase(4, 1578)]
[TestCase(14, 2178)]
public void Test(int n, int expected)
{
var input = File.ReadAllText("Input.txt");
for (var i = n; i < input.Length; i++)
{
var sequence = input[(i - n)..i];
if (sequence.Distinct().SequenceEqual(sequence))
{
Assert.That(i, Is.EqualTo(expected));
return;
}
}
Assert.Fail();
}
[TestCase(4, 1578)]
[TestCase(14, 2178)]
public void TestWithArray(int n, int expected)
{
var letters = new int[26];
var input = File.ReadAllText("Input.txt");
for (var i = 0; i < input.Length; i++)
{
if (i >= n) letters[input[i-n]-'a']--;
letters[input[i]-'a']++;
if (letters.Sum() == n && letters.All(x => x <= 1))
{
Assert.That(i + 1, Is.EqualTo(expected));
return;
}
}
Assert.Fail();
}
Sound Code์ Mark Heath๋์ ์ฝ๋๋ ์ฌ๋ญ ๋ค๋ฆ ๋๋ค.
public (string, string) ExpectedResult => ("1892", "2313");
public int FindMarkerPosition(string input, int distinct) =>
input.Window(distinct).TakeUntil(w => w.ToHashSet().Count == distinct).Count() + distinct - 1;
public (string, string) Solve(string[] input)
{
return ($"{Part1(input)}", $"{Part2(input)}");
}
long Part1(IEnumerable<string> input) => FindMarkerPosition(input.First(), 4);
long Part2(IEnumerable<string> input) => FindMarkerPosition(input.First(), 14);
SuperLinq๋ฅผ ์ฌ์ฉํด์ ์์ ํ LINQ ์คํ์ผ๋ก ๋ฌธ์ ๋ฅผ ํธ์ จ๋ค์.
Mark Heath๋์ ์ฝ๋๋ฅผ ์ดํดํ๊ธฐ ์ํด SuperLINQ(MoreLINQ๋ก๋ ๊ฐ๋ฅ)๋ฅผ ์ด์ฉํด ์ฝ๋๋ฅผ ์ฌ์์ฑํ์์ต๋๋ค.
public static string Solve1_LINQ(string input)
{
var markerSize = 4;
var result = input.Window(markerSize)
.TakeUntil(x => x.ToHashSet().Count == markerSize)
.Count() + markerSize - 1;
return result.ToString();
}
Window(windowSize)
๋ ์๋์ฐ ์ฌ์ด์ฆ ๋งํผ ๋ชฉ๋ก์ ์ํํ ์ ์๊ฒ ํฉ๋๋ค.TakeUntil()
๋ ์กฐ๊ฑด์ด ์ฐธ์ผ๋๊น์ง ๋ชฉ๋ก์ ์ป์ต๋๋ค.ToHashSet()
์ผ๋ก ์ค๋ณต๋์ง ์๋ ์งํฉ์ ๋ง๋ญ๋๋ค.@dimohy ๋ ์ฌ๋ก๊ทธ๋ฅผ ๋ณด๊ณ ์ ๋ ๋ฐ๋ผ์ ํ์ด๋ณด๊ณ ์์ต๋๋ค. ๋งค ๋ 12์์ ์ฌ์ฌํ์ง ์๊ฒ ๋ณด๋ผ ์ ์๊ฒ ๋ค์. ์ข์ ์ ๋ณด ๊ณ ๋ง์ต๋๋ค~
์ฃผ์ด์ง ๋ช ๋ น์ด์ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ํตํด 100000 ๋ณด๋ค ์์ ๋๋ ํ ๋ฆฌ ์ฌ์ด์ฆ์ ์ดํฉ์ ๊ตฌํ๋ ๋ฌธ์ ์ ๋๋ค.
$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k
์ ์ฝ๋ฉ ์ค๋ ฅ์ผ๋ก๋ ์งง์ ์ฝ๋๊ฐ ๋์ค์ง ์๋๋ฐ์,
public static string Solve1(string input)
{
var lines = input.Split(Environment.NewLine);
var root = Parse(lines);
var result = root.SearchDirectories()
.Where(x => x.Size < 100000)
.Sum(x => x.Size);
return result.ToString();
}
static DirectoryNode Parse(string[] lines)
{
var root = new DirectoryNode(null, "/");
DirectoryNode? currentDirectory = null;
foreach (var line in lines)
{
// ๋ช
๋ น์ด์ ๊ฒฝ์ฐ ๋ช
๋ น ์ฒ๋ฆฌ
if (line.StartsWith("$") is true)
{
var tokens = line.Split(' ');
if (tokens[1] is "cd")
{
if (tokens[2] is "/")
currentDirectory = root;
else if (tokens[2] is "..")
{
currentDirectory = currentDirectory?.Parent;
}
else
{
var dictionaryName = tokens[2];
currentDirectory = currentDirectory?.Nodes.FirstOrDefault(x => x is DirectoryNode && x.Name == dictionaryName) as DirectoryNode;
}
}
else if (tokens[1] is "ls")
continue;
else
{
throw new InvalidOperationException();
}
}
// ์๋ ๊ฒฝ์ฐ ํ์ผ ์ฌ์ด์ฆ ์ทจํฉ
else
{
var tokens = line.Split(' ');
// ๋๋ ํ ๋ฆฌ
if (tokens[0] is "dir")
{
var newDirectory = new DirectoryNode(currentDirectory, tokens[1]);
currentDirectory?.AddNode(newDirectory);
}
// ํ์ผ
else
{
var newFile = new FileNode(tokens[1], long.Parse(tokens[0]));
currentDirectory?.AddNode(newFile);
}
}
}
return root;
}
abstract record Node(string Name)
{
public abstract long Size { get; }
}
record DirectoryNode(DirectoryNode? Parent, string Name) : Node(Name)
{
public IEnumerable<Node> Nodes { get; } = new List<Node>();
public override long Size
{
get
{
var totals = 0L;
foreach (var node in Nodes)
totals += node.Size;
return totals;
}
}
public IEnumerable<DirectoryNode> SearchDirectories()
{
foreach (var node in Nodes)
{
if (node is DirectoryNode directory)
{
yield return directory;
foreach (var subDirectory in directory.SearchDirectories())
yield return subDirectory;
}
}
}
public void AddNode(Node node) => (Nodes as List<Node>)!.Add(node);
}
record FileNode(string Name, long FileSize) : Node(Name)
{
public override long Size => FileSize;
}
ํ์ผ์์คํ
์ ์ด ์ฌ์ด์ฆ๋ 70000000์ด๊ณ ๋จ์ ์ฉ๋์ด 30000000์ด ํ์ํฉ๋๋ค.
ํ ๋๋ ํ ๋ฆฌ๋ฅผ ์ญ์ ํ์ ๋ ํ์ํ ๋จ์ ์ฉ๋์ ํ๋ณดํ๊ธฐ ์ํ ๋ฌธ์ ์
๋๋ค. ๊ธฐ์ค์ ๋ถํฉํ๋ฉด์ ๊ทธ์ค์ ๊ฐ์ฅ ์์ ๋๋ ํ ๋ฆฌ์ ์ฌ์ด์ฆ๋ฅผ ๊ตฌํ๋ฉด ๋ฉ๋๋ค.
public static string Solve2(string input)
{
var lines = input.Split(Environment.NewLine);
var root = Parse(lines);
var usedSize = root.Size;
var mustDeleteSize = 30000000 - (70000000 - usedSize);
var result = root.SearchDirectories()
.Where(x => x.Size > mustDeleteSize)
.OrderBy(x => x.Size)
.Select(x => x.Size)
.First();
return result.ToString();
}
๋ค๋ฅธ ๋ถ์ ์ฝ๋๋ฅผ ์ดํด๋ณผ ํ์๊ฐ ์์ด ๋ณด์ ๋๋ค.
์์ ค๋ผ ๋์ ์ ๋ ์ ์ฌํ๊ฒ ์งฐ์ต๋๋ค.
๋งํฌํ์ค๋๋โฆ ์ ์ฌํฉ๋๋ค.
public IEnumerable<DirectoryNode> SearchDirectories()
{
foreach (var node in Nodes)
{
if (node is DirectoryNode directory)
{
yield return directory;
foreach (var subDirectory in directory.SearchDirectories())
yield return subDirectory;
}
}
}
์ด ์ฝ๋๋ฅผ ๊ฐ์ ํ๊ณ ์ถ์๋ฐ์, ๋น์ฅ์ ๋ฑํ ์์ด๋์ด๊ฐ ๋ ์ค๋ฅด์ง ์์ต๋๋ค.
public IEnumerable<DirectoryNode> SearchDirectories()
{
foreach (var node in Nodes)
{
if (node is DirectoryNode directory)
{
yield return directory;
foreach (var subDirectory in directory.SearchDirectories())
yield return subDirectory;
}
}
}
์ด ๋ถ๋ถ์ ๋ํ ๋ต๊ธ์ ๋จ๊ฒจ์ผ๊ฒ ๋ค๋ผ๊ณ ์๊ฐํ๋ฉฐ ์ฝ๊ณ ์์๋๋ฐ, ์ญ์ ๊ฐ์ ์๊ฐ์ด์๋ค์ ใ ใ
์ด์ ๊ธ์์ LINQ๋ก ํ๊ณ ์ถ๋ค๊ณ ํ์ ์ ์ ๋ ์ด๋ ๊ฒ ํด๋ณด์์ต๋๋ค
public IEnumerable<DirectoryNode> SearchDirectories()
{
return Nodes.OfType<DirectoryNode>()
.SelectMany(directoryNode => directoryNode.SearchDirectories());
}
๊ตฟ์ ๋๋ค. ๋ต์ ๊ทธ๊ณณ์ ์์๊ตฐ์!
30373
25512
65332
33549
35390
์ซ์๋ ํ์๋ฆฌ์ ์ขํ์ด๋ฉฐ ๋๋ฌด์ ๋์ด๋ฅผ ์๋ฏธํฉ๋๋ค. 0์ ๊ฐ์ฅ ๋ฎ๊ณ 9๊ฐ ๊ฐ์ฅ ๋์ ๋๋ฌด์ ๋๋ค.
์ผ๋ฐ: ์กด ๋ฐ์์ ์, ํ, ์ข, ์ฐ ์ด ์ง์ญ์ ๊ด์ฐฐํ๋ฉด์ ๋ณด์ด๋ ๋๋ฌด์ ๊ฐ์๋ฅผ ๊ตฌํ๋ ๋ฌธ์ ์
๋๋ค.
์ฌํ: ๊ฒฝ์น๊ฐ ์ข์ ์์น๋ฅผ ๊ตฌํ๋ ๋ฌธ์ ์
๋๋ค. ์ง์ ์์ ์, ํ, ์ข, ์ฐ์ ๋๋ฌด๊ฐ ๋ง์ด ๋ณด์ผ ์๋ก ์ข์ ์์น์ด๋ฉฐ ์ ์๋ ๋ณด์ด๋ ๋๋ฌด ๊ฐฏ์๋ง๋ (์ ๋๋ฌด * ํ ๋๋ฌด * ์ข ๋๋ฌด * ์ฐ ๋๋ฌด)๊ฐ ๋ฉ๋๋ค.
์ ๋ ์ธ๋ จ๋๊ฒ ๋ง๋๋ ๋ฐฉ๋ฒ์ด ๋ฐ๋ก ๋ ์ค๋ฅด์ง ์์ ์ผ๋ฐ์ ์ผ๋ก ์ฝ๋ฉ์ ํ์ต๋๋ค. ๋ค๋ฅธ ๋ถ๋ค์ ์ฝ๋๊ฐ ๊ถ๊ธํ ์์ ์ด๊ตฐ์.
public static string Solve1(string input)
{
var map = MakeMap(input);
var check = new bool[map.GetLength(0), map.GetLength(1)];
for (var y = 0; y < map.GetLength(1); y++)
ScanH(y);
for (var x = 0; x < map.GetLength(0); x++)
ScanV(x);
var sum = 0;
for (var y = 0; y < check.GetLength(1); y++)
for (var x = 0; x < check.GetLength(0); x++)
sum += check[x, y] is true ? 1 : 0;
return sum.ToString();
void ScanH(int y)
{
var high1 = -1;
var high2 = -1;
var length = map.GetLength(0);
for (var x = 0; x < length; x++)
{
if (map[x, y] > high1)
{
high1 = map[x, y];
check[x, y] = true;
}
if (map[length - x - 1, y] > high2)
{
high2 = map[length - x - 1, y];
check[length - x - 1, y] = true;
}
}
}
void ScanV(int x)
{
var high1 = -1;
var high2 = -1;
var length = map.GetLength(1);
for (var y = 0; y < length; y++)
{
if (map[x, y] > high1)
{
high1 = map[x, y];
check[x, y] = true;
}
if (map[x, length - y - 1] > high2)
{
high2 = map[x, length - y - 1];
check[x, length - y - 1] = true;
}
}
}
}
static int[,] MakeMap(string input)
{
var lines = input.Split(Environment.NewLine);
var map = new int[lines[0].Length, lines.Length];
for (var y = 0; y < lines.Length; y++)
{
var line = lines[y];
for (var x = 0; x < line.Length; x++)
{
map[x, y] = int.Parse(line[x].ToString());
}
}
return map;
}
public static string Solve2(string input)
{
var map = MakeMap(input);
var maxScore = 0;
for (var y = 0; y < map.GetLength(1); y++)
{
for (var x = 0; x < map.GetLength(0); x++)
{
var score = ScanScore(x, y);
if (score > maxScore)
maxScore = score;
}
}
return maxScore.ToString();
int ScanScore(int x, int y)
{
var xLength = map.GetLength(0);
var yLength = map.GetLength(1);
var score = 1;
var center = map[x, y];
// ์ผ์ชฝ ํ์
var (sx, sy) = (x - 1, y);
var high = -1;
while (sx >= 0)
{
var another = map[sx, sy];
if (another > center && another <= high)
break;
if (another < center && center <= high)
break;
if (another > high)
high = another;
sx--;
}
score *= x - (sx + 1);
// ์ค๋ฅธ์ชฝ ํ์
(sx, sy) = (x + 1, y);
high = -1;
while (sx < xLength)
{
var another = map[sx, sy];
if (another > center && another <= high)
break;
if (another < center && center <= high)
break;
if (another > high)
high = another;
sx++;
}
score *= (sx - 1) - x;
// ์ ํ์
(sx, sy) = (x, y - 1);
high = -1;
while (sy >= 0)
{
var another = map[sx, sy];
if (another > center && another <= high)
break;
if (another < center && center <= high)
break;
if (another > high)
high = another;
sy--;
}
score *= y - (sy + 1);
// ์๋ ํ์
(sx, sy) = (x, y + 1);
high = -1;
while (sy < yLength)
{
var another = map[sx, sy];
if (another > center && another <= high)
break;
if (another < center && center <= high)
break;
if (another > high)
high = another;
sy++;
}
score *= (sy - 1) - y;
return score;
}
}
ํ ์์ ค๋ผ๋์ ํ์ด๋ ์ ๋ ์ฌ๋ญ ๋ค๋ฅด๊ตฐ์. ๋ฐฐ์ธ ์ ์, LINQ๋ก 2์ฐจ์ ๋ฐฐ์ด์ ๋ง๋ค์๋ค๋ ๊ฒ. (๋ง๋ค ์ ์๋ค๋ ๊ฒ!)
๋งํฌํ์ค์ ํ์ด๋ ๋๋ ๋ ธ์์ด๊ตฐ์. LINQ ์คํ์ผ๋ก ๋ฌธ์ ๋ฅผ ํ์์ต๋๋ค. ์ฝ๋๊ฐ ๋งค์ฐ ๊ฐ๊ฒฐํ๊ณ ์ฝ๋๋ฅผ ์ดํดํ ์๋ง ์๋ค๋ฉด ๊ฐ์ฅ ์๋ฆ๋ค์ด ์ฝ๋์ธ ๊ฒ ๊ฐ์ต๋๋ค.
public class Day8 : ISolver
{
public (string, string) ExpectedResult => ("1832", "157320");
private static readonly Coord[] dirs = new Coord[] { (0, 1), (1, 0), (0, -1), (-1, 0) };
public (string, string) Solve(string[] input)
{
var g = Grid<int>.ParseToGrid(input, c => c - '0');
return ($"{Part1(g)}", $"{Part2(g)}");
}
private long Part1(Grid<int> g)
=> g.AllPositions().Count(p => dirs.Any(d => g.LineOut(p,d).All(n => g[p] > g[n])));
public long ScenicScore(Grid<int> g, Coord p)
=> dirs.Select(d => g.LineOut(p, d)
.TakeUntil(n => g[p] <= g[n]).Count())
.Aggregate((a, b) => a * b);
public long Part2(Grid<int> g)
=> g.AllPositions().Max(p => ScenicScore(g, p));
}
๋งํฌํ์ค๋์ ์ขํ๊ณ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ Grid<T>
ํด๋์ค๋ฅผ ๋ง๋ค์ด์ ์ดํ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํธ๋ ๊ฒ ๊ฐ์ต๋๋ค.
2์ฐจ์ ํ์ํ ๋ ์ด๋ ๊ฒ ํ๋ฉด ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ ธ์ ๋ง์ด ์ฌ์ฉํ๋ ๋ฐฉ์์ด์ฃ ~
์ค๋๋ง์ ๋ณด๋ ๋ฐ๊ฐ๋ค์
๊ฐ์๋ก ๋ฌธ์ ๊ฐ ์ด๋ ค์์ง๋๊ตฐ์โฆ
์ผ๋ฐ: ๋งค๋ญ์ด ์ด๋ํ ๋ ๊ผฌ๋ฆฌ์ ๊ฒฝ๋ก๋ฅผ ๊ตฌํด ๊ทธ ๊ฒฝ๋ก ์์น์ ํฉ์ ๊ตฌํ๋ ๋ฌธ์ ์
๋๋ค. ๋งค๋ญ์ ๊ธธ์ด๋ 2์
๋๋ค.
์ฌํ: ์ด์ ๋งค๋ญ์ ๊ธธ์ด๊ฐ 10์ด ๋ฉ๋๋ค. ๊ท์น์ ์ํด ์ด๋๋ ๋งค๋ญ์ ๋ง์ง๋ง ๊ฒฝ๋ก๋ฅผ ๊ตฌํด ๊ทธ ์์น์ ํฉ์ ๊ตฌํ๋ ๋ฌธ์ ์
๋๋ค.
public static string Solve1(string input)
{
// ์
๋ ฅ์์ ํค๋์ ์ด๋ ์ป๊ธฐ
var headPoints = input
.Split(Environment.NewLine)
.Select(x => ParseHeadMove(x))
.SelectMany(x => x)
.Aggregate(Enumerable.Empty<Point>().Append(new Point(0, 0)), (items, item) => items.Append(items.Last() + item)) // ์ข ๋ ์ ์ ํ LINQ ํจ์ ์ฐพ์์ผ ํจ
.ToArray();
var tailPoints = new List<Point>() { new Point(0, 0) };
Point beforeHeadPoint = headPoints.First();
foreach (var headPoint in headPoints.Skip(1))
{
var lastTailPoint = tailPoints.Last();
if (lastTailPoint.IsAdjacency(headPoint) is false)
tailPoints.Add(beforeHeadPoint);
beforeHeadPoint = headPoint;
}
return tailPoints.Distinct().Count().ToString();
}
static IEnumerable<Point> ParseHeadMove(string command)
{
var (cmd, move) = command.Split(' ')
.Chunk(2)
.Select(x => (x[0], int.Parse(x[1])))
.First();
var moving = cmd switch
{
"L" => new Point(-1, 0),
"R" => new Point(1, 0),
"U" => new Point(0, -1),
"D" => new Point(0, 1),
_ => throw new InvalidOperationException()
};
return Enumerable.Repeat(moving, move);
}
record struct Point(int X, int Y)
{
public static Point operator +(Point a, Point b) => new(a.X + b.X, a.Y + b.Y);
public bool IsAdjacency(Point a) => Math.Abs(X - a.X) <= 1 && Math.Abs(Y - a.Y) <= 1;
public Point GetNearest(Point to) => (to.X - X, to.Y - Y) switch
{
(< 0, < 0) => new(X - 1, Y - 1),
(< 0, 0) => new(X - 1, Y),
(< 0, > 0) => new(X - 1, Y + 1),
(0, > 0) => new(X, Y + 1),
(> 0, > 0) => new(X + 1, Y + 1),
(> 0, 0) => new(X + 1, Y),
(> 0, < 0) => new(X + 1, Y - 1),
(0, < 0) => new(X, Y - 1),
_ => throw new InvalidOperationException()
};
}
static void Draw(IEnumerable<Point> points)
{
var xLeft = points.Min(x => x.X);
var xRight = points.Max(x => x.X);
var yTop = points.Min(x => x.Y);
var yBottom = points.Max(x => x.Y);
var map = new string[xRight - xLeft + 1, yBottom - yTop + 1];
foreach (var point in points)
{
map[-xLeft + point.X, -yTop + point.Y] = "#";
}
for (var y = 0; y < map.GetLength(1); y++)
{
for (var x = 0; x < map.GetLength(0); x++)
{
if (map[x, y] == "#")
Console.Write("#");
else
Console.Write(".");
}
Console.WriteLine();
}
}
public static string Solve2(string input)
{
// ์
๋ ฅ์์ ํค๋์ ์ด๋ ์ป๊ธฐ
var headHistory = input
.Split(Environment.NewLine)
.Select(x => ParseHeadMove(x))
.SelectMany(x => x)
.Aggregate(Enumerable.Empty<Point>().Append(new Point(0, 0)), (items, item) => items.Append(items.Last() + item)) // ์ข ๋ ์ ์ ํ LINQ ํจ์ ์ฐพ์์ผ ํจ
.ToArray();
var tails = new List<Point>(Enumerable.Repeat(new Point(0, 0), 9));
var tailHistory = new List<Point>(tails);
foreach (var head in headHistory)
{
Point before = head;
for (var i = 0; i < tails.Count; i++)
{
var tail = tails[i];
if (tail.IsAdjacency(before) is false)
{
tails[i] = tail = tail.GetNearest(before);
if (i == tails.Count - 1)
tailHistory.Add(tail);
}
before = tail;
}
}
//Draw(tailHistory);
return tailHistory.Distinct().Count().ToString();
}
}
๊ตฌํํ Draw()
๋ฅผ ํตํด ์ฌํ ๋ฌธ์ ์ ๊ถค์ ์ ํ์ธํ ์ ์๋๋ฐ์
๋ค๋ฅธ ๋ถ๋ค์ ํ์ด๊ฐ ๊ถ๊ธํฉ๋๋ค.
noop
๊ณผ addx
๋ก ์ด๋ฃจ์ด์ง ๊ฐ๋จํ ๊ธฐ๊ณ๊ฐ ์์ต๋๋ค. noop
์ ํ ์ฌ์ดํด์ ์ฌ๊ณ addx
๋ 2 ์ฌ์ดํด์ ์๋นํ ํ ๋ ์ง์คํฐ ๊ฐ์ ๊ฐ์ ๋ํฉ๋๋ค.
noop
addx 3
addx -5
๋ ์ง์คํฐ ๊ธฐ๋ณธ ๊ฐ: 1
์ผ๋ฐ: 20, 60, 100, 140, 180, 220 ์ฌ์ดํด์ ๋ ์ง์คํฐ ๊ฐ์ ์ฌ์ดํด * ๊ฐ
์ผ๋ก ๊ณ์ฐํด์ ์ด ํฉ์ ๊ตฌํฉ๋๋ค.
์ฌํ: ํน์ ์กฐ๊ฑด์ ํตํด ํ๋ฉด์ ๊ตฌ์ฑํ๋ ์๊ทธ๋์ด ๋ฉ๋๋ค. ๊ทธ ์๊ทธ๋์ ์ด์ฉํด ํ๋ฉด์ ๊ตฌ์ฑํฉ๋๋ค.
public static string Solve1(string input)
{
var commands = input.Split(Environment.NewLine);
var machine = new Machine();
machine.Load(commands);
var sum = machine.Run()
.Take(220)
.Where(x => x.Cycle is 20 or 60 or 100 or 140 or 180 or 220)
.Select(x => x.Cycle * x.Value)
.Sum();
return sum.ToString();
}
public static string Solve2(string input)
{
var commands = input.Split(Environment.NewLine);
var machine = new Machine();
machine.Load(commands);
var sb = new StringBuilder();
foreach (var (cycle, value) in machine.Run().Take(240))
{
var xOffset = (cycle - 1) % 40;
if (xOffset >= value - 1 && xOffset <= value + 1)
sb.Append('#');
else
sb.Append('.');
if (xOffset is 39)
sb.AppendLine();
}
return sb.ToString();
}
class Machine
{
private int _rX = 1;
private Command[]? _commands;
public int RegisterX => _rX;
public void Load(string[] commands)
{
_commands = commands.Select(Command.Parse).ToArray();
}
private IEnumerable<Command> NextCommand()
{
if (_commands is null || _commands.Length is 0)
yield break;
var index = 0;
while (true)
{
var command = _commands[index % _commands.Length];
yield return command;
index++;
}
}
public IEnumerable<(int Cycle, int Value)> Run()
{
var rX = 1;
var cycle = 0;
foreach (var command in NextCommand())
{
foreach(var _ in Enumerable.Range(1, command.Cycles))
{
cycle++;
yield return (cycle, rX);
}
if (command is AddxCommand addxCommand)
rX += addxCommand.IncValue;
}
}
}
abstract record Command()
{
public abstract int Cycles { get; }
public static Command Parse(string input)
{
var tokens = input.Split(' ', StringSplitOptions.TrimEntries);
if (tokens[0] is "noop")
return new NoopCommand();
else if (tokens[0] is "addx")
return new AddxCommand(int.Parse(tokens[1]));
throw new InvalidOperationException();
}
}
record NoopCommand() : Command
{
public override int Cycles => 1;
}
record AddxCommand(int IncValue) : Command
{
public override int Cycles => 2;
}
๋ค๋ฅธ ๋ถ๋ค์ ์ฝ๋๋ ๋ถ์ํด๋ด ์๋ค.
์์ ค๋ผ๋์ ์ฝ๋ :
์ฝ. ์ฝ๋๊ฐ ๊ฐ๊ฒฐํ๊ตฐ์.
๋งํฌํ์ค๋ ์ฝ๋:
์ญ์ ๊ฐ๊ฒฐํ๊ตฐ์.
์ด๋ป๊ฒ ๋๊ฐ์ ์ฝ๋๊ฐ ์๋ค์โฆ ^^;
๋์ด์ด ๋งํ ๋ฌธ์ ๊ฐ ์๊ฒผ์ต๋๋ค. Day 11์ ์ฒซ๋ฒ์จฐ ๋ฌธ์ ๋ ๋ฌด๋ํ ํด๊ฒฐํ๋๋ฐ
๋๋ฒ์งธ ์ฌํ ๋ฌธ์ ๋ ๊ฐ์ด ๊ธฐํ๊ธ์๋ก ์ปค์ง๋ฏ๋ก BigInteger๋ฅผ ์ฌ์ฉํ์ผ๋ ์ญ๋ถ์กฑ์ด์์ต๋๋ค.
โฆ --;
ํ์์ต๋๋ค.
๋๋ฒ์งธ ์ฌํ ๋ฌธ์ ๋ Operation
๊ฒฐ๊ณผ ๊ฐ์ ๊ตฌํ๋ ๊ฒ์ ์๋๋ฏ๋ก ์ ๋๋ก Test
๋ ์ ์๊ฒ ๋ชจ๋ ์์ญ์ด์ ํ
์คํธ ๋๋๊ธฐ ๊ฐ์ ๊ณฑํ ๊ฐ
์ด ์ต๋ ๊ฐ์ด ๋๋๋ก
mulDivition = 23 * 19 * 13 * 17 // 96577
newOperationResult = operationResult % MulDivition
ํ์์ต๋๋ค. ์ด๋ฅผ ํตํด Operation
๊ฒฐ๊ณผ ๊ฐ์ด ๋ฌดํํ ์ฆ๊ฐํ๋ ๊ฒ์ ๋ง์ ์ ์์ต๋๋ค.
public static string Solve1(string input)
{
var monkeys = input.Split(Environment.NewLine)
.Chunk(7)
.Select(x => Monkey.Parse(x, 3))
.ToArray();
var targetRound = 20;
foreach (var _ in Enumerable.Range(1, targetRound))
{
foreach (var monkey in monkeys)
{
monkey.Test((number, value) =>
{
var handingMonkey = monkeys.First(x => x.Number == number);
handingMonkey.Has(value);
});
}
}
return monkeys
.OrderByDescending(x => x.Times)
.Take(2)
.Aggregate(1, (multi, monkey) => multi * monkey.Times)
.ToString();
}
public static string Solve2(string input)
{
var monkeys = input.Split(Environment.NewLine)
.Chunk(7)
.Select(x => Monkey.Parse(x, 1))
.ToArray();
var mulDivision = monkeys.Aggregate(1UL, (multi, monkey) => multi * (ulong)monkey.TestDivision);
var targetRound = 10000;
foreach (var round in Enumerable.Range(1, targetRound))
{
//Console.WriteLine(round);
foreach (var monkey in monkeys)
{
monkey.Test((number, value) =>
{
var handingMonkey = monkeys.First(x => x.Number == number);
handingMonkey.Has(value % mulDivision);
});
}
}
return monkeys
.OrderByDescending(x => x.Times)
.Take(2)
.Aggregate(1L, (multi, monkey) => multi * monkey.Times)
.ToString();
}
class Monkey
{
private Func<ulong, ulong> _operation;
private Queue<ulong> _items;
private int _ridiculousLevel;
private int _testDivision;
private int _divisibleTrueMonkeyNumber;
private int _divisibleFalseMonkeyNumber;
public int Number { get; }
public int Times { get; private set; }
public int TestDivision => _testDivision;
private Monkey(int number, ulong[] items, Func<ulong, ulong> operation, int ridiculousLevel, int testDivision, int divisibleTrueMonkeyNumber, int divisibleFalseMonkeyNumber)
{
Number = number;
_items = new Queue<ulong>(items);
_operation = operation;
_ridiculousLevel = ridiculousLevel;
_testDivision = testDivision;
_divisibleTrueMonkeyNumber = divisibleTrueMonkeyNumber;
_divisibleFalseMonkeyNumber = divisibleFalseMonkeyNumber;
}
public void Test(Action<int, ulong> handingFunc)
{
var count = _items.Count;
while (_items.Count > 0)
{
var item = _items.Dequeue();
var result = _operation(item);
var testResult = result / (ulong)_ridiculousLevel;
if (testResult % (ulong)_testDivision == 0)
handingFunc(_divisibleTrueMonkeyNumber, testResult);
else
handingFunc(_divisibleFalseMonkeyNumber, testResult);
}
Times += count;
}
public void Has(ulong value)
{
_items.Enqueue(value);
}
public static Monkey Parse(string[] strings, int ridiculousLevel)
{
var number = int.Parse(strings[0][7..8]);
var items = strings[1][18..]
.Split(',', StringSplitOptions.TrimEntries)
.Select(ulong.Parse)
.ToArray();
var strOperation = strings[2][19..];
var operation = (ulong x) => x;
if (strOperation is "old * old")
operation = x => x * x;
else if (strOperation.StartsWith("old +") is true)
{
var value = ulong.Parse(strOperation[5..]);
operation = x => x + value;
}
else if (strOperation.StartsWith("old *") is true)
{
var value = ulong.Parse(strOperation[5..]);
operation = x => x * value;
}
else
throw new InvalidOperationException();
var testDivision = int.Parse(strings[3][21..]);
var divisibleTrueMonkeyNumber = int.Parse(strings[4][29..]);
var divisibleFalseMonkeyNumber = int.Parse(strings[5][30..]);
return new Monkey(number, items, operation, ridiculousLevel, testDivision, divisibleTrueMonkeyNumber, divisibleFalseMonkeyNumber);
}
}
์ด๋ฒ AoC์ ์ฌ์ ์ LINQ ์ต๋๊ณผ ์ข ๋ ํจ์จ์ ์ธ (๊ทธ๋ฌ๋ ๊ฐ๋ ์ฑ์ ์ ์งํ๋) ์ฝ๋๋ฅผ ์์ฑํ๋ ์ฌ์ ์ ๋๋ค. ๋์๊ฐ ๋จ์ ํ ์คํธ๋ฅผ ๋ง๋ค๋ฉด์ ์์ ๋ฌธ์์ด๋ก ์ธํด ๊น๋ํ๊ฒ ํน์ฑ์ ๋ถ์ฌํ ์ ์์ด์ ์ข์์ต๋๋ค.
[TestCase("""
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi
""", ExpectedResult = "31")]
public string Day12_Test1(string input)
{
return Day12.Solve1(input);
}