public static void solveTapa(int solve_limit = -1) { is_over_solve_num = false; int process_limit = 3; while (true) { Tapa.was_change_board = false; // 数字マス周りのパターンを管理 PatternAroundNumBox.managePatternAroundNumBox(process_limit, solve_limit); if (Tapa.is_over_solve_num) { break; } // 伸び代のある黒マスから、黒マスが伸びないかを見て、可能なら実際に伸ばす。 Box.manageBlackBox(solve_limit); if (Tapa.is_over_solve_num) { break; } if (!was_change_board) { if (process_limit == 3) { if (Tapa.is_fast) { return; } // 高速モードなら手法の制限解除を行わない process_limit = 4; continue; // 解法を制限して回答が進まなければ制限解除 } return; // 解法の制限をなくしても問題が解けない or 回答終了 の場合終わり } if (process_limit == 4) { process_limit = 3; } // 解法の制限を解除して解が進んだ場合、改めて解法を制限する } }
/********************************* * * 未定マスを試し塗りしてバックトラックを行う * バックトラックの結果が一度でも正しければtrueを返す * 引数 * depth : バックトラックの深さ * * *******************************/ private bool doBackTrack(int depth) { StateSave save_point = new StateSave(); StateSave.saveNowState(save_point); bool ret_bool = false; // true:(途中)盤面が正しい // 深さをインクリメント depth++; // 黒マスと接している未定マスのリストを作成 List <Coordinates> adjacent_notdeployedbox_coord_list = new List <Coordinates>(); // 黒マスと接している未定マスがある時 foreach (Coordinates tmp_ndbox_coord in Tapa.not_deployedbox_coord_list) { if (Box.existBlackBoxAround(tmp_ndbox_coord)) { adjacent_notdeployedbox_coord_list.Add(tmp_ndbox_coord); } } // 未定マスはあるが、黒マスと接している未定マスがない時 if (adjacent_notdeployedbox_coord_list.Count == 0 && Tapa.not_deployedbox_coord_list.Count > 0) { foreach (Coordinates tmp_ndbox_coord in Tapa.not_deployedbox_coord_list) { adjacent_notdeployedbox_coord_list.Add(new Coordinates(tmp_ndbox_coord)); } } // 注目している未定マス領域に未定マスがただ1つ存在する時の処理 if (adjacent_notdeployedbox_coord_list.Count == 1) { for (int i = 0; i < 2; i++) { Coordinates tmp_ndbox_coord = adjacent_notdeployedbox_coord_list[0]; Tapa.box[tmp_ndbox_coord.x][tmp_ndbox_coord.y].Color = (i == 0) ? Box.BLACK : Box.WHITE; // 変化がなくなるまで処理を行う do { Tapa.was_change_board = false; PatternAroundNumBox.managePatternAroundNumBox(); Box.manageBlackBox(); } while (Tapa.was_change_board); // 処理中の未定マス群から色のついたマスを除外したリストを作成 List <Coordinates> arg_list = new List <Coordinates>(Tapa.not_deployedbox_coord_list); for (int j = arg_list.Count - 1; j >= 0; j--) { if (Tapa.box[arg_list[j].x][arg_list[j].y].Color != Box.NOCOLOR) { arg_list.RemoveAt(j); } } // 未定マスが存在すれば再起する if (arg_list.Count > 0) { ret_bool = ret_bool || doBackTrack(depth); } else // 未定マスが存在しない { if (Box.checkNotIsolationBlackBoxGroup() || Tapa.isCorrectAnswer()) // 盤面の一繋がりの黒マス群が孤立していないか { StateSave.saveNowState(BackTrack.correct_save_point); // 正しければ現在の盤面を保存 if (depth < min_depth) // 先読みした深さ(のうち小さい方)を記録 { min_depth = depth; tmp_ndbox_coord.printCoordinates(); Console.WriteLine(":min_depth >> " + min_depth); } ret_bool = true; } } // 元の状態に戻す StateSave.loadSavedState(save_point); // 黒マスで塗ったら正解の盤面が生成できなかった場合 if (!ret_bool) { // 未定マスの色を白にする Tapa.box[tmp_ndbox_coord.x][tmp_ndbox_coord.y].Color = Box.WHITE; StateSave.saveNowState(save_point); } } return(ret_bool); } // 注目している未定マス領域に未定マスが複数存在する時の処理 // 未定マスをたどる for (int i = 0; i < adjacent_notdeployedbox_coord_list.Count; i++) { Coordinates tmp_ndbox_coord = adjacent_notdeployedbox_coord_list[i]; // 未定マスの色を黒にする Tapa.box[tmp_ndbox_coord.x][tmp_ndbox_coord.y].Color = Box.BLACK; // 変化がなくなるまで処理を行う do { Tapa.was_change_board = false; PatternAroundNumBox.managePatternAroundNumBox(); Box.manageBlackBox(); } while (Tapa.was_change_board); // 処理中の未定マス群から色のついたマスを除外したリストを作成 List <Coordinates> arg_list = new List <Coordinates>(Tapa.not_deployedbox_coord_list); for (int j = arg_list.Count - 1; j >= 0; j--) { if (Tapa.box[arg_list[j].x][arg_list[j].y].Color != Box.NOCOLOR) { arg_list.RemoveAt(j); } } // 処理中の未定マス群に未定マスが残っていれば再起する if (arg_list.Count > 0) { ret_bool = ret_bool || doBackTrack(depth); } else // 処理中の未定マス群に未定マスが存在しない // 盤面に一繋がりの黒マス群が孤立していない or 盤面が正解 { if (Box.checkNotIsolationBlackBoxGroup() || Tapa.isCorrectAnswer()) { StateSave.saveNowState(BackTrack.correct_save_point); // 正しければ現在の盤面を保存 if (depth < min_depth) // 先読みした深さ(のうち小さい方)を記録 { min_depth = depth; tmp_ndbox_coord.printCoordinates(); Console.WriteLine(":min_depth >> " + min_depth); } ret_bool = true; } } // 元の状態に戻す StateSave.loadSavedState(save_point); // 黒マスで塗ったら正解の盤面が生成できなかった場合 if (!ret_bool) { // 未定マスの色を白にする Tapa.box[tmp_ndbox_coord.x][tmp_ndbox_coord.y].Color = Box.WHITE; StateSave.saveNowState(save_point); } } return(ret_bool); }