diff --git a/www/internals/adventofcode.php b/www/internals/adventofcode.php new file mode 100644 index 0000000..1db47dd --- /dev/null +++ b/www/internals/adventofcode.php @@ -0,0 +1,128 @@ + [ 'url-aoc'=>'https://adventofcode.com/2018/day/', 'blog-id' => 23, 'github' => 'https://github.com/Mikescher/AdventOfCode2018' ], + '2019' => [ 'url-aoc'=>'https://adventofcode.com/2019/day/', 'blog-id' => 24, 'github' => 'https://github.com/Mikescher/AdventOfCode2019' ], + ]; + + const LANGUAGES = + [ + 'cs' => ['ext'=>'linq', 'css'=>'language-csharp', 'name'=>'C#'], + ]; + + public static function listAllFromAllYears() + { + $all = require (__DIR__ . '/../statics/aoc/__all.php'); + + array_walk($all, function(&$value, $year) { array_walk($value, function (&$innervalue) use ($year) { $innervalue = self::readSingle($year, $innervalue); }); }); + + return $all; + } + + public static function listSingleYear($year) + { + $all = require (__DIR__ . '/../statics/aoc/__all.php'); + + return array_map('self::readSingle', $all[$year]); + } + + public static function listYears() + { + $all = require (__DIR__ . '/../statics/aoc/__all.php'); + + return array_keys($all); + } + + public static function readSingle($year, $a) + { + $yeardata = self::YEARS[$year]; + + $n2p = str_pad($a['day'], 2, '0', STR_PAD_LEFT); + $a['day-padded'] = $n2p; + + $a['url'] = '/blog/' . $yeardata['blog-id'] . '/Advent_of_Code_' . $year . '/day-' . $n2p; + $a['canonical'] = "https://www.mikescher.com" . $a['url']; + + $a['url_aoc'] = $yeardata['url-aoc'] . $a['day']; // adventofcode.com/{year}/day/{day} + + $a['file_challenge'] = (__DIR__ . '/../statics/aoc/'.$year.'/'.$n2p.'_challenge.txt'); + $a['file_input'] = (__DIR__ . '/../statics/aoc/'.$year.'/'.$n2p.'_input.txt'); + + $solutionfiles = []; + + foreach ($a['languages'] as $language) + { + for ($i=1; $i <= $a['parts']; $i++) + { + $solutionfiles []= (__DIR__ . '/../statics/aoc/' . $year . '/' . $n2p . '-' . $i . '.' . self::LANGUAGES[$language]['ext']); + } + } + + $a['file_solutions'] = $solutionfiles; + + return $a; + } + + public static function getDayFromStrIdent($year, $ident) + { + $e = explode('-', $ident, 2); // day-xxx + if (count($e)!==2) return null; + + $i = intval($e[1], 10); + if ($i == 0) return null; + + return self::getSingleDay($year, $i); + } + + public static function getSingleDay($year, $day) + { + foreach (self::listSingleYear($year) as $aocd) { + if ($aocd['day'] == $day) return $aocd; + } + return null; + } + + public static function checkConsistency() + { + $warn = null; + + foreach (self::listAllFromAllYears() as $year => $yd) + { + $daylist = []; + $titlelist = []; + + if (!array_key_exists($year, self::YEARS)) return ['result'=>'err', 'message' => 'Invalid Year: ' . $year]; + + foreach ($yd as $aocdata) + { + if (in_array($aocdata['day'], $daylist)) return ['result'=>'err', 'message' => 'Duplicate day ' . $aocdata['day']]; + $daylist []= $aocdata['day']; + + if (in_array($aocdata['title'], $titlelist)) return ['result'=>'err', 'message' => 'Duplicate title ' . $aocdata['title']]; + $titlelist []= $aocdata['title']; + + if (count($aocdata['solutions']) !== $aocdata['parts']) return ['result'=>'err', 'message' => 'Not enough solution-values in day' . $aocdata['day']]; + if (count($aocdata['file_solutions']) !== $aocdata['parts']) return ['result'=>'err', 'message' => 'Not enough solution-files in day' . $aocdata['day']]; + + if (!file_exists($aocdata['file_challenge'])) return ['result'=>'err', 'message' => 'file_challenge not found ' . $aocdata['file_challenge']]; + if (!file_exists($aocdata['file_input'])) return ['result'=>'err', 'message' => 'file_input not found ' . $aocdata['file_input']]; + + foreach ($aocdata['file_solutions'] as $sfile) + { + if (!file_exists($sfile)) return ['result'=>'err', 'message' => 'file_solution[?] not found ' . $sfile]; + } + + foreach ($aocdata['languages'] as $lang) + { + if (!array_key_exists($lang, self::LANGUAGES)) return ['result'=>'err', 'message' => 'Unknown language ' . $lang]; + } + } + } + + if ($warn != null) return $warn; + return ['result'=>'ok', 'message' => '']; + } +} \ No newline at end of file diff --git a/www/internals/blog.php b/www/internals/blog.php index 1dbcca4..6ffb112 100644 --- a/www/internals/blog.php +++ b/www/internals/blog.php @@ -6,10 +6,10 @@ class Blog { $all = require (__DIR__ . '/../statics/blog/__all.php'); - return array_map('self::completeSingle', $all); + return array_map('self::readSingle', $all); } - private static function completeSingle($d) + private static function readSingle($d) { if ($d['cat']==='blog') $d['url'] = "/blog/" . $d['id'] . "/" . destructiveUrlEncode($d['title']); @@ -20,6 +20,8 @@ class Blog $d['file_fragment'] = __DIR__ . '/../statics/blog/' . $d['fragment']; + if (!array_key_exists('extras', $d)) $d['extras'] = []; + return $d; } @@ -66,6 +68,12 @@ class Blog // aok + } else if ($post['type'] === 'aoc') { + + if (!array_key_exists('aoc:year', $post['extras'])) return ['result'=>'err', 'message' => 'AdventOfCode metadata [aoc:year] missing: ' . $post['title']]; + + // aok + } else { return ['result'=>'err', 'message' => 'Unknown type ' . $post['type']]; diff --git a/www/internals/euler.php b/www/internals/euler.php index 181b85d..c6b3c04 100644 --- a/www/internals/euler.php +++ b/www/internals/euler.php @@ -34,7 +34,7 @@ class Euler public static function getEulerProblemFromStrIdent($ident) { - $e = explode('-', $ident, 2); + $e = explode('-', $ident, 2); // problem-xxx if (count($e)!==2) return null; $i = intval($e[1], 10); diff --git a/www/pages/admin.php b/www/pages/admin.php index 7602096..0f04a50 100644 --- a/www/pages/admin.php +++ b/www/pages/admin.php @@ -6,6 +6,7 @@ require_once (__DIR__ . '/../internals/highscores.php'); require_once (__DIR__ . '/../internals/alephnoteStatistics.php'); require_once (__DIR__ . '/../internals/blog.php'); require_once (__DIR__ . '/../internals/euler.php'); +require_once (__DIR__ . '/../internals/adventofcode.php'); require_once (__DIR__ . '/../internals/highscores.php'); require_once (__DIR__ . '/../internals/mikeschergitgraph.php'); require_once (__DIR__ . '/../internals/programs.php'); @@ -21,6 +22,7 @@ $consistency_books = Books::checkConsistency(); $consistency_egh = MikescherGitGraph::checkConsistency(); $consistency_progimg = Programs::checkThumbnails(); $consistency_bookimg = Books::checkThumbnails(); +$consistency_aoc = AdventOfCode::checkConsistency(); ?> Book thumbnails:
input;
+
+void Main()
+{
+ input = File
+ .ReadAllLines(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), @"10_input.txt"))
+ .Where(p => !string.IsNullOrWhiteSpace(p))
+ .Select(l => new P
+ {
+ XX=int.Parse(l.Substring(10,6).Trim()),
+ YY=int.Parse(l.Substring(18,6).Trim()),
+ VX=int.Parse(l.Substring(36,2).Trim()),
+ VY=int.Parse(l.Substring(40,2).Trim()),
+ })
+ .ToList();
+
+
+
+ for (;;)
+ {
+ foreach (var v in input) { v.XX += v.VX; v.YY += v.VY; }
+
+
+ if (input.Any(Alone)) continue;
+ Print();
+
+ return;
+ }
+
+}
+
+bool Alone(P p) => !input.Any(i => i != p && Math.Abs(i.XX-p.XX)<=1 && Math.Abs(i.YY-p.YY)<=1);
+
+void Print()
+{
+ int minX = input.Min(i => i.XX);
+ int maxX = input.Max(i => i.XX);
+ int minY = input.Min(i => i.YY);
+ int maxY = input.Max(i => i.YY);
+
+ var b = new StringBuilder();
+ for (int y = minY; y <= maxY; y++)
+ {
+ for (int x = minX; x <= maxX; x++)
+ {
+ b.Append(input.Any(i => i.XX==x&&i.YY==y)?'#':'.');
+ }
+ b.AppendLine();
+ }
+ b.ToString().Dump();
+
+}
diff --git a/www/statics/aoc/2018/10-2.linq b/www/statics/aoc/2018/10-2.linq
new file mode 100644
index 0000000..d6d6358
--- /dev/null
+++ b/www/statics/aoc/2018/10-2.linq
@@ -0,0 +1,56 @@
+
input;
+
+void Main()
+{
+ input = File
+ .ReadAllLines(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), @"10_input.txt"))
+ .Where(p => !string.IsNullOrWhiteSpace(p))
+ .Select(l => new P
+ {
+ XX = int.Parse(l.Substring(10, 6).Trim()),
+ YY = int.Parse(l.Substring(18, 6).Trim()),
+ VX = int.Parse(l.Substring(36, 2).Trim()),
+ VY = int.Parse(l.Substring(40, 2).Trim()),
+ })
+ .ToList();
+
+
+
+ for (int i = 1; ; i++)
+ {
+ foreach (var v in input) { v.XX += v.VX; v.YY += v.VY; }
+
+
+ if (input.Any(Alone)) continue;
+ //Print();
+ i.Dump();
+ return;
+ }
+
+}
+
+bool Alone(P p) => !input.Any(i => i != p && Math.Abs(i.XX - p.XX) <= 1 && Math.Abs(i.YY - p.YY) <= 1);
+
+void Print()
+{
+ int minX = input.Min(i => i.XX);
+ int maxX = input.Max(i => i.XX);
+ int minY = input.Min(i => i.YY);
+ int maxY = input.Max(i => i.YY);
+
+ var b = new StringBuilder();
+ for (int y = minY; y <= maxY; y++)
+ {
+ for (int x = minX; x <= maxX; x++)
+ {
+ b.Append(input.Any(i => i.XX == x && i.YY == y) ? '#' : '.');
+ }
+ b.AppendLine();
+ }
+ b.ToString().Dump();
+
+}
diff --git a/www/statics/aoc/2018/10_challenge.txt b/www/statics/aoc/2018/10_challenge.txt
new file mode 100644
index 0000000..56d3acb
--- /dev/null
+++ b/www/statics/aoc/2018/10_challenge.txt
@@ -0,0 +1,149 @@
+--- Day 10: The Stars Align ---
+
+It's no use; your navigation system simply isn't capable of providing walking directions in the arctic circle, and certainly not in 1018.
+
+The Elves suggest an alternative. In times like these, North Pole rescue operations will arrange points of light in the sky to guide missing Elves back to base. Unfortunately, the message is easy to miss: the points move slowly enough that it takes hours to align them, but have so much momentum that they only stay aligned for a second. If you blink at the wrong time, it might be hours before another message appears.
+
+You can see these points of light floating in the distance, and record their position in the sky and their velocity, the relative change in position per second (your puzzle input). The coordinates are all given from your perspective; given enough time, those positions and velocities will move the points into a cohesive message!
+
+Rather than wait, you decide to fast-forward the process and calculate what the points will eventually spell.
+
+For example, suppose you note the following points:
+
+position=< 9, 1> velocity=< 0, 2>
+position=< 7, 0> velocity=<-1, 0>
+position=< 3, -2> velocity=<-1, 1>
+position=< 6, 10> velocity=<-2, -1>
+position=< 2, -4> velocity=< 2, 2>
+position=<-6, 10> velocity=< 2, -2>
+position=< 1, 8> velocity=< 1, -1>
+position=< 1, 7> velocity=< 1, 0>
+position=<-3, 11> velocity=< 1, -2>
+position=< 7, 6> velocity=<-1, -1>
+position=<-2, 3> velocity=< 1, 0>
+position=<-4, 3> velocity=< 2, 0>
+position=<10, -3> velocity=<-1, 1>
+position=< 5, 11> velocity=< 1, -2>
+position=< 4, 7> velocity=< 0, -1>
+position=< 8, -2> velocity=< 0, 1>
+position=<15, 0> velocity=<-2, 0>
+position=< 1, 6> velocity=< 1, 0>
+position=< 8, 9> velocity=< 0, -1>
+position=< 3, 3> velocity=<-1, 1>
+position=< 0, 5> velocity=< 0, -1>
+position=<-2, 2> velocity=< 2, 0>
+position=< 5, -2> velocity=< 1, 2>
+position=< 1, 4> velocity=< 2, 1>
+position=<-2, 7> velocity=< 2, -2>
+position=< 3, 6> velocity=<-1, -1>
+position=< 5, 0> velocity=< 1, 0>
+position=<-6, 0> velocity=< 2, 0>
+position=< 5, 9> velocity=< 1, -2>
+position=<14, 7> velocity=<-2, 0>
+position=<-3, 6> velocity=< 2, -1>
+
+Each line represents one point. Positions are given as >();
+
+ while(points.Any())
+ {
+ var p = points.First();
+ points.RemoveAt(0);
+ constellations.Add(Constell(p, points).ToList());
+ }
+
+ //constellations.Select(c => c.Select(q => string.Join(" ; ", q))).Dump();
+ constellations.Count().Dump();
+}
+
+IEnumerable