@@ -315,10 +315,66 @@ void sort(
315315 }
316316}
317317
318+ // Read current screen to find occupied and empty slots in the box.
319+ // Add a placeholder value for each slot in order into `boxes_data`. For empty slot the value is just std::nullopt, while
320+ // for the occupied slot it is an empty pokemon struct `CollectedPokemonInfo`.
321+ // Return the (row, col) index of the first pokemon (aka non-empty) slot in the box.
322+ std::array<size_t , 2 > find_occupied_slots_in_box (
323+ SingleSwitchProgramEnvironment& env,
324+ ProControllerContext& context,
325+ std::vector<std::optional<CollectedPokemonInfo>>& boxes_data,
326+ const std::vector<SortingRule>& sort_preferences)
327+ {
328+ BoxSorter_Descriptor::Stats& stats = env.current_stats < BoxSorter_Descriptor::Stats>();
329+
330+ VideoSnapshot screen = env.console .video ().snapshot ();
331+
332+ std::ostringstream ss;
333+ ss << " \n " ;
334+
335+ std::array<size_t , 2 > first_pokemon_slot = {SIZE_MAX, SIZE_MAX};
336+
337+ int num_empty_slots = 0 ;
338+ for (size_t row = 0 ; row < BOX_ROWS; row++){
339+ for (size_t col = 0 ; col < BOX_COLS; col++){
340+ ImageFloatBox slot_box (0.06 + (0.072 * col), 0.2 + (0.1035 * row), 0.03 , 0.057 );
341+ int current_box_value = (int )image_stddev (extract_box_reference (screen, slot_box)).sum ();
342+
343+ ss << current_box_value;
344+
345+ // checking color to know if a pokemon is on the slot or not
346+ if (current_box_value < 10 ){
347+ stats.empty ++;
348+ num_empty_slots++;
349+ boxes_data.push_back (std::nullopt ); // empty optional to make sorting easier later
350+ ss << " \u274c " ; // "X"
351+ }else {
352+ if (first_pokemon_slot[0 ] == SIZE_MAX){
353+ first_pokemon_slot = {row, col};
354+ }
355+ stats.pkmn ++;
356+ boxes_data.push_back (
357+ CollectedPokemonInfo{
358+ .preferences = &sort_preferences
359+ }
360+ ); // default initialised pokemon to know there is a pokemon here that needs a value
361+ ss << " \u2705 " ; // checkbox
362+ }
363+ }
364+ ss << " \n " ;
365+ }
366+
367+ env.update_stats ();
368+ env.log (ss.str ());
369+ env.add_overlay_log (" Empty: " + std::to_string (num_empty_slots) + " /30" );
370+
371+ return first_pokemon_slot;
372+ }
373+
318374void BoxSorter::program (SingleSwitchProgramEnvironment& env, ProControllerContext& context){
319375 StartProgramChecks::check_performance_class_wired_or_wireless (context);
320376
321- std::vector<SortingRule> sort_preferences = SORT_TABLE.preferences ();
377+ const std::vector<SortingRule> sort_preferences = SORT_TABLE.preferences ();
322378 if (sort_preferences.empty ()){
323379 throw UserSetupError (env.console , " At least one sorting method selection needs to be made!" );
324380 }
@@ -398,8 +454,10 @@ void BoxSorter::program(SingleSwitchProgramEnvironment& env, ProControllerContex
398454 }else {
399455 // Moving the cursor until it goes to the first slot
400456 if (!go_to_first_slot (env, context, VIDEO_DELAY)){
401- env.console .log (" ERROR: Could not move cursor to the first slot, please consider adjusting delay\n " , COLOR_RED);
402- return ;
457+ throw UserSetupError (
458+ env.logger (),
459+ " ERROR: Could not move cursor to the first slot, please consider adjusting delay."
460+ );
403461 }
404462 }
405463
@@ -408,59 +466,17 @@ void BoxSorter::program(SingleSwitchProgramEnvironment& env, ProControllerContex
408466 env.log (log_msg);
409467 env.console .overlay ().add_log (log_msg);
410468
411- screen = env.console .video ().snapshot ();
412-
413- // Box grid to find empty slots (red boxes) and fill boxes_data with value to check or not for pokemon dex number
414-
415- ss << " \n " ;
416469
417- std::array<size_t , 2 > first_poke_slot = {0 , 0 };
418- bool find_first_poke = false ;
419-
420- int num_empty_slots = 0 ;
421- for (size_t row = 0 ; row < BOX_ROWS; row++){
422- for (size_t column = 0 ; column < BOX_COLS; column++){
423- ImageFloatBox slot_box (0.06 + (0.072 * column), 0.2 + (0.1035 * row), 0.03 , 0.057 );
424- int current_box_value = (int )image_stddev (extract_box_reference (screen, slot_box)).sum ();
425-
426- ss << current_box_value;
427-
428- // checking color to know if a pokemon is on the slot or not
429- if (current_box_value < 10 ){
430- box_render.add (COLOR_RED, slot_box);
431- stats.empty ++;
432- num_empty_slots++;
433- env.update_stats ();
434- boxes_data.push_back (std::nullopt ); // empty optional to make sorting easier later
435- ss << " \u274c " ; // "X"
436- }else {
437- if (find_first_poke == false ){
438- first_poke_slot = {column, row};
439- find_first_poke = true ;
440- }
441- box_render.add (COLOR_GREEN, slot_box);
442- stats.pkmn ++;
443- env.update_stats ();
444- boxes_data.push_back (
445- CollectedPokemonInfo{
446- .preferences = &sort_preferences
447- }
448- ); // default initialised pokemon to know there is a pokemon here that needs a value
449- ss << " \u2705 " ; // checkbox
450- }
451- }
452- ss << " \n " ;
453- }
454- env.console .log (ss.str ());
455- env.add_overlay_log (" Empty: " + std::to_string (num_empty_slots) + " /30" );
470+ // Check box grid color stddev to find occupied slots and fill boxes_data with placeholder pokemon info.
471+ const std::array<size_t , 2 > first_pokemon_slot = find_occupied_slots_in_box (env, context, boxes_data, sort_preferences);
456472 ss.str (" " );
457473
458- // moving cursor to the first pokemon slot
459- dest_cursor = {0 , first_poke_slot[1 ], first_poke_slot[0 ]};
460- nav_cursor = move_cursor_to (env, context, nav_cursor, dest_cursor, GAME_DELAY);
461-
462474 // enter the summary screen to read pokemon info
463- if (find_first_poke){
475+ if (first_pokemon_slot[0 ] != SIZE_MAX){
476+ // moving cursor to the first pokemon slot
477+ dest_cursor = {0 , first_pokemon_slot[0 ], first_pokemon_slot[1 ]};
478+ nav_cursor = move_cursor_to (env, context, nav_cursor, dest_cursor, GAME_DELAY);
479+
464480 env.add_overlay_log (" Checking Summary..." );
465481
466482 pbf_press_button (context, BUTTON_A, 10 , GAME_DELAY);
0 commit comments