Initial commit
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user