Day 25 - [Let It Snow] 
void Main()
{
// To continue, please consult the code grid in the manual. Enter the code at row 2947, column 3029.
var x = FindSequenceNumber(2947, 3029);
var startCode = 20151125;
var code = (long)startCode;
for(int i = 1; i < x; i++){
code = GetNext(code);
}
code.Dump();
}
long GetNext(long code) => (code*252533) % 33554393;
long FindSequenceNumber(int row, int col)
{
var rowstart = 1;
for (int r = 0; r < row; r++)
{
rowstart += r;
}
var cell = rowstart;
for (int c = 1; c < col; c++)
{
cell += row + c;
}
return cell;
}
Day 24 - [It Hangs in the Balance] 
void Main()
{
var input =
File.ReadAllLines(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), "..", "day24.txt"))
.Select(int.Parse)
.ToList();
var part1 = GetPackageConfiguration(input, 3);
part1.Dump();
var part2 = GetPackageConfiguration(input, 4);
part2.Dump();
}
public long CalculateQuantumeEntanglement(IEnumerable<int> packages) => packages.Aggregate(1L, (x, y) => x * y);
public long GetPackageConfiguration(List<int> packages, int groups)
{
var groupWeight = packages.Sum() / groups;
for (var packagesInGroup = 0; packagesInGroup < packages.Count; packagesInGroup++)
{
var possibleGroups = FindPackageGroups(packages, packagesInGroup, groupWeight);
if (possibleGroups.Any())
return possibleGroups.Min(CalculateQuantumeEntanglement);
}
return default;
}
public IEnumerable<IImmutableList<int>> FindPackageGroups(List<int> packages, int packagesToInclude, int remainingWeight)
{
if (remainingWeight == 0)
{
yield return ImmutableList.Create<int>();
yield break;
}
if (packagesToInclude < 0 || remainingWeight < 0 || packages.Count == 0)
yield break;
if (packages[0] <= remainingWeight)
foreach (var group in FindPackageGroups(packages.Skip(1).ToList(), packagesToInclude - 1, remainingWeight - packages[0]))
{
yield return group.Add(packages[0]);
}
foreach (var group in FindPackageGroups(packages.Skip(1).ToList(), packagesToInclude, remainingWeight))
{
yield return group;
}
}
Day 23 - [Opening the Turing Lock] 
void Main()
{
var registers = new Dictionary<char,uint> { {'a', 0}, {'b', 0}};
// part 1
UseTrulyStateOfTheArtTechnologyToRunProgram(registers, input);
registers.Dump();
// part 2
registers = new Dictionary<char,uint> { {'a', 1}, {'b', 0}};
UseTrulyStateOfTheArtTechnologyToRunProgram(registers, input);
registers.Dump();
}
void UseTrulyStateOfTheArtTechnologyToRunProgram(Dictionary<char,uint> registers, string[] program)
{
var index = 0;
do
{
var i = program[index];
switch (i.Substring(0,3))
{
case "hlf" : registers[i[4]] /= 2; index++; break;
case "inc" : registers[i[4]] += 1; index++; break;
case "tpl" : registers[i[4]] *= 3; index++; break;
case "jmp" : index += int.Parse(i.Substring(4)); break;
case "jie" : index += registers[i[4]] % 2 == 0 ? int.Parse(i.Substring(7)) : 1; break;
case "jio" : index += registers[i[4]] == 1 ? int.Parse(i.Substring(7)) : 1; break;
}
} while (index < program.Length);
}
Day 22 - [Wizard Simulator 20XX] 
void Main()
{
var game = new GameState
{
playerHitPoints = 50,
playerMana = 500,
bossDamage = 10,
bossHitPoints = 71,
spellStates = new(),
};
var part1 = game.PlayerPlays()
.Where(p => p.playerHitPoints > 0)
.OrderBy(p => p.playerManaSpent)
.First();
part1.playerManaSpent.Dump();
var part2 = game.PlayerPlays(true)
.Where(p => p.playerHitPoints > 0)
.OrderBy(p => p.playerManaSpent)
.First();
part2.playerManaSpent.Dump();
}
public class GameState
{
public int playerManaSpent;
public int playerHitPoints;
public int playerDamage;
public int playerMana;
public int playerArmor;
public int bossHitPoints;
public int bossDamage;
public Dictionary<Spell, int> spellStates;
}
static class Helpers
{
static GameState Clone(this GameState gameState)
{
return new GameState
{
playerManaSpent = gameState.playerManaSpent,
playerHitPoints = gameState.playerHitPoints,
playerDamage = gameState.playerDamage,
playerMana = gameState.playerMana,
playerArmor = gameState.playerArmor,
bossHitPoints = gameState.bossHitPoints,
bossDamage = gameState.bossDamage,
spellStates = gameState.spellStates.ToDictionary(s => s.Key, s => s.Value),
};
}
static void CastSpell(this GameState gameState, Spell spell)
{
gameState.playerMana -= spell.Cost;
gameState.playerManaSpent += spell.Cost;
gameState.spellStates[spell] = spell.Timer;
spell.Cast(gameState);
}
static bool IsOver(this GameState gameState) =>
gameState.bossHitPoints <= 0 || gameState.playerHitPoints <= 0;
public static bool CanCast(this GameState state, Spell spell) =>
state.playerMana >= spell.Cost && (!state.spellStates.TryGetValue(spell, out var s) || s == 0);
public static IEnumerable<GameState> PlayerPlays(this GameState gameState, bool hardMode = false)
{
if (hardMode)
gameState.playerHitPoints--;
gameState.ApplySpells();
foreach (var spell in Spells.Where(s => gameState.CanCast(s)))
{
var cloned = gameState.Clone();
cloned.CastSpell(spell);
if (cloned.IsOver())
yield return cloned;
else
{
cloned.BossPlays();
if (cloned.IsOver())
yield return cloned;
else
foreach (var s in cloned.PlayerPlays(hardMode))
yield return s;
}
}
}
static void BossPlays(this GameState gameState)
{
gameState.ApplySpells();
if (gameState.bossHitPoints > 0)
gameState.playerHitPoints -= (gameState.bossDamage - gameState.playerArmor);
}
static void ApplySpells(this GameState gameState)
{
foreach (var spell in gameState.spellStates.Where(s => s.Value > 0).Select(s => s.Key))
{
gameState.spellStates[spell]--;
spell.Assess(gameState, spell);
}
}
}
public class Spell
{
public int Timer { get; set; }
public int Cost { get; set; }
public Action<GameState> Cast = _ => { };
public Action<GameState, Spell> Assess = (_, _) => { };
}
public static List<Spell> Spells = new()
{
new Spell
{
// Magic Missile
Cost = 53,
Cast = state => state.bossHitPoints -= 4
},
new Spell
{
// Drain
Cost = 73,
Cast = state =>
{
state.bossHitPoints -= 2;
state.playerHitPoints += 2;
}
},
new Spell
{
// Shield
Cost = 113,
Timer = 6,
Cast = state => state.playerArmor = 7,
Assess = (state, spell) => state.playerArmor = state.spellStates[spell] == 0 ? 0 : state.playerArmor
},
new Spell
{
// Poison
Cost = 173,
Timer = 6,
Assess = (state, spell) => state.bossHitPoints -= 3
},
new Spell
{
// Recharge
Cost = 229,
Timer = 5,
Assess = (state, spell) => state.playerMana += 101
},
};
Day 21 - [RPG Simulator 20XX] 
void Main()
{
var playerChoices =
from w in Weapons
from a in Armor.Append(new KeyValuePair<string, Stats>("None", new Stats()))
from r1 in Rings.Append(new KeyValuePair<string, Stats>("None", new Stats()))
from r2 in Rings.Append(new KeyValuePair<string, Stats>("None", new Stats()))
where r1.Key != r2.Key
select ($"{w.Key}; {a.Key}; {r1.Key}; {r2.Key}", new Stats
{
HitPoints = 100,
Cost = w.Value.Cost + a.Value.Cost + r1.Value.Cost + r2.Value.Cost,
Armor = w.Value.Armor + a.Value.Armor + r1.Value.Armor + r2.Value.Armor,
Damage = w.Value.Damage + a.Value.Damage + r1.Value.Damage + r2.Value.Damage,
});
var part1 = playerChoices.Where(p => Fight(p.Item2, new Stats { HitPoints = 109, Damage = 8, Armor = 2 })).OrderBy(p => p.Item2.Cost).First().Item2.Cost;
part1.Dump();
var part2 = playerChoices.Where(p => !Fight(p.Item2, new Stats { HitPoints = 109, Damage = 8, Armor = 2 })).OrderByDescending(p => p.Item2.Cost).First().Item2.Cost;
part2.Dump();
}
bool Fight(Stats player, Stats enemy)
{
while (true)
{
enemy.HitPoints -= GetDamage(player, enemy);
if (enemy.HitPoints <= 0) return true;
player.HitPoints -= GetDamage(enemy, player);
if (player.HitPoints <= 0) return false;
}
}
int GetDamage(Stats attacker, Stats defender) =>
Math.Max(1, attacker.Damage - defender.Armor);
class Stats
{
public int Cost { get; set; }
public int HitPoints { get; set; }
public int Damage { get; set; }
public int Armor { get; set; }
}
Dictionary<string, Stats> Weapons = new Dictionary<string, Stats>() {
{ "Dagger", new() { Cost = 8, Damage = 4 }},
{ "Shortsword", new() { Cost = 10, Damage = 5 }},
{ "Warhammer", new() { Cost = 25, Damage = 6 }},
{ "Longsword", new() { Cost = 40, Damage = 7 }},
{ "Greataxe", new() { Cost = 74, Damage = 8 }},
};
Dictionary<string, Stats> Armor = new Dictionary<string, Stats>() {
{ "Leather", new() { Cost = 13, Armor = 1 }},
{ "Chainmail", new() { Cost = 31, Armor = 2 }},
{ "Splintmail", new() { Cost = 53, Armor = 3 }},
{ "Bandedmail", new() { Cost = 75, Armor = 4 }},
{ "Platemail", new() { Cost = 102, Armor = 5 }},
};
Dictionary<string, Stats> Rings = new Dictionary<string, Stats>() {
{ "Damage +1", new() { Cost = 25, Damage = 1 }},
{ "Damage +2", new() { Cost = 50, Damage = 2 }},
{ "Damage +3", new() { Cost = 100, Damage = 3 }},
{ "Defense +1", new() { Cost = 20, Armor = 1 }},
{ "Defense +2", new() { Cost = 40, Armor = 2 }},
{ "Defense +3", new() { Cost = 80, Armor = 3 }},
};
Day 20 - [Infinite Elves and Infinite Houses] 
void Main()
{
var input = 29000000;
var guess = 0;
while(PresentsForHouse(guess) < input)
guess += 1000 ;
var house = guess;
for (var i = 0; i< 50000; i++)
if (PresentsForHouse(guess-i) >= input)
house = guess-i;
house.Dump();
guess = 0;
while(PresentsForHouse2(guess) < input)
guess += 1000 ;
house = guess;
for (var i = 0; i< 50000; i++)
if (PresentsForHouse2(guess-i) >= input)
house = guess-i;
house.Dump();
}
int PresentsForHouse(int house)
{
var presents = 0;
for(var elf = 1; elf <= house; elf++)
if ((house % elf) == 0)
presents += (elf * 10);
return presents;
}
int PresentsForHouse2(int house)
{
var presents = 0;
for(var elf = 1; elf <= house; elf++)
if ((house % elf) == 0 && (house / elf) <= 50)
presents += (elf * 11);
return presents;
}
Day 19 - [Medicine for Rudolph] 
void Main()
{
var input =
File.ReadAllLines(Path.Combine(Path.GetDirectoryName (Util.CurrentQueryPath),"..","day19.txt"));
var replacements =
input.Where(i => i.Contains("=>"))
.Select(i => i.Split(new[] { " => "},StringSplitOptions.None))
.Select(i => new ParticleReplacement { Particle = i[0], Replacement = i[1] })
.ToList();
var molecule =
input.Where(i => !i.Contains("=>") && !string.IsNullOrEmpty(i))
.FirstOrDefault();
// part 1
var p = new List<string>();
foreach (Match m in Regex.Matches(molecule, "("+ string.Join("|", replacements.Select(r => r.Particle).Distinct())+")"))
{
var leading = molecule.Substring(0, m.Groups[1].Index);
var trailing = molecule.Substring(m.Groups[1].Index + m.Groups[1].Length);
foreach(var s in replacements.Where(r=>r.Particle == m.Groups[1].Value).Select(r=>r.Replacement))
p.Add(leading + s + trailing);
}
p.Distinct().ToList().Count().Dump();
// part 2
var temp = molecule;
var steps = 0;
while (temp != "e")
{
var w = replacements.OrderByDescending (r => r.Replacement.Length).First(r => temp.Contains(r.Replacement));
steps += Regex.Matches(temp,w.Replacement).Count;
temp = Regex.Replace(temp,w.Replacement, w.Particle);
}
steps.Dump();
}
public class ParticleReplacement
{
public string Particle { get; set; }
public string Replacement { get; set; }
}
Day 18 - [Like a GIF For Your Yard] 
void Main()
{
var gridOrigin = new bool [100,100];
var input = File.ReadAllLines(Path.Combine(Path.GetDirectoryName (Util.CurrentQueryPath),"..","day18.txt")).ToArray();
for(var x = 0; x<input.Length; x++)
for (var y = 0; y<input[x].Length; y++)
gridOrigin[x,y] = input[x][y] == '#';
// part 1
var grid = gridOrigin;
for (var steps = 0; steps<100; steps++)
grid=Step(grid);
Total(grid).Dump();
// part 2
grid = gridOrigin;
Corners(grid);
for (var steps = 0; steps<100; steps++)
{
grid=Step(grid);
Corners(grid);
}
Total(grid).Dump();
}
void Corners(bool[,] grid)
{
grid[0,0] = true;
grid[grid.GetLength(0)-1,0] = true;
grid[0, grid.GetLength(1)-1] = true;
grid[grid.GetLength(0)-1, grid.GetLength(1)-1] = true;
}
int Total(bool[,] grid)
{
var count = 0;
for(var x = 0; x<grid.GetLength(0); x++)
for (var y = 0; y<grid.GetLength(1); y++)
if (grid[x,y])
count++;
return count;
}
bool[,] Step(bool[,] current)
{
var ret = new bool[current.GetLength(0),current.GetLength(1)];
for(var x=0; x<current.GetLength(0); x++)
for (var y=0; y<current.GetLength(1); y++)
ret[x,y] = current[x,y]
? (Count(current,x,y) == 2 || Count(current,x,y) == 3)
: Count(current,x,y) == 3;
return ret;
}
int Count(bool[,] current, int x, int y)
{
var maxX = current.GetLength(0)-1;
var maxY = current.GetLength(1)-1;
var ret=0;
for(var xx = (x==0?0:x-1); xx<=(x==maxX?maxX:x+1);xx++)
for(var yy = (y==0?0:y-1); yy<=(y==maxY?maxY:y+1);yy++)
if (!(x == xx && y == yy) && current[xx,yy])
ret++;
return ret;
}
Day 17 - [No Such Thing as Too Much] 
void Main()
{
var containers =
File.ReadAllLines(Path.Combine(Path.GetDirectoryName (Util.CurrentQueryPath),"..","day17.txt"))
.Select (f => int.Parse(f)).OrderByDescending(f => f)
.ToArray();
var counter = 0;
var max = 1 << containers.Length;
var c = new List<int>();
while (++counter < max)
{
var y = GetItemsTotaling(containers, counter, 150);
if (y > 0)
c.Add(y);
}
// part 1
c.Count().Dump();
// part 2
c.Where(m => m == c.Min(mm => mm)).Count().Dump();
}
int GetItemsTotaling(int[] source, int bits, int total)
{
var count = 0;
var volume = 0;
for (int i = source.Length - 1; i >=0 ; i--)
if ((bits & (1 << i)) > 0)
{
volume += source[i];
if (volume > total)
break;
count++;
}
return volume == total ? count : -1;
}
Day 16 - [Aunt Sue] 
void Main()
{
var auntSues = File.ReadAllLines(Path.Combine(Path.GetDirectoryName (Util.CurrentQueryPath),"..","day16.txt")).Select (f => ParseSue(f));
// part 1
auntSues.Where(a => a.Children == null || a.Children == 3)
.Where(a => a.Cats == null || a.Cats == 7)
.Where(a => a.Samoyeds == null || a.Samoyeds == 2)
.Where(a => a.Pomeranians == null || a.Pomeranians == 3)
.Where(a => a.Akitas == null || a.Akitas == 0)
.Where(a => a.Vizslas == null || a.Vizslas == 0)
.Where(a => a.Goldfish == null || a.Goldfish == 5)
.Where(a => a.Trees == null || a.Trees == 3)
.Where(a => a.Cars == null || a.Cars == 2)
.Where(a => a.Perfumes == null || a.Perfumes == 1)
.Single().Id.Dump();
// part 2
auntSues.Where(a => a.Children == null || a.Children == 3)
.Where(a => a.Cats == null || a.Cats > 7)
.Where(a => a.Samoyeds == null || a.Samoyeds == 2)
.Where(a => a.Pomeranians == null || a.Pomeranians < 3)
.Where(a => a.Akitas == null || a.Akitas == 0)
.Where(a => a.Vizslas == null || a.Vizslas == 0)
.Where(a => a.Goldfish == null || a.Goldfish < 5)
.Where(a => a.Trees == null || a.Trees > 3)
.Where(a => a.Cars == null || a.Cars == 2)
.Where(a => a.Perfumes == null || a.Perfumes == 1)
.Single().Id.Dump();
}
public AuntSue ParseSue(string input)
{
var m = Regex.Match(input, @"^Sue (\d+)\: (([a-z]+)\: (\d+)(, )?)+$");
var sue = new AuntSue { Id = int.Parse(m.Groups[1].Value) };
for( var i = 0; i < m.Groups[2].Captures.Count; i++)
{
switch(m.Groups[3].Captures[i].Value)
{
case "children": sue.Children=int.Parse(m.Groups[4].Captures[i].Value); break;
case "cats": sue.Cats=int.Parse(m.Groups[4].Captures[i].Value); break;
case "samoyeds": sue.Samoyeds=int.Parse(m.Groups[4].Captures[i].Value); break;
case "pomeranians": sue.Pomeranians=int.Parse(m.Groups[4].Captures[i].Value); break;
case "akitas": sue.Akitas=int.Parse(m.Groups[4].Captures[i].Value); break;
case "vizslas": sue.Vizslas=int.Parse(m.Groups[4].Captures[i].Value); break;
case "goldfish": sue.Goldfish=int.Parse(m.Groups[4].Captures[i].Value); break;
case "trees": sue.Trees=int.Parse(m.Groups[4].Captures[i].Value); break;
case "cars": sue.Cars=int.Parse(m.Groups[4].Captures[i].Value); break;
case "perfumes": sue.Perfumes=int.Parse(m.Groups[4].Captures[i].Value); break;
}
}
return sue;
}
public class AuntSue
{
public int Id { get; set; }
public int? Children { get ;set; }
public int? Cats { get ;set; }
public int? Samoyeds { get; set; }
public int? Pomeranians { get ;set; }
public int? Akitas { get ;set; }
public int? Vizslas { get ;set; }
public int? Goldfish { get ;set; }
public int? Trees { get ;set; }
public int? Cars { get; set; }
public int? Perfumes { get; set; }
}
Day 15 - [Science for Hungry People] 
void Main()
{
var ingredients =
File.ReadAllLines(Path.Combine(Path.GetDirectoryName (Util.CurrentQueryPath),"..","day15.txt"))
.Select(s =>
{
var m = Regex.Match(s, @"(.+)\: capacity (-?\d+), durability (-?\d+), flavor (-?\d+), texture (-?\d+), calories (\d+)" );
return new Ingredient
{
Name = m.Groups[1].Value,
Capacity = int.Parse(m.Groups[2].Value),
Durability = int.Parse(m.Groups[3].Value),
Flavor = int.Parse(m.Groups[4].Value),
Texture = int.Parse(m.Groups[5].Value),
Calories = int.Parse(m.Groups[6].Value),
};
}).ToArray();
var recipes = GetAll().Select (x => new [] { new IngredientAmount { Ingredient = ingredients[0], Amount = x[0] },
new IngredientAmount { Ingredient = ingredients[1], Amount = x[1] },
new IngredientAmount { Ingredient = ingredients[2], Amount = x[2] },
new IngredientAmount { Ingredient = ingredients[3], Amount = x[3] } });
var scores = recipes.Select(r => ScoreCookie(r));
// part 1
scores.OrderByDescending (r => r.Item1).First().Item1.Dump();
// part 2
scores.Where(r => r.Item2 == 500).OrderByDescending (r => r.Item1).First().Item1.Dump();
}
public IEnumerable<int[]> GetAll()
{
for (var a=0; a <= 100; a++) {
for (var b=0; b <= 100 -a ; b++) {
for (var c=0; c <= 100 -a -b; c++) {
yield return new [] { a,b,c,100-a-b-c};
}
}
}
}
public class IngredientAmount
{
public Ingredient Ingredient { get ;set; }
public int Amount { get ;set; }
}
public class Ingredient
{
public string Name { get ;set; }
public int Capacity { get ;set; }
public int Durability { get ;set; }
public int Flavor { get ;set; }
public int Texture { get ;set; }
public int Calories { get ;set; }
}
public Tuple<int, int> ScoreCookie(IEnumerable<IngredientAmount> recipe)
{
var total = new Ingredient
{
Capacity = recipe.Sum(r => r.Amount * r.Ingredient.Capacity),
Durability = recipe.Sum(r => r.Amount * r.Ingredient.Durability),
Flavor = recipe.Sum(r => r.Amount * r.Ingredient.Flavor),
Texture = recipe.Sum(r => r.Amount * r.Ingredient.Texture),
Calories = recipe.Sum(r => r.Amount * r.Ingredient.Calories),
};
return new Tuple<int, int>( (total.Capacity < 0 ? 0 : total.Capacity) * (total.Durability < 0 ? 0 : total.Durability) * (total.Flavor < 0 ? 0 : total.Flavor) * (total.Texture < 0 ? 0 : total.Texture) , total.Calories);
}
Day 14 - [Reindeer Olympics] 
void Main()
{
var reindeer =
File.ReadAllLines(Path.Combine(Path.GetDirectoryName (Util.CurrentQueryPath),"..","day14.txt"))
.Select(s =>
{
var m = Regex.Match(s, @"^([^ ]+) .* (\d+) .* (\d+) .* (\d+)" );
return new Reindeer
{
Name = m.Groups[1].Value,
Rate = int.Parse(m.Groups[2].Value),
Fly = int.Parse(m.Groups[3].Value),
Rest = int.Parse(m.Groups[4].Value)
};
});
// part 1
reindeer.Select(r => FlyFor(r, 2503)).OrderByDescending(t => t).First().Dump();
// part 2
var scores = reindeer.ToDictionary (r => r.Name, r => 0);
for (var t = 1; t < 2503; t++)
{
var leaders = reindeer.Select (r => new { r.Name, Distance = FlyFor(r, t) })
.GroupBy (r => r.Distance)
.OrderByDescending (r => r.Key)
.First()
.Select(r => r.Name);
foreach (var l in leaders)
scores[l]++;
}
scores.OrderByDescending (s => s.Value).First().Value.Dump();
}
public class Reindeer
{
public string Name { get ;set; }
public int Rate { get ;set; }
public int Fly { get ;set; }
public int Rest { get ;set; }
}
public int FlyFor(Reindeer d, int seconds)
{
var distance = 0;
var elapsed = 0;
while (elapsed < seconds)
{
if (elapsed + d.Fly < seconds)
{
elapsed += d.Fly;
distance += d.Rate * d.Fly;
}
else
{
distance += d.Rate * (seconds - elapsed);
elapsed = seconds;
}
elapsed += d.Rest;
}
return distance;
}
Day 13 - [Knights of the Dinner Table] 
void Main()
{
var measurements = File.ReadAllLines(Path.Combine(Path.GetDirectoryName (Util.CurrentQueryPath),"..","day13.txt")).Select(s =>
{
var m = Regex.Match(s, @"([^ ]+) would (gain|lose) (\d+) .* ([^ ]+)\.");
return new Measurement { Person = m.Groups[1].Value, Adjacent = m.Groups[4].Value, HappinessUnits = int.Parse(m.Groups[3].Value) * (m.Groups[2].Value == "lose" ? -1 : 1) };
}).ToList();
// part 1
CalculateHappiness(measurements).Dump();
// part 2
measurements.AddRange(measurements.Select(m => m.Person).Distinct().SelectMany(p => new [] { new Measurement { Person = "Me", Adjacent = p, HappinessUnits = 0 }, new Measurement { Person = p, Adjacent="Me" , HappinessUnits = 0}}).ToList());
CalculateHappiness(measurements).Dump();
}
int CalculateHappiness(List<Measurement> measurements)
{
var possibilities = Permutations(measurements.Select(m => m.Person).Distinct().ToList()).ToList();
var happiness = possibilities.Select(p => p.ToArray()).Select(p =>
{
var score = 0;
for (var pos = 0; pos < p.Length; pos ++)
{
score += measurements.First (m => m.Person == p[pos] && m.Adjacent == p[(pos+1 < p.Length) ? pos + 1 : 0]).HappinessUnits;
score += measurements.First (m => m.Person == p[pos] && m.Adjacent == p[(pos > 0) ? pos - 1 : p.Length-1]).HappinessUnits;
}
return score;
});
return happiness.OrderByDescending(s => s).First ();
}
public class Measurement
{
public string Person { get; set; }
public int HappinessUnits { get; set; }
public string Adjacent { get; set; }
}
IEnumerable<IEnumerable<T>> Permutations<T>(IEnumerable<T> list, int length = 0)
{
if (length == 0) length = list.Count();
if (length == 1) return list.Select(t => new T[] { t });
return Permutations(list, length - 1)
.SelectMany(t => list.Where(e => !t.Contains(e)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
Day 12 - [JSAbacusFramework.io] 
void Main()
{
// part 1
var reader = new JsonTextReader(new StringReader(File.ReadAllText(path)));
long count = 0;
while (reader.Read())
{
if (reader.TokenType == JsonToken.Integer)
count += (long)reader.Value;
}
count.Dump();
// part 2
var s = File.ReadAllText(path);
reader = new JsonTextReader(new StringReader(s));
Count(reader).Dump();
}
private long Count(JsonTextReader reader)
{
long ret = 0;
bool isRed= false;
bool isObject = reader.TokenType == JsonToken.StartObject;
while(reader.Read())
{
if (reader.TokenType == JsonToken.EndObject || reader.TokenType == JsonToken.EndArray)
return isRed ? 0 : ret;
if (reader.TokenType == JsonToken.Integer)
ret += (long)reader.Value;
if (reader.TokenType == JsonToken.StartObject || reader.TokenType == JsonToken.StartArray)
ret += Count(reader);
if (isObject && string.Equals(reader.Value as string, "red"))
isRed=true;
}
return ret;
}
Day 11 - [Corporate Policy] 
void Main()
{
var password = "hepxcrrq";
password = FindNextPassword(password);
password.Dump();
password = FindNextPassword(password);
password.Dump();
}
public Regex Incrementing = new Regex("(abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz)");
public Regex Forbidden = new Regex("[iol]");
public string FindNextPassword(string currentPassword)
{
do
{
currentPassword = Increment(currentPassword);
} while (Forbidden.IsMatch(currentPassword) || !Incrementing.IsMatch(currentPassword) || !HasRepeatingPairs(currentPassword));
return currentPassword;
}
public bool HasRepeatingPairs(string input)
{
var Repeats = new List<char>();
for (var i = 0; i < input.Length - 1; i++)
{
if (input[i] == input[i+1])
Repeats.Add(input[i]);
}
return Repeats.Distinct().Count() >= 2;
}
public string Increment(string input)
{
var chars = input.ToCharArray();
for (var i = 1; i <= chars.Length; i++)
{
if (chars[chars.Length-i] == 'z')
{
chars[chars.Length-i] = 'a';
continue;
}
chars[chars.Length-i]++;
break;
}
return new string(chars);
}
Day 10 - [Elves Look, Elves Say] 
void Main()
{
// part 1
var value = input;
for (var counter = 0; counter < 40; counter++)
value = LookAndSay(value);
value.Length.Dump();
// part 2
value = input;
for (var counter = 0; counter < 50; counter++)
value = LookAndSay(value);
value.Length.Dump();
}
string LookAndSay(string i)
{
var ret = new StringBuilder();
int pos = 0;
while (pos < i.Length)
{
var counter = 0;
var current = i[pos];
while ((pos+counter) < i.Length && i[pos+counter] == current)
counter++;
ret.AppendFormat("{0}{1}", counter, current);
pos += counter;
}
return ret.ToString();
}
Day 9 - [All in a Single Night] 
void Main()
{
var possibilities = Permutations( segments.Select(s => s.PointA).Concat(segments.Select(s => s.PointB)).Distinct());
var routes = possibilities.Select(p => Calculate(p, segments));
routes.Min().Dump();
routes.Max().Dump();
}
int Calculate(IEnumerable<string> points, List<Segment> segments)
{
return points.Zip(points.Skip(1), (f,s) => segments.Single(se => (se.PointA == f && se.PointB == s) || (se.PointB == f && se.PointA == s) ).Distance ).Sum();
}
IEnumerable<IEnumerable<T>> Permutations<T>(IEnumerable<T> list, int length = 0)
{
if (length == 0) length = list.Count();
if (length == 1) return list.Select(t => new T[] { t });
return Permutations(list, length - 1)
.SelectMany(t => list.Where(e => !t.Contains(e)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
public class Route
{
public IEnumerable<string> Points { get ;set; }
public IEnumerable<Segment> Legs { get ;set; }
public int Distance { get ;set; }
}
public class Segment
{
public string PointA { get ;set; }
public string PointB { get ;set; }
public int Distance { get ;set; }
}
Day 8 - [Matchsticks] 
// part 1
var totalLength = strings.Sum(s => s.Length);
var unescaped = strings.Select(s => s.Substring(1, s.Length-2))
.Select(s => Regex.Replace(s, "\\\\\\\\", @"\"))
.Select(s => Regex.Replace(s, "\\\\\"", "\""))
.Select(s => Regex.Replace(s, "\\\\[x]([0-9a-f]{2})", "X"));
var memLength = unescaped.Sum(s => s.Length);
(totalLength - memLength).Dump();
// part 2
var escaped = strings.Select(u => Regex.Replace(u, "\\\\", "\\\\"))
.Select(u => Regex.Replace(u, "\"","\\\""));
(escaped.Sum(s => s.Length + 2) - totalLength).Dump();
Day 7 - [Some Assembly Required] 
void Main()
{
// part 1
Resolve(instructions);
instructions["a"].Output.Dump();
// part 2
var answer = instructions["a"].Output;
foreach (var i in instructions)
i.Value.Output = null;
instructions["b"].Input = answer.ToString();
Resolve(instructions);
instructions["a"].Output.Dump();
}
public class Gate
{
public string Input { get ;set; }
public UInt16? Output { get; set; }
}
public ushort? Check(Dictionary<string, Gate> instructions, string input)
{
ushort value;
if (ushort.TryParse(input, out value))
return value;
else
if (instructions[input].Output != null)
return instructions[input].Output.Value;
return null;
}
public void Resolve(Dictionary<string, Gate> instructions)
{
while (instructions["a"].Output == null)
{
foreach(var i in instructions)
{
if (i.Value.Output != null)
continue;
UInt16 x;
if (UInt16.TryParse(i.Value.Input, out x))
{
i.Value.Output = x;
continue;
}
var reg = Regex.Match(i.Value.Input, @"(.+) (AND|OR|LSHIFT|RSHIFT) (.+)");
if (reg.Success)
{
var operand1 = reg.Groups[1].Value;
var op = reg.Groups[2].Value;
var operand2 = reg.Groups[3].Value;
var op1 = Check(instructions, reg.Groups[1].Value);
var op2 = Check(instructions, reg.Groups[3].Value);
if (op1 == null || op2 == null)
continue;
switch(op)
{
case "AND": i.Value.Output = (UInt16 )(op1 & op2); break;
case "OR" : i.Value.Output = (UInt16)(op1 | op2); break;
case "LSHIFT": i.Value.Output = (UInt16)(op1 << op2); break;
case "RSHIFT" : i.Value.Output = (UInt16)(op1 >> op2); break;
}
continue;
}
reg = Regex.Match(i.Value.Input, @"NOT (.*)");
if (reg.Success)
{
var op1 = Check(instructions, reg.Groups[1].Value);
if (op1 == null) continue;
i.Value.Output = (UInt16)~op1;
continue;
}
if (instructions[i.Value.Input].Output == null)
continue;
i.Value.Output = instructions[i.Value.Input].Output.Value;
continue;
}
}
}
Day 6 - [Probably a Fire Hazard] 
var grid = new Boolean[1000, 1000];
var intensity = new int[1000, 1000];
foreach (var i in instructions)
{
var coords = Regex.Match(i, @"(\d+),(\d+)");
var tl = new Point(int.Parse(coords.Groups[1].Value), int.Parse(coords.Groups[2].Value));
coords = coords.NextMatch();
var br = new Point(int.Parse(coords.Groups[1].Value), int.Parse(coords.Groups[2].Value));
for (var x = tl.X; x <= br.X; x++)
{
for (var y = tl.Y; y <= br.Y; y++)
{
if (i.Contains("toggle"))
{
grid[x, y] = !grid[x, y];
intensity[x, y] += 2;
}
else
{
var val = i.Contains("on");
grid[x, y] = val;
if (val)
intensity[x ,y]++;
else
if (intensity[x, y] > 0)
intensity[x, y]--;
}
}
}
}
int counter = 0;
int brightness = 0;
for (var x = 0; x < 1000; x++)
{
for (var y = 0; y < 1000; y++)
{
brightness += intensity[x, y];
if (grid[x,y])
counter++;
}
}
counter.Dump();
brightness.Dump();
Day 5 - [Doesn’t He Have Intern-Elves For This?] 
// part 1
var regexVowels = new Regex(@"(.*[aeiou].*){3,}", RegexOptions.IgnoreCase);
var regexDoubled = new Regex(@"(.)\1", RegexOptions.IgnoreCase);
var regexExclude = new Regex(@"(ab|cd|pq|xy)", RegexOptions.IgnoreCase);
strings.Where (s => regexVowels.IsMatch(s) && regexDoubled.IsMatch(s) && !regexExclude.IsMatch(s)).Count().Dump();
// part 2
var regex1 = new Regex(@"(.{2}).*\1", RegexOptions.IgnoreCase);
var regex2 = new Regex(@"(.).\1", RegexOptions.IgnoreCase);
strings.Where (s => regex1.IsMatch(s) && regex2.IsMatch(s)).Count().Dump();;
Day 4 - [The Ideal Stocking Stuffer] 
// part 1
using (MD5 md5Hash = MD5.Create())
{
byte[] hash;
var counter = -1;
do{
counter++;
hash = md5Hash.ComputeHash(Encoding.ASCII.GetBytes(key + counter));
} while (hash[0] != 0 || hash[1] != 0 || hash[2] > 15);
counter.Dump();
}
// part 2
using (MD5 md5Hash = MD5.Create())
{
byte[] data = keyBytes;
byte[] hash;
int currentLimit = -1;
var counter = -1;
int temp;
int count;
do{
counter++;
if (counter > currentLimit)
{
Array.Resize(ref data, data.Length + 1);
Array.Copy(keyBytes, data, keyBytes.Length);
currentLimit = (int)Math.Pow(10, data.Length - keyBytes.Length) - 1;
}
count = 0;
temp = counter;
while (temp > 0)
{
count++;
data[data.Length - count] = (byte)(temp % 10 + 48);
temp = temp / 10;
}
hash = md5Hash.ComputeHash(data);
} while (hash[0] != 0 || hash[1] != 0 || hash[2] != 0);
counter.Dump();
}
Day 3 - [Perfectly Spherical Houses in a Vacuum] 
void Main()
{
// part 1
var pos = new Point(0,0);
var deliveries = new Dictionary<Point, int>();
deliveries.Add(pos, 1);
foreach(var route in input.ToCharArray())
{
FollowRoute(ref pos, route);
RecordDelivery(pos, deliveries);
}
deliveries.Count().Dump();
// part 2
var enumerator = input.GetEnumerator();
var santa = new Point(0,0);
var roboSanta = new Point(0,0);
var deliveries2 = new Dictionary<Point, int>();
deliveries2.Add(santa,2);
while(enumerator.MoveNext())
{
FollowRoute(ref santa, enumerator.Current);
RecordDelivery(santa, deliveries2);
if (enumerator.MoveNext())
{
FollowRoute(ref roboSanta, enumerator.Current);
RecordDelivery(roboSanta, deliveries2);
}
}
deliveries2.Count().Dump();
}
void FollowRoute(ref Point position, char route)
{
switch (route)
{
case '^': position.Y++; break;
case 'v': position.Y--; break;
case '>': position.X++; break;
case '<': position.X--; break;
}
}
void RecordDelivery(Point position, Dictionary<Point, int> deliveries)
{
if (deliveries.ContainsKey(position))
deliveries[position]++;
else
deliveries.Add(position,1);
}
Day 2 - [I Was Told There Would Be No Math] 
// part 1
var paper = boxes.Select(b =>
{
var surfaces = new [] { b[0] * b[1], b[1] * b[2], b[2] * b[0] };
return surfaces.Sum (s => 2 * s) + surfaces.Min ( );
}).Sum();
paper.Dump();
// part 2
var ribbon = boxes.Select (b =>
{
var perimeter = (new [] { b[0] + b[1], b[1] + b[2], b[2] + b[0] }).Min() * 2;
var bow = b[0] * b[1] * b[2];
return perimeter + bow;
}).Sum();
ribbon.Dump();
Day 1 - [Not Quite Lisp] 
// part 1
var x = instructions.Count (i => i == '(') - instructions.Count (i => i == ')');
x.Dump();
// part 2
var floor = 0;
for (var counter = 0; counter < instructions.Length; counter++)
{
var c = instructions[counter];
if (c =='(')
floor++;
if (c == ')')
floor--;
if (floor < 0)
{
(counter+1).Dump();
break;
}
}