private static void SaveComprCounters(Compressor compr, string destDir) { TextTable table = new TextTable { DefaultAlignment = HorizontalTextAlignment.Right, ColumnSpacing = 3, MaxWidth = int.MaxValue }; compr.ComputeCounterTotals(); int rownum = 0; int indent_prev = 0; foreach (var key in compr.Counters.Keys.Order()) { int indent = 4 * key.ToCharArray().Count(c => c == '|'); if (indent < indent_prev) { rownum++; } indent_prev = indent; table.SetCell(0, rownum, new string(' ', indent) + key.Split('|').Last(), alignment: HorizontalTextAlignment.Left); table.SetCell(1, rownum, Math.Round(compr.Counters[key], 3).ToString("#,0")); rownum++; } File.WriteAllText(Path.Combine(destDir, "counters.txt"), table.ToString()); }
public static void Test() { var ruleCombinationHistogram = new Dictionary <string, int>(); var numCorrectCardsHistorgram = new Dictionary <int, Dictionary <string, int> >(); var numWrongCardsHistorgram = new Dictionary <int, Dictionary <string, int> >(); const int numIter = 2000; var rnd = new Random(); var numRules = 0; for (int iter = 0; iter < numIter; iter++) { var rules = getRules(Edgework.Generate(5, 10, false, rnd)); numRules = rules.Length; var puzzle = generatePuzzle(rules, rnd); var rulesIndexesStr = puzzle.ActiveRuleIndexes.Order().Select(r => r + 1).JoinString(","); ruleCombinationHistogram.IncSafe(rulesIndexesStr); numCorrectCardsHistorgram.IncSafe(puzzle.CorrectCards.Length, rulesIndexesStr); numWrongCardsHistorgram.IncSafe(puzzle.WrongCards.Length, rulesIndexesStr); } foreach (var kvp in ruleCombinationHistogram.OrderBy(k => k.Key)) { Console.WriteLine($"{kvp.Key} = {kvp.Value * 100.0 / numIter:0.0}%"); } Console.WriteLine($"Factor: {ruleCombinationHistogram.Max(k => k.Value) / (double) ruleCombinationHistogram.Min(k => k.Value):0.0}"); Console.WriteLine(); for (int i = 0; i < numRules; i++) { Console.WriteLine($"Rule #{i + 1} = {ruleCombinationHistogram.Where(p => p.Key.Contains((i + 1).ToString())).Sum(p => p.Value) * 100.0 / numIter:0.0}%"); } Console.WriteLine(); ConsoleUtil.WriteLine("Distribution of number of correct cards:".Color(ConsoleColor.White)); var tt = new TextTable { ColumnSpacing = 2 }; var rulesIndexesStrs = ruleCombinationHistogram.Keys.Order().ToArray(); for (int col = 0; col < rulesIndexesStrs.Length; col++) { tt.SetCell(col + 1, 0, rulesIndexesStrs[col].Color(ConsoleColor.White)); } for (int i = numCorrectCardsHistorgram.Keys.Max(); i >= 0; i--) { tt.SetCell(0, i + 1, $"{i} cards".Color(ConsoleColor.White), alignment: HorizontalTextAlignment.Right); for (int col = 0; col < rulesIndexesStrs.Length; col++) { tt.SetCell(col + 1, i + 1, numCorrectCardsHistorgram.Get(i, null)?.Get(rulesIndexesStrs[col]).NullOr(val => $"{val * 100.0 / numIter:0.0}%".Color(ConsoleColor.Cyan)) ?? "", alignment: HorizontalTextAlignment.Right); } //Console.WriteLine($"{i} correct cards: {numCorrectCardsHistorgram.Get(i, 0) * 100.0 / numIter:0.0}%"); } tt.WriteToConsole(); //Console.WriteLine(); //ConsoleUtil.WriteLine("Distribution of number of wrong cards:".Color(ConsoleColor.White)); //for (int i = numWrongCardsHistorgram.Keys.Max(); i >= 0; i--) // Console.WriteLine($"{i} wrong cards: {numWrongCardsHistorgram.Get(i, 0) * 100.0 / numIter:0.0}%"); }
private static void WriteToConsole(IDictionary <string, Highscore> highscores) { var table = new TextTable { ColumnSpacing = 2, DefaultAlignment = HorizontalTextAlignment.Right }; int row = 2; foreach (var hs in highscores.OrderBy(kvp => kvp.Key.StartsWith("Recent") ? 1 : 0).ThenBy(kvp => kvp.Key)) { table.SetCell(0, 0, "Name"); table.SetCell(1, 0, "Any order"); table.SetCell(2, 0, "Alphabetic", colSpan: 26); var best = highscores.Values.Min(h => h.BestAnyOrder); table.SetCell(0, row, hs.Key); table.SetCell(1, row, toDisplayStr(hs.Value.BestAnyOrder, best)); for (int i = 0; i < 26; i++) { var curChar = (char)('A' + i); best = highscores.Values.Min(h => h.BestAlphabetic[curChar]); table.SetCell(2 + i, 1, curChar.ToString()); table.SetCell(2 + i, row, toDisplayStr(hs.Value.BestAlphabetic[curChar], best)); } row++; } table.WriteToConsole(); }
static void CountWords() { var entities = "ensp=\u2002,emsp=\u2003,nbsp=\u00a0,ge=≥,gt=>,lt=<,le=≤,amp=&,shy=\u00ad,mdash=—,trade=™,ohm=Ω,ldquo=“,rdquo=”,horbar=―,rarr=→,uarr=↑,darr=↓,larr=←,times=×" .Split(',') .Select(p => p.Split('=')) .ToDictionary(p => $"&{p[0]};", p => p[1]); var words = new DirectoryInfo(@"D:\c\KTANE\Public\HTML") .EnumerateFiles("*.html", SearchOption.TopDirectoryOnly) .Where(file => !file.Name.Contains('(')) .Select(file => File.ReadAllText(file.FullName)) .Select(text => Regex.Replace(text, @"\A.*(?=<body)", "", RegexOptions.Singleline)) .Select(text => Regex.Replace(text, @"<style>([^<]*)</style>", "", RegexOptions.Singleline)) .Select(text => Regex.Replace(text, @"<[^>]+>", "", RegexOptions.Singleline)) .Select(text => Regex.Replace(text, @"&\w+;", m => entities[m.Value], RegexOptions.Singleline)) .Select(text => text.Replace("Keep Talking and Nobody Explodes Mod", "")) .Select(text => text.Replace("Keep Talking and Nobody Explodes v. 1", "")) .SelectMany(text => Regex.Matches(text, @"[-'’\w]+", RegexOptions.Singleline).Cast <Match>()) .Where(m => m.Value.All(ch => ch >= 'A' && ch <= 'Z')) .Select(m => m.Value.ToUpperInvariant()) //.Where(word => word.Length >= 2) .Where(word => Indicator.WellKnown.Concat(new[] { "NLL" }).Contains(word.ToUpperInvariant())) .GroupBy(word => word, StringComparer.OrdinalIgnoreCase) .ToDictionary(gr => gr.Key, gr => gr.Count(), StringComparer.OrdinalIgnoreCase); var tt = new TextTable { ColumnSpacing = 2 }; var row = 0; foreach (var kvp in words.OrderByDescending(p => p.Value).Take(100)) { tt.SetCell(0, row, $"{row + 1}.".ToString().Color(ConsoleColor.Blue), alignment: HorizontalTextAlignment.Right); tt.SetCell(1, row, kvp.Value.ToString().Color(ConsoleColor.White), alignment: HorizontalTextAlignment.Right); tt.SetCell(2, row, kvp.Key.Color(ConsoleColor.Green)); tt.SetCell(3, row, new string('█', kvp.Value)); row++; } tt.WriteToConsole(); }
protected override ExecuteResult ExecuteCore() { var result = new ExecuteResult(); var volumes = convert(new ManagementObjectSearcher("select * from Win32_Volume").Get()); var table = new TextTable(); table.HeaderRows = 1; table.SetCell(0, 0, "Path".Color(ConsoleColor.White)); table.SetCell(1, 0, "Volume".Color(ConsoleColor.White)); table.SetCell(2, 0, "Free space".Color(ConsoleColor.White), alignment: HorizontalTextAlignment.Right); table.ColumnSpacing = 3; int nextRow = 1; foreach (var volume in Volumes) { var volumeName = new string(new char[1024]); try { GetVolumePathName(volume.Path, volumeName, volumeName.Length); volumeName = volumeName.Substring(0, volumeName.IndexOf('\0')); } catch { throw new Exception($"Unable to retrieve volume name for path {volume.Path}"); } double spaceGb; try { var vol = volumes.Single(v => (string)v["Name"] == volumeName || (string)v["DeviceID"] == volumeName); volumeName = (string)vol["Name"]; spaceGb = ((ulong)vol["FreeSpace"]) / 1_000_000_000.0; } catch { throw new Exception($"Unable to retrieve free space for volume {volumeName}, path {volume.Path}"); } var status = spaceGb < volume.RedAlertBelowGB ? Status.RedAlert : spaceGb < volume.WarnBelowGB ? Status.Warning : Status.Healthy; table.SetCell(0, nextRow, volume.Path); table.SetCell(1, nextRow, volumeName); table.SetCell(2, nextRow, $"{spaceGb:#,0.0} GB".Color(status.GetConsoleColor()), alignment: HorizontalTextAlignment.Right); nextRow++; result.UpdateStatus(status); } result.ConsoleReport += table.ToColoredString(); return(result); }
/// <summary> /// Processes the "benchmark algorithm on all files" command-line command. /// </summary> private static void command_Benchmark(string algName, RVariant[] algArgs) { WaitFormShow("benchmarking..."); Dictionary <string, Compressor> compressors = new Dictionary <string, Compressor>(); foreach (var file in Directory.GetFiles(".", "*.png")) { compressors.Add(file, GetCompressor(algName)); } // Queue all jobs... foreach (var file in compressors.Keys) { Compressor compr = compressors[file]; compr.Configure(algArgs); compr.CanonicalFileName = Path.GetFileNameWithoutExtension(file); string sourcePath = file; string destDir = PathUtil.AppPathCombine("i4c-output", "benchmark.{0},{1}".Fmt(algName, compr.ConfigString), compr.CanonicalFileName); string destFile = "{0}.{1},{2}.i4c".Fmt(compr.CanonicalFileName, algName, compr.ConfigString); Func <Compressor, string, string, string, WaitCallback> makeCallback = (v1, v2, v3, v4) => (dummy2 => CompressFile(v1, v2, v3, v4)); ThreadPool.QueueUserWorkItem(makeCallback(compr, sourcePath, destDir, destFile)); } // ...and wait until they're finished. int worker = 0, dummy; while (worker < Environment.ProcessorCount) { Thread.Sleep(200); ThreadPool.GetAvailableThreads(out worker, out dummy); } // Compute stats totals Dictionary <string, double> totals = new Dictionary <string, double>(); foreach (var file in compressors.Keys) { var counters = compressors[file].Counters; foreach (var key in counters.Keys) { if (totals.ContainsKey(key)) { totals[key] += counters[key]; } else { totals.Add(key, counters[key]); } } } // Write stats totals to a text file TextTable table = new TextTable { ColumnSpacing = 3, MaxWidth = int.MaxValue, DefaultAlignment = HorizontalTextAlignment.Right }; table.SetCell(1, 0, "TOTAL"); int colnum = 2; int rownum = 2; foreach (var str in compressors.Values.Select(val => val.CanonicalFileName).Order()) { table.SetCell(colnum++, 0, str); } int indent_prev = 0; foreach (var key in totals.Keys.Order()) { int indent = 4 * key.ToCharArray().Count(c => c == '|'); if (indent < indent_prev) { rownum++; } indent_prev = indent; table.SetCell(0, rownum, new string(' ', indent) + key.Split('|').Last(), alignment: HorizontalTextAlignment.Left); table.SetCell(1, rownum, Math.Round(totals[key], 3).ToString("#,0")); colnum = 2; foreach (var compr in compressors.Values.OrderBy(c => c.CanonicalFileName)) { if (compr.Counters.ContainsKey(key)) { table.SetCell(colnum++, rownum, Math.Round(compr.Counters[key], 3).ToString("#,0")); } else { table.SetCell(colnum++, rownum, "N/A"); } } rownum++; } File.WriteAllText(PathUtil.AppPathCombine("i4c-output", "benchmark.{0},{1}.txt".Fmt(algName, compressors.Values.First().ConfigString)), table.ToString()); WaitFormHide(); }
public static void RunSimulations() { const int numIterations = 100000; var astrologyElements = new[] { "Fire", "Water", "Earth", "Air" }; var astrologyPlanets = new[] { "Sun", "Jupiter", "Moon", "Saturn", "Mercury", "Uranus", "Venus", "Neptune", "Mars", "Pluto" }; var astrologyZodiacs = new[] { "Aries", "Leo", "Sagittarius", "Taurus", "Virgo", "Capricorn", "Gemini", "Libra", "Aquarius", "Cancer", "Scorpio", "Pisces" }; var yes = new[] { "Yes" }; var blindMazeColorNames = "Red,Green,White,Gray,Yellow".Split(','); var simulatables = Ut.NewArray( new Simulatable { Active = false, Name = "Connection Check", GetResult = ew => { var numbers = Enumerable.Range(0, 8).Select(_ => Rnd.Next(1, 9)).ToArray(); return(Ut.NewArray( numbers.Distinct().Count() == 8 ? "1. all distinct" : numbers.Count(c => c == 1) > 1 ? "2. more than one “1”" : numbers.Count(c => c == 7) > 1 ? "3. more than one “7”" : numbers.Count(c => c == 2) >= 3 ? "4. at least three “2”s" : numbers.Count(c => c == 5) == 0 ? "5. no “5”s" : numbers.Count(c => c == 8) == 2 ? "6. exactly two “8”s" : ew.GetNumBatteries().Apply(bs => bs > 6 || bs == 0) ? "7. more than 6 or no batteries" : "8. count the batteries")); } }, new Simulatable { Active = false, Name = "Laundry: 4/2+BOB (“unicorn”)", GetResult = ew => ew.GetNumAABatteries() == 4 && ew.GetNumDBatteries() == 0 && ew.HasLitIndicator("BOB") ? yes : null }, new Simulatable { Active = false, Name = "Lettered Keys", GetResult = ew => { var number = Rnd.Next(0, 100); return(Ut.NewArray( number == 69 ? "1. 69 → D" : number % 6 == 0 ? "2. divisible by 6 → A" : ew.GetNumBatteries() >= 2 && number % 3 == 0 ? "3. ≥ 2 batteries and divisible by 3 → B" : ew.SerialNumber.Any("CE3".Contains) ? (number >= 22 && number <= 79 ? "4. C, E, 3 & 22 ≤ n ≤ 79 → B" : "5. C, E, 3 → C") : number < 46 ? "6. n < 46 → D" : "7. otherwise → A")); } }, new Simulatable { Active = false, Name = "Astrology", GetResult = ew => { var planet = Rnd.Next(astrologyPlanets.Length); var zodiac = Rnd.Next(astrologyZodiacs.Length); var element = Rnd.Next(astrologyElements.Length); var elemPlanet = new[, ] { { 0, 0, 1, -1, 0, 1, -2, 2, 0, -1 }, { -2, 0, -1, 0, 2, 0, -2, 2, 0, 1 }, { -1, -1, 0, -1, 1, 2, 0, 2, 1, -2 }, { -1, 2, -1, 0, -2, -1, 0, 2, -2, 2 } }; var elemZodiac = new[, ] { { 1, 0, -1, 0, 0, 2, 2, 0, 1, 0, 1, 0 }, { 2, 2, -1, 2, -1, -1, -2, 1, 2, 0, 0, 2 }, { -2, -1, 0, 0, 1, 0, 1, 2, -1, -2, 1, 1 }, { 1, 1, -2, -2, 2, 0, -1, 1, 0, 0, -1, -1 } }; var planetZodiac = new[, ] { { -1, -1, 2, 0, -1, 0, -1, 1, 0, 0, -2, -2 }, { -2, 0, 1, 0, 2, 0, -1, 1, 2, 0, 1, 0 }, { -2, -2, -1, -1, 1, -1, 0, -2, 0, 0, -1, 1 }, { -2, 2, -2, 0, 0, 1, -1, 0, 2, -2, -1, 1 }, { -2, 0, -1, -2, -2, -2, -1, 1, 1, 1, 0, -1 }, { -1, -2, 1, -1, 0, 0, 0, 1, 0, -1, 2, 0 }, { -1, -1, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1 }, { -1, 2, 0, 0, 1, -2, 1, 0, 2, -1, 1, 0 }, { 1, 0, 2, 1, -1, 1, 1, 1, 0, -2, 2, 0 }, { -1, 0, 0, -1, -2, 1, 2, 1, 1, 0, 0, -1 } }; var omen = new[] { astrologyPlanets[planet], astrologyZodiacs[zodiac], astrologyElements[element] }.Sum(str => str.Any(ew.SerialNumber.Contains) ? 1 : -1); omen += elemPlanet[element, planet] + elemZodiac[element, zodiac] + planetZodiac[planet, zodiac]; return(omen == 0 ? new[] { "No Omen" } : omen > 0 ? new[] { "Good Omen", omen.ToString() } : new[] { "Poor Omen", (-omen).ToString() }); } }, new Simulatable { Active = false, Name = "Plumbing", GetResult = ew => { // Plumbing: most inputs and outputs var redInput = // For: Serial contains a '1' +(ew.SerialNumber.Contains('1') ? 1 : 0) // For: Exactly 1 RJ45 port + (ew.GetNumPorts(PortType.RJ45) == 1 ? 1 : 0) // Against: Any duplicate ports - (ew.HasDuplicatePorts() ? 1 : 0) // Against: Any duplicate ew.SerialNumber characters - (ew.SerialNumber.Order().SelectConsecutivePairs(false, (c1, c2) => c1 == c2).Any() ? 1 : 0) > 0; var yellowInput = // For: Serial contains a '2' +(ew.SerialNumber.Contains('2') ? 1 : 0) // For: One or more Stereo RCA ports + (ew.GetNumPorts(PortType.StereoRCA) > 0 ? 1 : 0) // Against: No duplicate ports - (ew.HasDuplicatePorts() ? 0 : 1) // Against: Serial contains a '1' or 'L' - (ew.SerialNumber.Contains('1') || ew.SerialNumber.Contains('L') ? 1 : 0) > 0; var greenInput = // For: Serial contains 3 or more numbers +(ew.SerialNumber.Count(ch => ch >= '0' && ch <= '9') >= 3 ? 1 : 0) // For: One or more DVI-D ports + (ew.GetNumPorts(PortType.DVI) > 0 ? 1 : 0) // Against: Red Input is inactive - (redInput ? 0 : 1) // Against: Yellow Input is inactive - (yellowInput ? 0 : 1) > 0; var blueInput = // Note: Always active if all other inputs are inactive (!redInput && !yellowInput && !greenInput) || ( // For: At least 4 unique ports (ew.GetNumPortTypes() >= 4 ? 1 : 0) // For: At least 4 batteries + (ew.GetNumBatteries() >= 4 ? 1 : 0) // Against: No ports - (ew.GetPorts().Any() ? 0 : 1) // Against: No batteries - (ew.GetNumBatteries() == 0 ? 1 : 0) > 0 ); var redOutput = // For: One or more Serial ports (ew.GetNumPorts(PortType.Serial) > 0 ? 1 : 0) // For: Exactly one battery + (ew.GetNumBatteries() == 1 ? 1 : 0) // Against: Serial contains more than 2 numbers - (ew.SerialNumber.Count(ch => ch >= '0' && ch <= '9') >= 3 ? 1 : 0) // Against: More than 2 inputs are active - ((redInput ? 1 : 0) + (blueInput ? 1 : 0) + (greenInput ? 1 : 0) + (yellowInput ? 1 : 0) > 2 ? 1 : 0) > 0; var yellowOutput = // For: Any duplicate ports (ew.HasDuplicatePorts() ? 1 : 0) // For: Serial contains a '4' or '8' + (ew.SerialNumber.Contains('4') || ew.SerialNumber.Contains('8') ? 1 : 0) // Against: Serial doesn't contain a '2' - (ew.SerialNumber.Contains('2') ? 0 : 1) // Against: Green Input is active - (greenInput ? 1 : 0) > 0; var greenOutput = // For: Exactly 3 inputs are active ((redInput ? 1 : 0) + (blueInput ? 1 : 0) + (greenInput ? 1 : 0) + (yellowInput ? 1 : 0) == 3 ? 1 : 0) // For: Exactly 3 ports are present + (ew.GetNumPorts() == 3 ? 1 : 0) // Against: Less than 3 ports are present - (ew.GetNumPorts() < 3 ? 1 : 0) // Against: Serial contains more than 3 numbers - (ew.SerialNumberDigits().Count() > 3 ? 1 : 0) > 0; var blueOutput = // Note: Always active if all other outputs are inactive (!redOutput && !greenOutput && !yellowOutput) || // For: All inputs are active +((redInput && greenInput && yellowInput && blueInput) ? 1 : 0) // For: Any other output is inactive + (!redOutput || !yellowOutput || !greenOutput ? 1 : 0) // Against: Less than 2 batteries - (ew.GetNumBatteries() < 2 ? 1 : 0) // Against: No Parallel port - (ew.GetNumPorts(PortType.Parallel) == 0 ? 1 : 0) > 0; var numInputs = (redInput ? 1 : 0) + (blueInput ? 1 : 0) + (greenInput ? 1 : 0) + (yellowInput ? 1 : 0); var numOutputs = (redOutput ? 1 : 0) + (blueOutput ? 1 : 0) + (greenOutput ? 1 : 0) + (yellowOutput ? 1 : 0); return(Ut.NewArray( //$"{numInputs} inputs", //$"{numOutputs} outputs" new[] { redInput ? "Red in" : null, yellowInput ? "Yellow in" : null, greenInput ? "Green in" : null, blueInput ? "Blue in" : null, redOutput ? "Red out" : null, yellowOutput ? "Yellow out" : null, greenOutput ? "Green out" : null, blueOutput ? "Blue out" : null } .Where(s => s != null).JoinString(", ") )); } }, new Simulatable { Active = false, Name = "Chess", GetResult = ew => new[] { Chess.GetSolution(ew.SerialNumber.Last() % 2 != 0, out _, out _)[6] } }, new Simulatable { Active = true, Name = "Blind Maze", GetResult = ew => { // Colors of the N/S/W/E buttons var cols = new[] { Rnd.Next(0, 5), Rnd.Next(0, 5), Rnd.Next(0, 5), Rnd.Next(0, 5) }; // 0 = Red // 1 = Green // 2 = White // 3 = Gray // 4 = Yellow // If there are at least two red buttons, if (cols.Count(c => c == 0) >= 2) { // rotate the maze 90 degrees clockwise and then calculate starting position. return new[] { "90", "after" } } ; // Otherwise, if there are at least 5 batteries, if (ew.GetNumBatteries() >= 5) { // calculate starting position and then rotate the maze 90 degrees clockwise. return new[] { "90", "before" } } ; // Otherwise, if there is an IND indicator, if (ew.HasIndicator("IND")) { // rotate the maze 180 degrees and then calculate starting position. return new[] { "180", "after" } } ; // Otherwise, if there are no yellow buttons and at least one red button, if (cols.Count(c => c == 4) == 0 && cols.Count(c => c == 0) > 0) { // rotate your perspective of the maze 90 degrees clockwise and then calculate starting position. return new[] { "270", "after" } } ; // Otherwise, if there are at least 2 types of maze-based modules on the bomb*, if (Rnd.NextDouble() < .25) { // calculate starting position and then rotate the maze 180 degrees clockwise. return new[] { "180", "before" } } ; // Otherwise, if there is at most 1 port type on the bomb, if (ew.GetNumPortTypes() < 2) { // calculate starting position and then rotate your perspective of the maze 90 degrees clockwise. return new[] { "270", "before" } } ; // Otherwise, keep the maze as it is. return(new[] { "0" }); } } ).Where(s => s.Active).ToArray(); var results = new AutoDictionary <string, SimulatedResult>(str => new SimulatedResult()); var hundredths = numIterations / 100; for (int attempt = 0; attempt < numIterations; attempt++) { if (attempt % hundredths == 0) { Console.Write($"{attempt / hundredths}%\r"); } var edgework = Edgework.Generate(); foreach (var sim in simulatables) { var result = sim.GetResult(edgework); if (result == null) { continue; } var sr = results[sim.Name]; for (int i = 0; i < result.Length; i++) { sr = sr.Children[result[i]]; } sr.Count++; } } Console.WriteLine("Done"); Console.WriteLine(); var tt = new TextTable { ColumnSpacing = 2 }; var row = 0; foreach (var kvp in results) { tt.SetCell(0, row, kvp.Key.Color(ConsoleColor.White)); tt.SetCell(1, row, "{0/Cyan:0.####}% (or 1 in {1/Magenta:0}){2}".Color(ConsoleColor.Gray).Fmt( kvp.Value.TotalCount / (double)numIterations * 100, numIterations / (double)kvp.Value.TotalCount, generateTree(kvp.Value, numIterations, skipTop: true))); row++; } tt.WriteToConsole(); Console.WriteLine(); }
public static void GenerateData() { var freqs = new Dictionary <char, int>(); foreach (var p in _text) { foreach (var w in p) { foreach (var l in w) { freqs.IncSafe(l); } } } ConsoleUtil.WriteParagraphs(freqs.OrderByDescending(kvp => kvp.Value).Select(kvp => $"{kvp.Key}={kvp.Value}").JoinString(", ")); Console.WriteLine(new string('─', 20)); var lists = _text.Select(line => line.Select(word => word.Select(x => new List <(int paraIx, int wordIx, int letterIx)>()).ToArray()).ToArray()).ToArray(); var dic = new Dictionary <char, List <(int paraIx, int wordIx, int letterIx)> >(); for (int p = 0; p < 26; p++) { for (int w = 0; w < 26; w++) { if (w != p) { for (int l = 0; l < 26; l++) { if (l != p && l != w) { var(paraIx, wordIx, letterIx, ch) = getPosition(p, w, l); lists[paraIx][wordIx][letterIx].Add((p, w, l)); dic.AddSafe(ch, (p, w, l)); } } } } } ConsoleUtil.WriteParagraphs(_text.Select((para, paraIx) => para.Select((word, wordIx) => word.Select((ch, chIx) => { var num = lists[paraIx][wordIx][chIx].Count / 2; return(ch.Color((ConsoleColor)(num % 16), num == 0 ? ConsoleColor.Red : (ConsoleColor)(num / 16))); }).JoinColoredString()).JoinColoredString(" ")).JoinColoredString("\n")); ConsoleUtil.WriteLine("{0} paragraphs. Unused letters = {1}".Color(null) .Fmt(_text.Length, lists.Sum(one => one.Sum(two => two.Count(three => three.Count == 0))).Apply(x => x.ToString().Color(x == 0 ? ConsoleColor.Green : ConsoleColor.Magenta)))); Utils.ReplaceInFile(@"D:\c\KTANE\SimonSends\Assets\SimonSendsModule.cs", "/*MANUAL*/", "/*!MANUAL*/", $@"@""{_text.Select(para => para.JoinString(" ")).JoinString("|")}"""); const int iterations = 1000000; // How many times does each combo occur? Sum of the values is equal to iterations. var comboStats = new Dictionary <string, int>(); // How many times does each letter (A–Z) occur? Sum is greater than iterations. var letterStats = Ut.NewArray(3, _ => new Dictionary <char, int>()); // How many times does each solution length occur? var lengthStats = new Dictionary <int, int>(); for (int iter = 0; iter < iterations; iter++) { var available = Enumerable.Range(0, 26).ToList().Shuffle(); var r = available[0]; var g = available[1]; var b = available[2]; var(_, _, _, newR) = getPosition(b, g, r); var(_, _, _, newG) = getPosition(r, b, g); var(_, _, _, newB) = getPosition(g, r, b); var rMorse = constructMorse(newR); var gMorse = constructMorse(newG); var bMorse = constructMorse(newB); var combo = Enumerable.Range(0, Ut.Max(rMorse.Length, gMorse.Length, bMorse.Length)) .Select(i => { var isR = i >= rMorse.Length ? false : rMorse[i] == '#'; var isG = i >= gMorse.Length ? false : gMorse[i] == '#'; var isB = i >= bMorse.Length ? false : bMorse[i] == '#'; return("KBGCRMYW"[(isB ? 1 : 0) + (isG ? 2 : 0) + (isR ? 4 : 0)]); }) .JoinString(); comboStats.IncSafe(combo); letterStats[0].IncSafe(newR); letterStats[1].IncSafe(newG); letterStats[2].IncSafe(newB); lengthStats.IncSafe(combo.Length); } Console.WriteLine(comboStats.Count); foreach (var kvp in comboStats.OrderByDescending(p => p.Value).Take(10)) { Console.WriteLine($"{kvp.Key,13} = {100 * kvp.Value / (double) iterations:0.##}%"); } Console.WriteLine("---"); var tt = new TextTable { ColumnSpacing = 2 }; for (int i = 0; i < 3; i++) { tt.SetCell(i, 0, letterStats[i] .OrderByDescending(p => p.Value) .Select(kvp => "{0} = {1,6:0.00}% {2}".Color(null).Fmt(kvp.Key.Color(new[] { ConsoleColor.Red, ConsoleColor.Green, ConsoleColor.Blue }[i]), 100 * kvp.Value / (double)iterations, new string('█', (200 * kvp.Value + iterations / 2) / iterations))) .JoinColoredString("\n") .Replace(" ", "\u00a0")); } tt.WriteToConsole(); Console.WriteLine("---"); foreach (var kvp in lengthStats.OrderBy(p => p.Key)) { Console.WriteLine($"{kvp.Key,2} = {100 * kvp.Value / (double) iterations,6:0.00}% {new string('█', (100 * kvp.Value + iterations / 2) / iterations)}"); } }
private static void SetCell(TextTable tt, int col, int row, Dictionary <string, string> items) { string str = null; if (items.Values.Distinct().Count() == 1) { str = items.Values.First(); } else { // Try numbers var strs1 = new List <string>(); for (char n = '1'; n <= '3'; n++) { var tItems = items.Where(p => p.Key.StartsWith(n)).ToArray(); if ("ASDF".All(ch => items.ContainsKey(n.ToString() + ch))) { var biggestGroup = tItems.GroupBy(p => p.Value).MaxElement(g => g.Count()); if (biggestGroup.Count() == 1) { biggestGroup = null; } foreach (var tItem in tItems) { if (biggestGroup == null || !biggestGroup.Any(p => p.Key == tItem.Key)) { strs1.Add($"{tItem.Key}={tItem.Value}"); } } if (biggestGroup != null) { strs1.Add($"{n}={biggestGroup.First().Value}"); } } else { strs1.AddRange(tItems.Select(p => $"{p.Key}={p.Value}")); } } // Try letters var strs2 = new List <string>(); foreach (char l in "ASDF") { var tItems = items.Where(p => p.Key.EndsWith(l)).ToArray(); if ("123".All(ch => items.ContainsKey(ch + l.ToString()))) { var biggestGroup = tItems.GroupBy(p => p.Value).MaxElement(g => g.Count()); if (biggestGroup.Count() == 1) { biggestGroup = null; } foreach (var tItem in tItems) { if (biggestGroup == null || !biggestGroup.Any(p => p.Key == tItem.Key)) { strs2.Add($"{tItem.Key}={tItem.Value}"); } } if (biggestGroup != null) { strs2.Add($"{l}={biggestGroup.First().Value}"); } } else { strs2.AddRange(tItems.Select(p => $"{p.Key}={p.Value}")); } } str = (strs1.Count > strs2.Count ? strs2 : strs1).JoinString("\n"); } tt.SetCell(col, row, str); }
public static void Simulations() { const int iterations = 100000; const int quadrantCount = 5; var getQuadrantCounts = Ut.Lambda((bool[][] arr) => { var qCounts = new int[4]; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { if (arr[x][y]) { qCounts[(y / 4) * 2 + (x / 4)]++; } } } return(qCounts); }); var quadrantCountRule = Ut.Lambda((bool white) => new Tuple <string, Func <bool[][], Edgework, int> >( $"Exactly one quadrant has {quadrantCount} or fewer {(white ? "white" : "black")} pixels ⇒ number of {(white ? "white" : "black")} pixels in the other 3 quadrants", (arr, edgework) => { var qCounts = getQuadrantCounts(arr); if ((white ? qCounts.Count(sum => sum <= quadrantCount) : qCounts.Count(sum => sum >= (16 - quadrantCount))) != 1) { return(0); } var qIx = (white ? qCounts.IndexOf(sum => sum <= quadrantCount) : qCounts.IndexOf(sum => sum >= (16 - quadrantCount))) + 1; return((qCounts.Where((sum, ix) => ix != qIx).Sum() + 3) % 4 + 1); })); var totalCountRule = Ut.Lambda((int num, bool white) => new Tuple <string, Func <bool[][], Edgework, int> >( $"The entire bitmap has {num} or more {(white ? "white" : "black")} pixels ⇒ number of {(white ? "white" : "black")} pixels", (arr, edgework) => { var sum = 0; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { sum += (arr[x][y] ^ white) ? 0 : 1; } } if (sum >= num) { return(((sum + 3) % 4) + 1); } return(0); })); var rowColumnRule = new Tuple <string, Func <bool[][], Edgework, int> >( "Exactly one row or column is completely white or completely black ⇒ x- or y-coordinate", (arr, edgework) => { int answer = 0; for (int x = 0; x < 8; x++) { var isWhite = arr[x][0]; for (int y = 1; y < 8; y++) { if (arr[x][y] != isWhite) { goto next; } } if (answer != 0) { return(0); } // The coordinate is 0-based, but the answer needs to be 1-based. answer = (x % 4) + 1; next:; } for (int y = 0; y < 8; y++) { var isWhite = arr[0][y]; for (int x = 1; x < 8; x++) { if (arr[x][y] != isWhite) { goto next; } } if (answer != 0) { return(0); } // The coordinate is 0-based, but the answer needs to be 1-based. answer = (y % 4) + 1; next:; } return(answer); }); var squareRule = new Tuple <string, Func <bool[][], Edgework, int> >( "There is a 3×3 square that is completely white or completely black ⇒ x-coordinate of center of first in reading order", (arr, edgework) => { for (int x = 1; x < 7; x++) { for (int y = 1; y < 7; y++) { var isWhite = arr[x][y]; for (int xx = -1; xx < 2; xx++) { for (int yy = -1; yy < 2; yy++) { if (arr[x + xx][y + yy] != isWhite) { goto next; } } } // x is 0-based, but the answer needs to be 1-based. return((x % 4) + 1); next:; } } return(0); }); var quadrantMajorityRule = Ut.Lambda((string name, Func <int, int, Edgework, bool> compare, Func <int, int, Edgework, bool[][], int> getAnswer) => new Tuple <string, Func <bool[][], Edgework, int> >( name, (arr, widgets) => { var quadrantCounts = new int[4]; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { if (arr[x][y]) { quadrantCounts[(x / 4) * 2 + (y / 4)]++; } } } var w = quadrantCounts.Count(q => q > 8); var b = quadrantCounts.Count(q => q < 8); return(compare(b, w, widgets) ? ((getAnswer(b, w, widgets, arr) + 3) % 4) + 1 : 0); })); var rules = Ut.NewArray( quadrantCountRule(true), quadrantMajorityRule("There are as many mostly-white quadrants as there are lit indicators ⇒ number of batteries", (b, w, widgets) => w == widgets.GetNumLitIndicators(), (b, w, widgets, arr) => widgets.GetNumBatteries()), rowColumnRule, quadrantMajorityRule("There are fewer mostly-white quadrants than mostly-black quadrants ⇒ number of mostly-black quadrants", (b, w, widgets) => w < b, (b, w, widgets, arr) => b), totalCountRule(36, true), quadrantMajorityRule("There are more mostly-white quadrants than mostly-black quadrants ⇒ smallest number of black in any quadrant", (b, w, widgets) => w > b, (b, w, widgets, arr) => 16 - getQuadrantCounts(arr).Max()), quadrantCountRule(false), quadrantMajorityRule("There are as many mostly-black quadrants as there are unlit indicators ⇒ number of ports", (b, w, widgets) => b == widgets.GetNumUnlitIndicators(), (b, w, widgets, arr) => widgets.GetNumPorts()), squareRule, quadrantMajorityRule("There are as many mostly-white quadrants as mostly-black quadrants ⇒ first numeric digit of the serial number", (b, w, widgets) => w == b, (b, w, widgets, arr) => Rnd.Next(0, 10))); var counts = new int[rules.Length, 4]; for (int iter = 0; iter < iterations; iter++) { var edgework = Edgework.Generate(); var bitmap = Ut.NewArray(8, 8, (_, __) => Rnd.Next(0, 2) == 0); var startRule = Rnd.Next(0, rules.Length); var answer = 0; string rule; int ruleIndex; for (int r = 0; r < rules.Length; r++) { ruleIndex = (r + startRule) % rules.Length; var tup = rules[ruleIndex]; answer = tup.Item2(bitmap, edgework); if (answer != 0) { rule = tup.Item1; goto found; } } Console.WriteLine(rules.Select(r => r.Item2(bitmap, edgework)).JoinString(", ")); System.Diagnostics.Debugger.Break(); break; found :; counts[ruleIndex, answer - 1]++; } var tt = new TextTable { ColumnSpacing = 2 }; var ruleCounts = new int[rules.Length]; for (int a = 0; a < 4; a++) { tt.SetCell(a + 1, 0, (a + 1).ToString().Color(ConsoleColor.White), alignment: HorizontalTextAlignment.Right); tt.SetCell(a + 1, rules.Length + 1, ((Enumerable.Range(0, rules.Length).Sum(r => counts[r, a]) * 100 / (double)iterations).ToString("0.0") + "%").Color(ConsoleColor.Green), alignment: HorizontalTextAlignment.Right); } for (int r = 0; r < rules.Length; r++) { tt.SetCell(0, r + 1, rules[r].Item1.Color(ConsoleColor.Cyan).Apply(s => s.ColorSubstring(s.IndexOf('⇒'), ConsoleColor.DarkCyan)), alignment: HorizontalTextAlignment.Right); for (int a = 0; a < 4; a++) { tt.SetCell(a + 1, r + 1, ((counts[r, a] * 100 / (double)iterations).ToString("0.0") + "%").Color(ConsoleColor.Magenta), alignment: HorizontalTextAlignment.Right); } tt.SetCell(5, r + 1, ((Enumerable.Range(0, 4).Sum(a => counts[r, a]) * 100 / (double)iterations).ToString("0.0") + "%").Color(ConsoleColor.White), alignment: HorizontalTextAlignment.Right); ruleCounts[r] += Enumerable.Range(0, 4).Sum(a => counts[r, a]); } tt.WriteToConsole(); Console.WriteLine(); ConsoleUtil.WriteLine("Ratio of most likely to least likely rule: {0/White:0.0}".Color(ConsoleColor.White).Fmt(ruleCounts.Max() / (double)ruleCounts.Min())); }
public static void RunStatistics() { var opinions = new List <int> [6]; for (int i = 0; i < 6; i++) { opinions[i] = new List <int>(); } const int iterations = 1000000; for (int iter = 0; iter < iterations; iter++) { var edgework = Edgework.Generate(5, 5); var i = edgework.GetNumIndicators(); var b = edgework.GetNumBatteries(); var m = Rnd.Next(7, 16); var h = edgework.GetNumBatteryHolders(); var f = Rnd.NextDouble() < .02 ? 1 : 0; var p = edgework.GetNumPorts(); var l = edgework.GetNumPortPlates(); var s = edgework.SerialNumberDigits().Sum(); opinions[0].Add((h * f - l * l) + 20 * b); opinions[1].Add(s * p - b * b * b); opinions[2].Add(m + 3 * (i + p) - f * b); opinions[3].Add(i * (20 + m) - p * l); opinions[4].Add(p * (l * b + 3) + l + b - s); opinions[5].Add(h * h * h + l * l + f * f * f * f - m); } var tt = new TextTable { ColumnSpacing = 2 }; tt.SetCell(0, 0, "Faction"); tt.SetCell(1, 0, "Mean", alignment: HorizontalTextAlignment.Right); tt.SetCell(2, 0, "Variance", alignment: HorizontalTextAlignment.Right); tt.SetCell(3, 0, "Stddev", alignment: HorizontalTextAlignment.Right); tt.SetCell(4, 0, "Min", alignment: HorizontalTextAlignment.Right); tt.SetCell(5, 0, "Max", alignment: HorizontalTextAlignment.Right); for (int i = 0; i < 6; i++) { tt.SetCell(0, i + 1, "red,blue,yellow,green,purple,orange".Split(',')[i]); var mean = (double)opinions[i].Sum() / iterations; var variance = opinions[i].Sum(o => (o - mean) * (o - mean)) / iterations; tt.SetCell(1, i + 1, $"{mean:0.0}", alignment: HorizontalTextAlignment.Right); tt.SetCell(2, i + 1, $"{variance:0.0}", alignment: HorizontalTextAlignment.Right); tt.SetCell(3, i + 1, $"{Math.Sqrt(variance):0.0}", alignment: HorizontalTextAlignment.Right); tt.SetCell(4, i + 1, opinions[i].Min().ToString(), alignment: HorizontalTextAlignment.Right); tt.SetCell(5, i + 1, opinions[i].Max().ToString(), alignment: HorizontalTextAlignment.Right); } tt.WriteToConsole(); }