float GetCost(int xpos, int ypos, byte life, sbyte invul, bool hasBonus) { CostMap cm = GetCostMap(life, invul, hasBonus); if (cm == null) { return(float.PositiveInfinity); } short xpix = Physics.pos_to_px(xpos); short ypix = Physics.pos_to_px(ypos); float cost = cm.CostAtPx(xpix, ypix, Flooding.GetRealInvul(life, invul)); float mult_cost = cost * Settings.cost_multiplier; return(cost > 0 && mult_cost <= 0 ? float.Epsilon : mult_cost); }
public void ComputeNewCostMaps() { ExtendedCostMap full_life_cost_map; if (!Settings.allow_wall_clip) { full_life_cost_map = f.ComputeExtendedCostMap(Flooding.WallClipSetting.NoWallClip, 0); } else if (Settings.full_life <= 1 && Settings.restrict_complete_wall_clip_when_one_heart) { full_life_cost_map = f.ComputeExtendedCostMap(Flooding.WallClipSetting.NoCompleteWallClip, 0); } else { full_life_cost_map = f.ComputeExtendedCostMap(Flooding.WallClipSetting.Allow, 0); } if (!Settings.allow_wall_clip || !Settings.restrict_complete_wall_clip_when_one_heart || Settings.full_life <= 1 || Settings.invul_frames < 0) { cost_maps = new ExtendedCostMap[1][]; cost_maps[0] = new ExtendedCostMap[] { full_life_cost_map }; } else { int total_op = 2 + Settings.nb_additional_cost_maps; parent.UpdateProgressBarAndHighlight(100 / total_op, null); cost_maps = new ExtendedCostMap[2][]; cost_maps[1] = new ExtendedCostMap[] { full_life_cost_map }; int current_op = 1; ExtendedCostMap[] cms = new ExtendedCostMap[Settings.nb_additional_cost_maps + 1]; for (int i = 0; i < cms.Length; i++) { int invul = i * (Settings.invul_frames + 1) / cms.Length; cms[i] = f.ComputeExtendedCostMap(Flooding.WallClipSetting.NoCompleteWallClip, Flooding.GetRealInvul(1, (sbyte)invul)); current_op++; parent.UpdateProgressBarAndHighlight(100 * current_op / total_op, null); } cost_maps[0] = cms; } }
public Action[] Solve(HelirinState init, int min_life_score) { if (cost_maps == null || init == null) { return(null); } SimplePriorityQueue <HelirinState> q = new SimplePriorityQueue <HelirinState>(); Dictionary <HelirinState, StateData> data = new Dictionary <HelirinState, StateData>(); Dictionary <HelirinState, int> life_data = null; if (!Settings.allow_state_visit_with_less_life && Settings.invul_frames >= 0 && Settings.full_life >= 2) { life_data = new Dictionary <HelirinState, int>(); } // Set range of possible inputs int min_input = 0; if (Settings.min_ab_speed == 1) { min_input = 1; } else if (Settings.min_ab_speed == 2) { min_input = 9; } else if (Settings.min_ab_speed == 3) { min_input = 17; } else if (Settings.min_ab_speed > 3) { min_input = 25; } // Init HelirinState norm_init = NormaliseState(init); float cost = GetCost(init.xpos, init.ypos, init.life, init.invul, init.HasBonus()); float weight = 0; float total_cost = cost + weight; q.Enqueue(norm_init, total_cost); data.Add(norm_init, new StateData(init, weight, cost, null, null, false)); if (life_data != null) { life_data.Add(ClearLifeDataOfState(norm_init), Flooding.GetRealInvul(init.life, init.invul)); } // ProgressBar and preview settings float init_cost = cost; bool[,] preview = new bool[cost_maps[0][0].Get(true).Height, cost_maps[0][0].Get(true).Width]; int since_last_update = 0; // A* HelirinState result = null; while (q.Count > 0 && result == null) { HelirinState norm_st = q.Dequeue(); StateData st_data = data[norm_st]; st_data.already_treated = true; weight = st_data.weight + 1; // ProgressBar and preview settings preview[Physics.pos_to_px(st_data.exact_state.ypos) - f.PixelStart.y, Physics.pos_to_px(st_data.exact_state.xpos) - f.PixelStart.x] = true; since_last_update++; if (since_last_update >= Settings.nb_iterations_before_ui_update) { since_last_update = 0; parent.UpdateProgressBarAndHighlight(100 - st_data.cost * 100 / init_cost, preview); } for (int i = 24; i >= min_input; i--) { Action a = (Action)i; HelirinState nst = p.Next(st_data.exact_state, a); HelirinState norm_nst = NormaliseState(nst); // Lose / Not enough life / Out of search space ? int life_score = Flooding.GetRealInvul(nst.life, nst.invul); if (nst.gs == GameState.Lose || (life_score < min_life_score && life_score >= 0) || IsOutOfSearchSpace(nst.xpos, nst.ypos)) { continue; } // Already enqueued with more life ? HelirinState cleared_nst = null; if (life_data != null) { cleared_nst = ClearLifeDataOfState(norm_nst); int old_life_score; life_data.TryGetValue(cleared_nst, out old_life_score); // Default value for 'old_life_score' (type int) is 0. if (old_life_score > life_score) { continue; } } // Already visited ? // If the state was already visited, we should not add it to the queue again! Otherwise it could overwrite the state entry and corrupt some paths. StateData old; data.TryGetValue(norm_nst, out old); // Default value for 'old' (type StateData) is null. if (old != null && old.already_treated) { continue; } // Keep only if it is a non-infinite better cost cost = GetCost(nst.xpos, nst.ypos, nst.life, nst.invul, nst.HasBonus()); if (cost >= float.PositiveInfinity) { continue; } total_cost = cost + weight; if (old != null && total_cost >= old.cost + old.weight) { continue; } // Is the state terminal without having completed the objective? if (cost > 0 && nst.IsTerminal()) { continue; } // Everything's okay, we add the config to the data and queue StateData nst_data = new StateData(nst, weight, cost, a, norm_st, false); data[norm_nst] = nst_data; if (life_data != null) { life_data[cleared_nst] = life_score; } // Target reached ? We look at the cost rather than the game state, because the target can be different than winning if (cost <= 0) { result = norm_nst; break; } // We don't use UpdatePriority because it does not change the InsertionIndex (first-in, first-out) if (old != null) { q.Remove(norm_nst); } q.Enqueue(norm_nst, total_cost); /* * if (old == null) * q.Enqueue(norm_nst, total_cost); * else * q.UpdatePriority(norm_nst, total_cost); */ } } // Retrieve full path if (result == null) { return(null); } List <Action> res = new List <Action>(); while (result != null) { StateData sd = data[result]; if (sd.action.HasValue) { res.Add(sd.action.Value); } result = sd.previous_state; } res.Reverse(); return(res.ToArray()); }
private void updateCostMapDisplay() { mapc.SetCostMap(b.GetCostMap((byte)cm_preview_l, (sbyte)invulCostMap.Value, !cm_preview_bonus), Flooding.GetRealInvul((byte)cm_preview_l, (sbyte)invulCostMap.Value)); }