This one's really quick - just implement the pseduorandom number generator, iterate 2000 times, and that's that.
private uint GenNumber(uint number)
{
number = (number ^ (number << 6)) % 16777216;
number = (number ^ (number >> 5)) % 16777216;
number = (number ^ (number << 11)) % 16777216;
return number;
}
private uint GetNthNumber(uint initial, int n)
{
uint num = initial;
for (int i = 0; i < n; i++) num = GenNumber(num);
return num;
}
Okay, now it gets interesting. Today's problem is basically all in part 2. Somehow I have to find a 4-digit sequence (the sequence of changes) that would result in the highest sell price.
The obvious first step is simply to generate the prices as well as all of the changes.
private void GeneratePrices()
{
foreach (var num in initialNumbers)
{
uint lastNum = num;
int lastPrice = (int)num % 10;
var prices = new List<int>();
var changes = new List<int>();
prices.Add(lastPrice);
changes.Add(-50);
for (int i = 0; i < 2000; i++)
{
uint nextNum = GenNumber(lastNum);
int nextPrice = (int)(nextNum % 10);
prices.Add((int)nextPrice);
changes.Add(nextPrice - lastPrice);
lastPrice = nextPrice;
lastNum = nextNum;
}
// Use prices somehow...
}
}
A bit messy, but it works.
Now, a pattern matching thing. I could do a naieve approach and just search for each pattern, but it might make more sense to make a note of each pattern in each set instead.
private List<Dictionary<(int, int, int, int), int>> pricePatterns = new List<Dictionary<(int, int, int, int), int>>();
private void GeneratePatterns(List<int> changes, List<int> prices)
{
var patterns = new Dictionary<(int, int, int, int), int>();
for (int i = 0; i < changes.Count - 3; i++)
{
var pattern = (changes[i], changes[i + 1], changes[i + 2], changes[i + 3]);
if (!patterns.ContainsKey(pattern)) patterns[pattern] = prices[i + 3];
}
pricePatterns.Add(patterns);
}
That works exceedingly fast even on the full input. Now just to iterate through [-9,9)^4 = 130,321
possabilities. I can probably optimize that to not have impossible runs (like (-9, -9, -9, -9)
will never happen), but only if I need to.
private int GetReturns((int, int, int, int) pattern)
{
if (!PatternValid(pattern)) return 0;
int sum = 0;
foreach (var monkey in pricePatterns)
{
if (monkey.TryGetValue(pattern, out int price))
{
sum += price;
}
}
return sum;
}
private bool PatternValid((int, int, int, int) pattern)
{
var change = pattern.Item1;
change += pattern.Item2;
if (Math.Abs(change) > 9) return false;
change += pattern.Item3;
if (Math.Abs(change) > 9) return false;
change += pattern.Item4;
if (Math.Abs(change) > 9) return false;
return true;
}
It takes a while to run - just because it has a lot that it's checking - but it's still under 30 seconds.