70 lines
2.4 KiB
C#
70 lines
2.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using GameOfLife.Entities;
|
|
|
|
namespace GameOfLife.IO
|
|
{
|
|
// https://conwaylife.com/wiki/Apgcode
|
|
public class ApgcodeDecoder
|
|
{
|
|
private static readonly Regex PrefixRegex = new Regex(@"(?<header>.+(?=_))?_?(?<code>.+)");
|
|
private static readonly Regex ExpansionRegex = new Regex(@"y(\w+)");
|
|
public Pattern Pattern { get; }
|
|
public PatternMetadata Metadata { get; }
|
|
|
|
public ApgcodeDecoder(string apgcode, string name = null)
|
|
{
|
|
var match = PrefixRegex.Match(apgcode);
|
|
if (!match.Success)
|
|
throw new ArgumentException("Invalid apgcode");
|
|
var header = match.Groups["header"].Value;
|
|
var code = match.Groups["code"].Value;
|
|
if (!string.IsNullOrEmpty(header))
|
|
Metadata = new ApgcodePatternMetaData(header,name);
|
|
|
|
var expanded = ExpandAbbreviations(code);
|
|
Pattern = DecodeCells(expanded).ToPattern();
|
|
}
|
|
|
|
private IEnumerable<Cell> DecodeCells(string expanded)
|
|
{
|
|
var rowNum = 0;
|
|
foreach (var strip in expanded.Split('z'))
|
|
{
|
|
var colBits = strip.Select(ConvertToUint).ToArray();
|
|
for (var i = 0; i < 5; i++)
|
|
{
|
|
var colNum = 0;
|
|
foreach (var colBit in colBits)
|
|
{
|
|
if ((colBit >> i & 0b_1) == 1)
|
|
yield return new Cell(colNum, rowNum);
|
|
colNum++;
|
|
}
|
|
|
|
rowNum++;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string ExpandAbbreviations(string apgcode)
|
|
{
|
|
apgcode = apgcode.Replace("w", "00");
|
|
apgcode = apgcode.Replace("x", "000");
|
|
apgcode = ExpansionRegex.Replace(apgcode, m =>
|
|
new string('0', 4 + Convert.ToInt32(ConvertToUint(m.Groups[1].Value[0]))));
|
|
return apgcode;
|
|
}
|
|
|
|
public static uint ConvertToUint(char c)
|
|
{
|
|
if (c >= '0' && c <= '9')
|
|
return (uint)(c - '0');
|
|
if (c >= 'a' && c <= 'z')
|
|
return (uint)(c - 'a' + 10);
|
|
throw new Exception("Cannot convert char " + c.ToString());
|
|
}
|
|
}
|
|
} |