private static void RecursiveSearch <Gb, M, T>(Gb[] gbs, DFParameters <Gb, M, T> parameters, DFState <M, T> state, HashSet <int> seenStates) where Gb : PokemonGame where M : Map <M, T> where T : Tile <M, T> { if (parameters.EndTiles != null && state.EdgeSet == parameters.EndEdgeSet && parameters.EndTiles.Any(t => t.X == state.Tile.X && t.Y == state.Tile.Y)) { if (parameters.FoundCallback != null) { parameters.FoundCallback(state); } } if (parameters.PruneAlreadySeenStates && !seenStates.Add(state.GetHashCode())) { return; } foreach (Edge <M, T> edge in state.Tile.Edges[state.EdgeSet]) { if (state.WastedFrames + edge.Cost > parameters.MaxCost) { continue; } if ((state.BlockedActions & edge.Action) > 0) { continue; } if (edge.Action == Action.A && state.APressCounter > 0) { continue; } IGTResults results = PokemonGame.IGTCheckParallel <Gb>(gbs, state.IGT, gb => gb.Execute(edge.Action) == gb.OverworldLoopAddress, parameters.NoEncounterSS); DFState <M, T> newState = new DFState <M, T>() { Tile = edge.NextTile, EdgeSet = edge.NextEdgeset, Log = state.Log + edge.Action.LogString() + " ", IGT = results, WastedFrames = state.WastedFrames + edge.Cost, }; int noEncounterSuccesses = results.TotalSuccesses; if (noEncounterSuccesses >= parameters.NoEncounterSS) { int rngSuccesses = results.RNGSuccesses(0x9); if (rngSuccesses >= parameters.RNGSS) { newState.APressCounter = edge.Action == Action.A ? 2 : Math.Max(state.APressCounter - 1, 0); Action blockedActions = state.BlockedActions; if ((edge.Action & Action.A) > 0) { blockedActions |= Action.A; } else { blockedActions &= ~(Action.A | Action.StartB); } newState.BlockedActions = blockedActions; RecursiveSearch(gbs, parameters, newState, seenStates); } } } }
private static void RecursiveSearch <Gb, T>(Gb[] gbs, DFParameters <Gb, T> parameters, DFState <T> state, HashSet <int> seenStates) where Gb : GameBoy where T : Tile <T> { if (parameters.EndTiles != null && state.EdgeSet == parameters.EndEdgeSet && parameters.EndTiles.Any(t => t.X == state.Tile.X && t.Y == state.Tile.Y)) { if (parameters.FoundCallback != null) { parameters.FoundCallback(state); } else { Console.WriteLine(state.Log); } } if (parameters.PruneAlreadySeenStates && !seenStates.Add(state.GetHashCode())) { return; } byte[][] states = state.IGT.States; foreach (Edge <T> edge in state.Tile.Edges[state.EdgeSet]) { if (state.WastedFrames + edge.Cost > parameters.MaxCost) { continue; } if ((state.BlockedActions & edge.Action) > 0) { continue; } IGTResults results = GameBoy.IGTCheckParallel <Gb>(gbs, states, gb => gb.Execute(edge.Action) == gb.OverworldLoopAddress, parameters.EncounterCallback == null ? parameters.NoEncounterSS : 0); DFState <T> newState = new DFState <T>() { Tile = edge.NextTile, EdgeSet = edge.NextEdgeset, Log = state.Log + edge.Action.LogString() + " ", IGT = results, WastedFrames = state.WastedFrames + edge.Cost, }; int noEncounterSuccesses = results.TotalSuccesses; if (parameters.EncounterCallback != null) { int encounterSuccesses = results.TotalFailures; for (int i = 0; i < results.NumIGTFrames && encounterSuccesses >= parameters.EncounterSS; i++) { gbs[0].LoadState(results.States[i]); if (parameters.EncounterCallback(gbs[0])) { encounterSuccesses++; } } if (encounterSuccesses >= parameters.EncounterSS) { if (parameters.FoundCallback != null) { parameters.FoundCallback(newState); } else { Console.WriteLine(state.Log); } } } if (noEncounterSuccesses >= parameters.NoEncounterSS) { Action blockedActions = state.BlockedActions; if (edge.Action == Action.A) { blockedActions |= Action.StartB; } if ((edge.Action & Action.A) > 0) { blockedActions |= Action.A; } else { blockedActions &= ~(Action.A | Action.StartB); } newState.BlockedActions = blockedActions; RecursiveSearch(gbs, parameters, newState, seenStates); } } }