public void SpellOptimizerTest() { var allSpells = GetAllSpells().ToList(); var baseSpell = ImmutableStack <Spell> .Instance .Push(allSpells[0]) .Push(allSpells[1]) .Push(allSpells[2]) .Push(allSpells[3]); var spellsForLearn = new List <Spell>() { allSpells[15], allSpells[27], allSpells[31], allSpells[9], allSpells[7], allSpells[11], }; var tomeSpells = spellsForLearn.Select((x, i) => new Learn(x.Id, 0, x.Tiers, i)) .ToList(); var orders = new List <Order> { OrderReceipts[2], OrderReceipts[7], OrderReceipts[22], OrderReceipts[31], OrderReceipts[13], }; var sw = Stopwatch.StartNew(); var spellOptimizer = new SpellOptimizer(); var mapForLearn = spellOptimizer.GetSpellMapForLearn(orders, tomeSpells, baseSpell, sw); foreach (var item in mapForLearn) { var sb = new StringBuilder(); sb.Append($"points: {item.TotalRupies}, length: {item.TotalLength}, maxDeep: {item.MaxDeep} | "); foreach (var i in item.LearnOrder) { sb.Append($" -> {i}"); } Console.WriteLine(sb); } Console.WriteLine("Optimal path for second set."); var t = mapForLearn[1]; for (var i = 0; i < orders.Count; i++) { Console.WriteLine($"Recipes for order {i}"); foreach (var recipes in t.OptimalRecipes[i]) { Console.WriteLine($"\t{recipes}"); } } }
public void BugTest() { var allSpells = GetAllSpells().ToList(); var baseSpell = ImmutableStack <Spell> .Instance .Push(allSpells[0]) .Push(allSpells[1]) .Push(allSpells[2]) .Push(allSpells[3]); var tomeSpells = new List <Learn> { new Learn(244, 0, (-2, 0, -1, 2), 0), new Learn(245, 0, (-3, 0, 0, 1), 1), new Learn(246, 0, (-4, 0, 2, 0), 2), new Learn(247, 0, (3, -2, 1, 0), 3), new Learn(248, 0, (0, -3, 3, 0), 4), new Learn(249, 0, (0, 0, -3, 3), 5), }; var orders = new List <Order> { OrderReceipts[22], OrderReceipts[29], OrderReceipts[10], OrderReceipts[15], OrderReceipts[3], }; var spellOptimizer = new SpellOptimizer(); var sw = Stopwatch.StartNew(); var learnMap = spellOptimizer.GetSpellMapForLearn(orders, tomeSpells, baseSpell, sw); var spells = baseSpell; var learnRes = Player.TryGetLearnAction(learnMap, tomeSpells, spells, 3, new HashSet <int>()); spells = spells.Push(new Spell(147, ((Learn)learnRes.action).Spell, true, 1)); tomeSpells = tomeSpells.Where(x => x.Id != ((Learn)learnRes.action).Id).ToList(); var learnRes2 = Player.TryGetLearnAction(learnMap, tomeSpells, spells, 3, new HashSet <int>()); spells = spells.Push(new Spell(741, ((Learn)learnRes2.action).Spell, true, 1)); tomeSpells = tomeSpells.Where(x => x.Id != ((Learn)learnRes2.action).Id).ToList(); var learnRes3 = Player.TryGetLearnAction(learnMap, tomeSpells, spells, 3, new HashSet <int>()); }
static void Main(string[] args) { GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; //LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; string[] inputs; var turnNumber = -1; List <SpellMap> learnMap = null; SpellMap bestSpellMap = null; var useGreedy = true; GreedyResolver greedyResolver = null; Path previousActions = Path.Instance; int? greadyOrderTurn = null; int finishedOrdersCnt = 0; var usedOrders = new HashSet <int>(); var sw = new Stopwatch(); // game loop while (true) { turnNumber++; int actionCount = int.Parse(Console.ReadLine()); // the number of spells and recipes in play sw.Restart(); var orders = new List <Order>(); var spells = ImmutableStack <Spell> .Instance; var learns = new List <Learn>(); var usedSpells = new HashSet <int>(); for (int i = 0; i < actionCount; i++) { inputs = Console.ReadLine().Split(' '); int actionId = int.Parse(inputs[0]); // the unique ID of this spell or recipe string actionType = inputs[1]; // in the first league: BREW; later: CAST, OPPONENT_CAST, LEARN, BREW int delta0 = int.Parse(inputs[2]); // tier-0 ingredient change int delta1 = int.Parse(inputs[3]); // tier-1 ingredient change int delta2 = int.Parse(inputs[4]); // tier-2 ingredient change int delta3 = int.Parse(inputs[5]); // tier-3 ingredient change byte price = byte.Parse(inputs[6]); // the price in rupees if this is a potion int tomeIndex = int.Parse(inputs[7]); // in the first two leagues: always 0; later: the index in the tome if this is a tome spell, equal to the read-ahead tax int taxCount = int.Parse(inputs[8]); // in the first two leagues: always 0; later: the amount of taxed tier-0 ingredients you gain from learning this spell bool castable = inputs[9] != "0"; // in the first league: always 0; later: 1 if this is a castable player spell bool repeatable = inputs[10] != "0"; // for the first two leagues: always 0; later: 1 if this is a repeatable player spell if (actionType == "BREW") { orders.Add(new Order(actionId, (delta0, delta1, delta2, delta3), price)); } if (actionType == "CAST") { spells = spells.Push(new Spell(actionId, (delta0, delta1, delta2, delta3), repeatable, 1)); if (!castable) { usedSpells.Add(actionId); } } if (actionType == "LEARN") { learns.Add(new Learn(actionId, taxCount, (delta0, delta1, delta2, delta3), tomeIndex)); } } //Console.Error.WriteLine($"Orders cnt: {orders.Count}"); var needRest = usedSpells.Any(); StateRes res = null; for (int i = 0; i < 2; i++) { inputs = Console.ReadLine().Split(' '); int inv0 = int.Parse(inputs[0]); // tier-0 ingredients in inventory int inv1 = int.Parse(inputs[1]); int inv2 = int.Parse(inputs[2]); int inv3 = int.Parse(inputs[3]); byte score = byte.Parse(inputs[4]); // amount of rupees if (i == 0) { res = new StateRes((inv0, inv1, inv2, inv3), score); } } var currentState = new GameState ( res, spells, orders, learns, usedOrders, usedSpells, new HashSet <int>(), Path.Instance, needRest ); // Write an action using Console.WriteLine() // To debug: Console.Error.WriteLine("Debug messages..."); if (turnNumber == 0) { var learnTime = new Stopwatch(); learnTime.Restart(); var spellOptimizer = new SpellOptimizer(); learnMap = spellOptimizer.GetSpellMapForLearn(orders, learns, spells, sw); Console.Error.WriteLine($"Learn time: {learnTime.ElapsedMilliseconds:F1}"); } if (bestSpellMap == null) { var learnRes = TryGetLearnAction(learnMap, learns, spells, currentState.StateRes.Inventary[0], currentState.UsedSpells); bestSpellMap = learnRes.spellMap; if (learnRes.action != null) { var q = new StringBuilder(); q.Append(learnRes.action.Print()); if (bestSpellMap != null) { greedyResolver = new GreedyResolver(bestSpellMap); q.Append($" I AM READY! D{bestSpellMap.MaxDeep}"); var dbg = new StringBuilder(); foreach (var idx in bestSpellMap.LearnOrder) { dbg.Append($" {idx}"); } Console.Error.WriteLine(dbg); } else { q.Append(" I SHOULD BE SMARTER!"); } Console.WriteLine(q.ToString()); continue; } } if (useGreedy && greedyResolver != null) { var decision = greedyResolver.Resolve(currentState, previousActions, finishedOrdersCnt); finishedOrdersCnt = decision.finishedOrders; previousActions = decision.previousActions; var greedyAction = decision.nextAction; if (greedyAction != null) { if (greedyAction is Order) { usedOrders.Add(((Order)greedyAction).Id); greadyOrderTurn = turnNumber; } Console.WriteLine($"{greedyAction.Print()} I AM GREEDY!"); continue; } if (greadyOrderTurn == turnNumber - 1) { Console.WriteLine($"{new Rest().Print()} I AM GREEDY!"); continue; } } var action = new Resolver(debug, 35).Resolve(currentState, sw); if (action.StartsWith("BREW")) { var num = int.Parse(action.Split(' ')[1]); usedOrders.Add(num); } Console.WriteLine(action); // in the first league: BREW <id> | WAIT; later: BREW <id> | CAST <id> [<times>] | LEARN <id> | REST | WAIT } }