public StateSave(StateSave origin_state) { // 引数の盤面の全てのマス this.saved_box = new Box[Tapa.MAX_BOARD_ROW + 2][]; for (int i = 0; i < Tapa.MAX_BOARD_ROW + 2; i++) { this.saved_box[i] = new Box[Tapa.MAX_BOARD_COL + 2]; for (int j = 0; j < Tapa.MAX_BOARD_COL + 2; j++) { this.saved_box[i][j] = new Box(origin_state.saved_box[i][j]); } } // 引数の数字マスの座標のリスト this.saved_numbox_coord_list = StateSave.getStateCoordList(origin_state.saved_numbox_coord_list); // 引数の未定マスの座標リスト this.saved_not_deployedbox_coord_list = StateSave.getStateCoordList(origin_state.saved_not_deployedbox_coord_list); // 引数の伸び代のある黒マスの座標リスト this.saved_edge_blackbox_coord_list = StateSave.getStateCoordList(origin_state.saved_edge_blackbox_coord_list); // 引数の一繋がりの黒マス群の座標リスト this.saved_isolation_blackboxes_group_list = StateSave.getStateMultiCoordList(origin_state.saved_isolation_blackboxes_group_list); // 引数の一繋がりの未定マス群の座標リスト //this.saved_isolation_notdeployedboxes_group_list // = StateSave.getStateMultiCoordList(origin_state.saved_isolation_notdeployedboxes_group_list); // 引数の盤面が変更されたかの情報 this.saved_was_changed_board = origin_state.saved_was_changed_board; }
/********************************* * * 未定マスを試し塗りしてバックトラックを行う * バックトラックの結果が一度でも正しければ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; }
/********************************* * * 切断点のみの団子マスに接している黒マス群のうち * 最も短い黒マス群とそれに接している切断点を削除する * * *******************************/ private static void removeCutDumpling() { // 団子マス4つの保存用 List <Coordinates> dump_coord; // 団子マスの座標を取得、団子マスがなければ終わり while ((dump_coord = Box.getDumpCoord()) != null) { // 切断点に接している切断点以外の黒マス保存用 // Key : 切断点に接している黒マス // Value : 切断点 Dictionary <Coordinates, Coordinates> adj_dict = new Dictionary <Coordinates, Coordinates>(); foreach (Coordinates co in dump_coord) { // 切断点が接している黒マス座標を取得 List <Coordinates> tmp_adj_coord = Box.getWhatColorBoxCoordListAround(co, Box.BLACK); // 接している黒マスのうち切断点の情報を除外 foreach (Coordinates tmp_co in dump_coord) { tmp_adj_coord.Remove(tmp_co); } adj_dict[tmp_adj_coord[0]] = co; } // 盤面編集用 StateSave edit = new StateSave(); StateSave.saveNowState(edit); // 盤面editの団子マスdump_coordを未定マスにする foreach (Coordinates co in dump_coord) { edit.saved_box[co.x][co.y].revision_color = Box.NOCOLOR; } // edit盤面を生成 // (一繋がりの黒マス群が複数生成される) StateSave.makeEditBoard(edit); // 黒マス群リストのうち、最少の黒マス群の参照を取得 List <Coordinates> min_bblist = Box.getMinIsoBlackBoxListRef(); // 切断点の黒マスの団子を黒く塗る foreach (Coordinates co in dump_coord) { edit.saved_box[co.x][co.y].revision_color = Box.BLACK; } // min_bblistとそれに接している切断点を未定マスにする foreach (Coordinates co in min_bblist) { edit.saved_box[co.x][co.y].revision_color = Box.NOCOLOR; if (!adj_dict.ContainsKey(co)) { continue; } edit.saved_box[adj_dict[co].x][adj_dict[co].y].revision_color = Box.NOCOLOR; } // edit盤面を生成 // (団子マスを1つ除外できた盤面) StateSave.makeEditBoard(edit); } }
/********************************* * * 数字マスを削除して問題生成する。 * 引数: * boxnumber_in_whitebox_coord_dict : 数字マスの座標と数字の対応 * * *******************************/ private void generateTapaProblemInDeleteNumBox() { if (Tapa.DEBUG) { Console.WriteLine("ソート前"); Tapa.printCoordList(Problem.can_be_number_whitebox_list); } // 【削除する数字マスを選ぶ順番】 // ヒント数で降順にソート[固定] のみ //////// ヒント数が同数だったらidの数で昇順にソートしたデータを後ろから選ぶ Tapa.numbox_coord_list.Sort( delegate(Coordinates co1, Coordinates co2) { int hint1 = Tapa.box[co1.x][co1.y].min_hint; int hint2 = Tapa.box[co2.x][co2.y].min_hint; if (hint1 < hint2) { return 1; } else if (hint1 > hint2) { return -1; } else { return 0; //int num1 = Tapa.box[co1.x][co1.y].id_list.Count; //int num2 = Tapa.box[co2.x][co2.y].id_list.Count; //if (num1 < num2) { return -1; } //else if (num1 > num2) { return 1; } //else return 0; } }); // 未削除の数字マスリストを現在残っている数字マスリストで更新 Problem.can_be_number_whitebox_list = new List<Coordinates>(Tapa.numbox_coord_list); if (Tapa.DEBUG) { Console.WriteLine("ソート後"); Tapa.printCoordList(Problem.can_be_number_whitebox_list); } // 削除対象のリストを後ろからチェック for (int i = Problem.can_be_number_whitebox_list.Count - 1; i >= 0; i--) { // 時間計測開始 System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); // 現在の状態を保存 StateSave save_point = new StateSave(); StateSave.saveNowState(save_point); // 削除判定の行われていない数字マスの内、 // [最少ヒント数で降順][パターン数で昇順]でソートしたリストの後ろから順に数字マスを選ぶ Coordinates deleting_numbox_coord = Problem.can_be_number_whitebox_list[i]; // 選択された数字マスを、未削除の数字マス座標リストから除外する。 Problem.can_be_number_whitebox_list.Remove(deleting_numbox_coord); Box deleting_box = Tapa.box[deleting_numbox_coord.x][deleting_numbox_coord.y]; // 浅いコピー // 選択した数字マスを未定マスにする deleting_box.revision_color = Box.NOCOLOR; // 選択した座標を未定マスにする deleting_box.hasNum = false; // 数字を持ってるフラグをオフにする Tapa.numbox_coord_list.Remove(deleting_numbox_coord); // 数字マスリストから除外 Tapa.not_deployedbox_coord_list.Add(new Coordinates(deleting_numbox_coord)); // 未定マスリストに追加 // 問題を解く Tapa.solveTapa(); // 解ならば復元後に、選択した数字マスをそのまま未定マスにする。 if (Tapa.isCorrectAnswer()) { StateSave.loadSavedState(save_point); // 選択した数字マスを未定マスにする Tapa.box[deleting_numbox_coord.x][deleting_numbox_coord.y].revision_color = Box.NOCOLOR; // 選択した座標を未定マスにする Tapa.box[deleting_numbox_coord.x][deleting_numbox_coord.y].hasNum = false; // 数字を持ってるフラグをオフにする Tapa.numbox_coord_list.Remove(deleting_numbox_coord); // 数字マスリストから除外 Tapa.not_deployedbox_coord_list.Add(new Coordinates(deleting_numbox_coord)); // 未定マスリストに追加 } else { // 解でないなら、盤面を復元するのみ。 StateSave.loadSavedState(save_point); } //時間計測終了 sw.Stop(); deleting_numbox_coord.printCoordinates(); Console.WriteLine("del >> " + sw.Elapsed + "(" + Problem.can_be_number_whitebox_list.Count + ")"); } }
/********************************* * * 盤面の間違っている箇所を未定マスにする. * * 引数 * partway : 途中盤面を保存したもの * result : 解答 * * *******************************/ private static void modifyMistakeBoard(StateSave partway, StateSave result) { // 数字マスの座標と数値のハッシュを作成 Dictionary<Coordinates, int> num_dict = new Dictionary<Coordinates, int>(); foreach (Coordinates num in Tapa.numbox_coord_list) { num_dict[num] = Tapa.box[num.x][num.y].boxNum; } // 盤面の初期化 Tapa.resetBoard(); // 数字マスの設置 Problem.setNumBoxInBoard(num_dict); // 回答途中の盤面のうち,正しいマスのみを残す for (int i = 1; i <= Tapa.MAX_BOARD_ROW; i++) { for (int j = 1; j <= Tapa.MAX_BOARD_COL; j++) { Box r = result.saved_box[i][j]; Box p = partway.saved_box[i][j]; if (p.Color == Box.NOCOLOR || p.Color != r.Color) { continue; } else { Tapa.box[i][j].Color = p.Color; } } } }
/********************************* * * 盤面の初期状態から始めて問題を解けるか判断する. * * True:解ける * * 引数 * partway : 途中盤面を保存したもの * result : 解答保存用 * * *******************************/ private static bool judgeCanSolveInitialBoard(StateSave partway, StateSave result) { // 数字マスの座標と数値のハッシュを作成 Dictionary<Coordinates, int> num_dict = new Dictionary<Coordinates, int>(); foreach (Coordinates num in Tapa.numbox_coord_list) { num_dict[num] = Tapa.box[num.x][num.y].boxNum; } // 盤面の初期化 Tapa.resetBoard(); // 数字マスの設置 Problem.setNumBoxInBoard(num_dict); // 回答する Tapa.solveTapa(); StateSave.saveNowState(result); if (Tapa.isCorrectAnswer()) { StateSave.loadSavedState(partway); return true; } StateSave.loadSavedState(partway); return false; }
/********************************* * * 盤面の埋め方が正しいか判断する * * true : 正しい * * 引数 * partway : 途中盤面 * * *******************************/ private static bool isCorrectMiddleBoard(StateSave partway) { Tapa.solveTapa(); if (Tapa.isCorrectAnswer()) { StateSave.loadSavedState(partway); return true; } StateSave.loadSavedState(partway); return false; }
/********************************* * * txtからヒントを生成 * * *******************************/ public static bool manageMakingHintFromTxt() { Problem p = new Problem(); p.readPartwayTapaTxt(Problem.prb_hintfile_path); StateSave partway = new StateSave(); StateSave result = new StateSave(); // 入力盤面の保存 StateSave.saveNowState(partway); // 初期盤面を解けないとき,途中まででも出力. if (!Problem.judgeCanSolveInitialBoard(partway, result)) { StateSave.loadSavedState(result); generateTapaHintText(Problem.ans_hintfile_path); return false; } // 途中盤面が正しい場合,ヒントを与える. if (Problem.isCorrectMiddleBoard(partway)) { Tapa.solveTapa(Tapa.not_deployedbox_coord_list.Count - calcHintNum()); } // そうでない場合,間違った箇所を未定マスにする. else { Problem.modifyMistakeBoard(partway, result); } // ans_hintfile_path = @"C:\Users\Amano\OneDrive\zemi\ans_tapa.txt"; // ヒントtxtはexeファイルと同じディレクトリ generateTapaHintText(Problem.ans_hintfile_path); return true; }
/********************************* * * 未定マスを試し塗りしてバックトラックを行う * バックトラックの結果が一度でも正しければ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); }
/********************************* * * 数字マスを削除して問題生成する。 * 引数: * boxnumber_in_whitebox_coord_dict : 数字マスの座標と数字の対応 * * *******************************/ private void generateTapaProblemInDeleteNumBox() { if (Tapa.DEBUG) { Console.WriteLine("ソート前"); Tapa.printCoordList(Problem.can_be_number_whitebox_list); } // 【削除する数字マスを選ぶ順番】 // ヒント数で降順にソート[固定] のみ //////// ヒント数が同数だったらidの数で昇順にソートしたデータを後ろから選ぶ Tapa.numbox_coord_list.Sort( delegate(Coordinates co1, Coordinates co2) { int hint1 = Tapa.box[co1.x][co1.y].min_hint; int hint2 = Tapa.box[co2.x][co2.y].min_hint; if (hint1 < hint2) { return(1); } else if (hint1 > hint2) { return(-1); } else { return(0); //int num1 = Tapa.box[co1.x][co1.y].id_list.Count; //int num2 = Tapa.box[co2.x][co2.y].id_list.Count; //if (num1 < num2) { return -1; } //else if (num1 > num2) { return 1; } //else return 0; } }); // 未削除の数字マスリストを現在残っている数字マスリストで更新 Problem.can_be_number_whitebox_list = new List <Coordinates>(Tapa.numbox_coord_list); if (Tapa.DEBUG) { Console.WriteLine("ソート後"); Tapa.printCoordList(Problem.can_be_number_whitebox_list); } // 削除対象のリストを後ろからチェック for (int i = Problem.can_be_number_whitebox_list.Count - 1; i >= 0; i--) { // 時間計測開始 System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); // 現在の状態を保存 StateSave save_point = new StateSave(); StateSave.saveNowState(save_point); // 削除判定の行われていない数字マスの内、 // [最少ヒント数で降順][パターン数で昇順]でソートしたリストの後ろから順に数字マスを選ぶ Coordinates deleting_numbox_coord = Problem.can_be_number_whitebox_list[i]; // 選択された数字マスを、未削除の数字マス座標リストから除外する。 Problem.can_be_number_whitebox_list.Remove(deleting_numbox_coord); Box deleting_box = Tapa.box[deleting_numbox_coord.x][deleting_numbox_coord.y]; // 浅いコピー // 選択した数字マスを未定マスにする deleting_box.revision_color = Box.NOCOLOR; // 選択した座標を未定マスにする deleting_box.hasNum = false; // 数字を持ってるフラグをオフにする Tapa.numbox_coord_list.Remove(deleting_numbox_coord); // 数字マスリストから除外 Tapa.not_deployedbox_coord_list.Add(new Coordinates(deleting_numbox_coord)); // 未定マスリストに追加 // 問題を解く Tapa.solveTapa(); // 解ならば復元後に、選択した数字マスをそのまま未定マスにする。 if (Tapa.isCorrectAnswer()) { StateSave.loadSavedState(save_point); // 選択した数字マスを未定マスにする Tapa.box[deleting_numbox_coord.x][deleting_numbox_coord.y].revision_color = Box.NOCOLOR; // 選択した座標を未定マスにする Tapa.box[deleting_numbox_coord.x][deleting_numbox_coord.y].hasNum = false; // 数字を持ってるフラグをオフにする Tapa.numbox_coord_list.Remove(deleting_numbox_coord); // 数字マスリストから除外 Tapa.not_deployedbox_coord_list.Add(new Coordinates(deleting_numbox_coord)); // 未定マスリストに追加 } else { // 解でないなら、盤面を復元するのみ。 StateSave.loadSavedState(save_point); } //時間計測終了 sw.Stop(); deleting_numbox_coord.printCoordinates(); Console.WriteLine("del >> " + sw.Elapsed + "(" + Problem.can_be_number_whitebox_list.Count + ")"); } }
/********************************* * * 1. 呼ばれた時の状態を保存する。 * 2. co座標のid_listからidを取り出し、配置する。 * 3. 黒マスの孤立を調べ、孤立していればidを除外する。 * 4. 状態を元に戻す。 * 5. 2-4をid_list内のid全てに対して行う。 * * 引数 * co : 数字マスの座標 * id_list : idのリスト * * *******************************/ private static void excludeIdToMakeIsolationBlackBoxGroup(Coordinates co, List<byte> id_list) { StateSave save_point = new StateSave(); // 現在の状態を保存 StateSave.saveNowState(save_point); // 孤立するidのid_listでの要素番号を保存するリスト List<int> iso_id_ite_list = new List<int>(); for (int i = id_list.Count - 1; i >= 0; i--) { PatternAroundNumBox.setPatternAroundNumBox(co, id_list[i]); // 数字マスの周囲5*5マス以内にある黒マス群のリストを取得 List<int> bbgroup_index_list = Box.getIndexBlackBoxGroupListAround55(co); List<List<Coordinates>> multi_list = new List<List<Coordinates>>(); foreach (int index in bbgroup_index_list) { multi_list.Add(Tapa.isolation_blackboxes_group_list[index]); } if (!Box.checkNotIsolationBlackBoxGroup(multi_list) // 盤面に孤立した黒マス群がないか調べる && Tapa.not_deployedbox_coord_list.Count > 0) { iso_id_ite_list.Add(i); } StateSave.loadSavedState(save_point); } // 孤立したidをid_listから削除 foreach (int tmp_ite in iso_id_ite_list) { // id_list.RemoveAt(tmp_ite); Tapa.box[co.x][co.y].id_list.RemoveAt(tmp_ite); } }
/********************************* * * 1. 呼ばれた時の状態を保存する。 * 2. co座標のid_listからidを取り出し、配置する。 * 3. 2.の状態で他の数字マスのidのチェック→除外を行う。 * 4. どれか1つでも数字マスのid_listの大きさが0になった場合、 * そのidのid_listでの添字を記録する。 * 5. id_listの次のidに対して、2-5を繰り返す。 * 6. id_listのid全ての調査が終わったら、4.で記録したidをid_listから除外する。 * * 引数 * co : 数字マスの座標 * id_list : idのリスト * * *******************************/ private static void excludeIdToKillOtherNameBoxAllId(Coordinates co, List<byte> id_list) { StateSave save_point = new StateSave(); // 現在の状態を保存 StateSave.saveNowState(save_point); // 除外するidのid_listでのインデックスを保存するリスト List<int> kill_id_ite_list = new List<int>(); for (int i = id_list.Count - 1; i >= 0; i--) { // idの試し塗り PatternAroundNumBox.setPatternAroundNumBox(co, id_list[i]); // 数字マスのリストから今回試し塗りしたidの数字マスを除外 Tapa.numbox_coord_list.Remove(co); Tapa.box[co.x][co.y].hasNum = false; // co周り5*5マスにある黒マスが属する黒マス群のインデックスを取得 List<int> bbgroup_index_list = Box.getIndexBlackBoxGroupListAround55(co); List<Coordinates> numbox_around_bbgroup_coord_list = Box.getCoordListAroundBlackBoxGroup(bbgroup_index_list); for (int ite_coord = numbox_around_bbgroup_coord_list.Count - 1; ite_coord >= 0; ite_coord--) { // 黒マス群付近の数字マスリスト Coordinates tmp_co = new Coordinates(numbox_around_bbgroup_coord_list[ite_coord]); for (int ite_id = Tapa.box[tmp_co.x][tmp_co.y].id_list.Count - 1; ite_id >= 0; ite_id--) { // id_list byte tmp_id = Tapa.box[tmp_co.x][tmp_co.y].id_list[ite_id]; if (!PatternAroundNumBox.checkPatternAroundNumBox(tmp_co, tmp_id)) { // idのパターンが配置できない Tapa.box[tmp_co.x][tmp_co.y].id_list.RemoveAt(ite_id); } } // idの通り配置したら黒マスの団子ができてしまう PatternAroundNumBox.excludeDumplingId(tmp_co, Tapa.box[tmp_co.x][tmp_co.y].id_list); // id_listのうち、孤立する黒マス群を作るidを除外(id_listごとに処理したほうが効率的) PatternAroundNumBox.excludeIdToMakeIsolationBlackBoxGroup(tmp_co, Tapa.box[tmp_co.x][tmp_co.y].id_list); // id_listの大きさが0なら今回試し塗りしたidの添字を、除外するid_listに追加し、次のidを見に行く。 if (Tapa.box[tmp_co.x][tmp_co.y].id_list.Count == 0) { kill_id_ite_list.Add(i); break; } } // 保存した状態をロード StateSave.loadSavedState(save_point); } // 除外対象のidをid_listから除外 foreach (int tmp_ite in kill_id_ite_list) { Tapa.box[co.x][co.y].id_list.RemoveAt(tmp_ite); } }
/********************************* * * リストや盤面の状態を保存 * * *******************************/ public static void saveNowState(StateSave save_point) { ////// 呼びだされた時点での盤面の全てのマス for (int i = 0; i < Tapa.MAX_BOARD_ROW + 2; i++) { save_point.saved_box[i] = new Box[Tapa.MAX_BOARD_COL + 2]; for (int j = 0; j < Tapa.MAX_BOARD_COL + 2; j++) { save_point.saved_box[i][j] = new Box(Tapa.box[i][j]); } } // 呼びだされた時点での数字マスの座標のリスト save_point.saved_numbox_coord_list = StateSave.getStateCoordList(Tapa.numbox_coord_list); // 呼びだされた時点での未定マスの座標リスト save_point.saved_not_deployedbox_coord_list = StateSave.getStateCoordList(Tapa.not_deployedbox_coord_list); // 呼びだされた時点での伸び代のある黒マスの座標リスト save_point.saved_edge_blackbox_coord_list = StateSave.getStateCoordList(Tapa.edge_blackbox_coord_list); // 呼びだされた時点での一繋がりの黒マス群の座標リスト save_point.saved_isolation_blackboxes_group_list = StateSave.getStateMultiCoordList(Tapa.isolation_blackboxes_group_list); // 呼びだされた時点での一繋がりの黒マス群の座標リスト //save_point.saved_isolation_notdeployedboxes_group_list // = StateSave.getStateMultiCoordList(Tapa.isolation_notdeployedboxes_group_list); // 呼びだされた時点での盤面が変更されたかの情報 save_point.saved_was_changed_board = Tapa.was_change_board; }
/********************************* * * 盤面sのうち、bの座標を未定マスにした盤面を作成する。 * * *******************************/ public static void makeEditBoard(StateSave s) { Tapa.resetBoard(); for (int i = 1; i <= Tapa.MAX_BOARD_ROW; i++) { for (int j = 1; j <= Tapa.MAX_BOARD_COL; j++) { Tapa.box[i][j].connecting_color = s.saved_box[i][j].Color; } } }
/********************************* * * リストや盤面の状態を引数の状態に復元 * * *******************************/ public static void loadSavedState(StateSave save_point) { for (int i = 0; i < Tapa.MAX_BOARD_ROW + 2; i++) { for (int j = 0; j < Tapa.MAX_BOARD_COL + 2; j++) { Tapa.box[i][j] = new Box(save_point.saved_box[i][j]); } } loadSavedStateEdgeBlackBoxCoordList(save_point.saved_edge_blackbox_coord_list); loadSavedStateIsolationBlackBoxesGroupList(save_point.saved_isolation_blackboxes_group_list); loadSavedStateNotDeployedBoxCoordList(save_point.saved_not_deployedbox_coord_list); loadSavedStateNumBoxCoordList(save_point.saved_numbox_coord_list); Tapa.was_change_board = save_point.saved_was_changed_board; }
/********************************* * * 切断点のみの団子マスに接している黒マス群のうち * 最も短い黒マス群とそれに接している切断点を削除する * * *******************************/ private static void removeCutDumpling() { // 団子マス4つの保存用 List<Coordinates> dump_coord; // 団子マスの座標を取得、団子マスがなければ終わり while ((dump_coord = Box.getDumpCoord()) != null) { // 切断点に接している切断点以外の黒マス保存用 // Key : 切断点に接している黒マス // Value : 切断点 Dictionary<Coordinates, Coordinates> adj_dict = new Dictionary<Coordinates, Coordinates>(); foreach (Coordinates co in dump_coord) { // 切断点が接している黒マス座標を取得 List<Coordinates> tmp_adj_coord = Box.getWhatColorBoxCoordListAround(co, Box.BLACK); // 接している黒マスのうち切断点の情報を除外 foreach (Coordinates tmp_co in dump_coord) { tmp_adj_coord.Remove(tmp_co); } adj_dict[tmp_adj_coord[0]] = co; } // 盤面編集用 StateSave edit = new StateSave(); StateSave.saveNowState(edit); // 盤面editの団子マスdump_coordを未定マスにする foreach (Coordinates co in dump_coord) { edit.saved_box[co.x][co.y].revision_color = Box.NOCOLOR; } // edit盤面を生成 // (一繋がりの黒マス群が複数生成される) StateSave.makeEditBoard(edit); // 黒マス群リストのうち、最少の黒マス群の参照を取得 List<Coordinates> min_bblist = Box.getMinIsoBlackBoxListRef(); // 切断点の黒マスの団子を黒く塗る foreach (Coordinates co in dump_coord) { edit.saved_box[co.x][co.y].revision_color = Box.BLACK; } // min_bblistとそれに接している切断点を未定マスにする foreach (Coordinates co in min_bblist) { edit.saved_box[co.x][co.y].revision_color = Box.NOCOLOR; if (!adj_dict.ContainsKey(co)) { continue; } edit.saved_box[adj_dict[co].x][adj_dict[co].y].revision_color = Box.NOCOLOR; } // edit盤面を生成 // (団子マスを1つ除外できた盤面) StateSave.makeEditBoard(edit); } }