Exemplo n.º 1
0
        /// <summary>
        /// or-toolsの検証
        /// 小さいサイズの問題を解けるかどうか試しにやってみる
        /// </summary>
        public void SolvSmallProblemByOrTools()
        {
            // フィールドとスタンプの生成
            int    field_size = 64;  // 今回の例では正方形なので縦横共通
            string field_str  = Shape.star;
            int    stamp_size = 4;   // 今回の例では正方形なので縦横共通
            string stamp_str  = stamp_size.ToString() + ";" + stamp_size.ToString() + ";" +
                                "1111" +
                                "0101" +
                                "0110" +
                                "1110";
            Field field = new Field();

            field.SetTargetField(field_str);
            Stamp stamp = new Stamp(0, stamp_str);

            // CpModelに変数を追加
            CpModel model = new CpModel();
            Dictionary <Tuple <int, int>, IntVar> stamp_variables = new Dictionary <Tuple <int, int>, IntVar>();
            Dictionary <Tuple <int, int>, IntVar> field_variables = new Dictionary <Tuple <int, int>, IntVar>();

            // スタンプ変数
            for (int y = (stamp_size - 1) * (-1); y < field_size; ++y)
            {
                for (int x = (stamp_size - 1) * (-1); x < field_size; ++x)
                {
                    string name = "stamp_" + y.ToString() + "_" + x.ToString();
                    stamp_variables[new Tuple <int, int>(y, x)] = model.NewBoolVar(name);
                }
            }
            // フィールド変数
            for (int y = 0; y < field_size; ++y)
            {
                for (int x = 0; x < field_size; ++x)
                {
                    string name = "field" + y.ToString() + "_" + x.ToString();
                    field_variables[new Tuple <int, int>(y, x)] = model.NewBoolVar(name);
                }
            }


            List <Tuple <short, short> > field_black_cell_coordinates = field.GetBlackCellCoordinates();

            foreach (var field_cell in field_black_cell_coordinates)
            {
                List <IntVar> var_take_xors = new List <IntVar>();
                List <Tuple <short, short> > stamp_black_cell_coordinates = stamp.GetBlackCellCoordinate();
                foreach (var stamp_cell in stamp_black_cell_coordinates)
                {
                    int y_ind = field_cell.Item1 - stamp_cell.Item1;
                    int x_ind = field_cell.Item2 - stamp_cell.Item2;
                    var_take_xors.Add(stamp_variables[new Tuple <int, int>(y_ind, x_ind)]);
                }
                model.AddBoolXor(var_take_xors);
            }

            List <Tuple <short, short> > field_white_cell_coordinates = field.GetWhiteCellCoordinates();

            foreach (var field_cell in field_white_cell_coordinates)
            {
                List <IntVar> var_take_xors = new List <IntVar>();
                List <Tuple <short, short> > stamp_black_cell_coordinates = stamp.GetBlackCellCoordinate();
                foreach (var stamp_cell in stamp_black_cell_coordinates)
                {
                    int y_ind = field_cell.Item1 - stamp_cell.Item1;
                    int x_ind = field_cell.Item2 - stamp_cell.Item2;
                    var_take_xors.Add(stamp_variables[new Tuple <int, int>(y_ind, x_ind)]);
                }

                // target fieldの情報を制約に追加.
                List <IntVar> field_variable = new List <IntVar>();
                field_variable.Add(field_variables[new Tuple <int, int>(field_cell.Item1, field_cell.Item2)]);
                model.AddBoolAnd(field_variable);

                var_take_xors.Add(field_variables[new Tuple <int, int>(field_cell.Item1, field_cell.Item2)]);
                model.AddBoolXor(var_take_xors);
            }

            // 求解
            CpSolver solver = new CpSolver();

            solver.StringParameters = "max_time_in_seconds:5.0";
            Console.WriteLine("start!!\n");
            CpSolverStatus status = solver.Solve(model);

            // 解の検証
            Console.WriteLine("Pressing stamp is:");
            if (status == CpSolverStatus.Feasible)
            {
                for (int y = (stamp_size - 1) * (-1); y < field_size; ++y)
                {
                    for (int x = (stamp_size - 1) * (-1); x < field_size; ++x)
                    {
                        Tuple <int, int> cur_pos = new Tuple <int, int>(y, x);
                        if (solver.Value(stamp_variables[cur_pos]) == 1)
                        {
                            field.PressStamp(stamp, (short)x, (short)y);
                            Console.Write("1");
                        }
                        else
                        {
                            Console.Write("0");
                        }
                    }
                    Console.WriteLine();
                }

                Console.WriteLine("\nmy_field is :");
                field.PrintMyself();
                Console.WriteLine("\ntarget_field is :");
                field.PrintTargetField();
            }
        }