Exemplo n.º 1
0
        /*********************************
        *
        * 盤面の初期状態から始めて問題を解けるか判断する.
        *
        * 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);
        }
Exemplo n.º 2
0
        /*********************************
        *
        * 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);
        }
Exemplo n.º 3
0
        /*********************************
        *
        * 切断点のみの団子マスに接している黒マス群のうち
        * 最も短い黒マス群とそれに接している切断点を削除する
        *
        * *******************************/
        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);
            }
        }
Exemplo n.º 4
0
        /*********************************
        *
        * 未定マスを試し塗りしてバックトラックを行う
        * バックトラックの結果が一度でも正しければ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);
        }
Exemplo n.º 5
0
        /*********************************
        *
        * 数字マスを削除して問題生成する。
        * 引数:
        * 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 + ")");
            }
        }