Files
game-of-life/GameOfLife/IO/RleDecoder.cs
T
2026-05-07 03:23:56 +00:00

82 lines
2.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using GameOfLife.Entities;
namespace GameOfLife.IO
{
public class RleDecoder
{
public Pattern Pattern { get; }
public PatternMetadata Metadata { get; }
public RleDecoder(string filename) : this(new FileInfo(filename)) { }
public RleDecoder(FileSystemInfo fi) : this(GetLines(fi)) { }
public RleDecoder(IEnumerable<string> encodedRle)
{
var groups =
(from line in encodedRle
let trimmed = line.Trim()
where
!string.IsNullOrEmpty(trimmed)
group line by line.StartsWith("#") into g
select g
).ToArray();
var comments = groups.First(g => g.Key);
var nonComments = groups.First(g => !g.Key).ToArray();
Metadata = new RlePatternMetaData(nonComments.First(), comments);
var rleData = string.Join("", nonComments.Skip(1));
Pattern = Pattern.Extract(ExpandRle(rleData).ToArray());
}
/// <summary>
/// Returns RLE encoded string into decoded expansion, breaking lines into an enumeration
/// </summary>
private static IEnumerable<string> ExpandRle(string rleData)
{
if (!rleData.Contains("!"))
throw new ArgumentException("RLE pattern did not contain terminating character '!'");
var encodedRle
= rleData.Substring(0, rleData.IndexOf("!", StringComparison.Ordinal));
var rleDecodingRegex = new Regex(@"(?<count>\d*)(?<char>[a-z$])");
var matches = rleDecodingRegex.Matches(encodedRle);
var decoded = string.Empty;
foreach (Match match in matches)
{
var countStr = match.Groups["count"].Value;
var count = string.IsNullOrEmpty(countStr) ? 1 : int.Parse(countStr);
var c = match.Groups["char"].Value.First();
for (var i = 0; i < count; i++)
{
switch (c)
{
case '$':
yield return decoded;
decoded = string.Empty;
break;
default:
decoded += c;
break;
}
}
}
yield return decoded;
}
private static IEnumerable<string> GetLines(FileSystemInfo fi)
{
if (!fi.Exists)
throw new FileNotFoundException(fi.FullName);
return File.ReadAllLines(fi.FullName);
}
}
}