// File: /workspace/github_cpp_makefile_star2_O2/ArashPartow[P]exprtk-extras/exprtk_sudoku_solver.cpp
// Function: void sudoku_solver<double>()
void sudoku_solver()
{
   typedef exprtk::symbol_table<T>         symbol_table_t;
   typedef exprtk::expression<T>           expression_t;
   typedef exprtk::parser<T>               parser_t;
   typedef exprtk::function_compositor<T>  compositor_t;
   typedef typename compositor_t::function function_t;

   std::vector<T> board =
   {
      0, 0, 0, 0, 0, 8, 2, 0, 5,
      0, 0, 0, 3, 2, 0, 0, 0, 8,
      0, 0, 0, 0, 0, 5, 6, 0, 0,
      0, 1, 0, 0, 4, 7, 0, 9, 3,
      0, 0, 0, 0, 0, 0, 0, 0, 0,
      8, 6, 0, 2, 3, 0, 0, 1, 0,
      0, 0, 6, 8, 0, 0, 0, 0, 0,
      5, 0, 0, 0, 7, 3, 0, 0, 0,
      4, 0, 3, 9, 0, 0, 0, 0, 0,
   };

   exprtk::rtl::io::package<T> io_package;

   symbol_table_t symbol_table;
   symbol_table.add_vector  ("board", board);
   symbol_table.add_function("print_digit",
                             [](T v) ->T
                             { printf(" %d ",static_cast<int>(v)); return 0; });
   symbol_table.add_package (io_package);

   compositor_t compositor(symbol_table);

   compositor.load_variables(true);
   compositor.load_vectors  (true);

   compositor.add(
      function_t("get_board")
      .vars("col", "row")
      .expression
      ( " board[row * sqrt(board[]) + col]; " ));

   compositor.add(
      function_t("set_board")
      .vars("col", "row", "value")
      .expression
      ( " board[row * sqrt(board[]) + col] := value; " ));

   compositor.add(
      function_t("display_board")
      .expression
      (
         " const var n := sqrt(board[]);                             "
         "                                                           "
         " for (var row := 0; row < n; row += 1)                     "
         " {                                                         "
         "    for (var col := 0; col < n; col += 1)                  "
         "    {                                                      "
         "       print_digit(get_board(col,row));                    "
         "                                                           "
         "       if ((col > 0) and (col < 8) and (col + 1) % 3 == 0) "
         "       {                                                   "
         "          print('|')                                       "
         "       }                                                   "
         "    };                                                     "
         "                                                           "
         "    println('');                                           "
         "                                                           "
         "    if ((row > 0) and (row < 8) and (row + 1) % 3 == 0)    "
         "    {                                                      "
         "       println('---------+---------+----------');          "
         "    }                                                      "
         " }                                                         "
      ));

   compositor.add(
      function_t("is_valid")
      .vars("col", "row", "num")
      .expression
      (
         " const var n := sqrt(board[]);                              "
         "                                                            "
         " for (var i := 0; i < n; i += 1)                            "
         " {                                                          "
         "    if (                                                    "
         "         (get_board(col, i  ) == num) or                    "
         "         (get_board(i  , row) == num)                       "
         "       )                                                    "
         "    {                                                       "
         "       return [false];                                      "
         "    }                                                       "
         " };                                                         "
         "                                                            "
         " var subgrid_row := row - floor(row % 3);                   "
         " var subgrid_col := col - floor(col % 3);                   "
         "                                                            "
         " for (var i := subgrid_row; i < subgrid_row + 3; i += 1)    "
         " {                                                          "
         "    for (var j := subgrid_col; j < subgrid_col + 3; j += 1) "
         "    {                                                       "
         "       if (get_board(j,i) == num)                           "
         "       {                                                    "
         "          return [false];                                   "
         "       }                                                    "
         "    }                                                       "
         " };                                                         "
         "                                                            "
         " return [true];                                             "
      ));

   compositor.add(
      function_t("solve_sudoku")
      .expression
      (
         " const var n := sqrt(board[]);                "
         "                                              "
         " for (var row := 0; row < n; row += 1)        "
         " {                                            "
         "    for (var col := 0; col < n; col += 1)     "
         "    {                                         "
         "       if (get_board(col, row) != 0)          "
         "       {                                      "
         "          continue;                           "
         "       }                                      "
         "                                              "
         "       for (var num := 1; num <= 9; num += 1) "
         "       {                                      "
         "          if (not(is_valid(col, row, num)))   "
         "          {                                   "
         "             continue;                        "
         "          }                                   "
         "                                              "
         "          set_board(col, row, num);           "
         "                                              "
         "          if (solve_sudoku())                 "
         "          {                                   "
         "             return [true];                   "
         "          };                                  "
         "                                              "
         "          set_board(col, row, 0);             "
         "       };                                     "
         "                                              "
         "       return [false];                        "
         "    }                                         "
         " };                                           "
         "                                              "
         " return [true];                               "
      ));

   const std::string sudoku_solver_program =
      " if (solve_sudoku())                           "
      " {                                             "
      "    println('Puzzle Solved!');                 "
      " }                                             "
      " else                                          "
      " {                                             "
      "    println('Error: Failed to solve puzzle.'); "
      " };                                            "
      "                                               "
      " display_board();                              ";

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.compile(sudoku_solver_program,expression);

   expression.value();
}

// Assembly:
pushq %rbx
subq $0x15e0, %rsp           # imm = 0x15E0
leaq 0x137d7e(%rip), %rsi    # 0x24b0a0
leaq 0xbf8(%rsp), %rbx
movl $0x288, %edx            # imm = 0x288
movq %rbx, %rdi
callq 0x111070
leaq 0x98(%rsp), %rdi
pushq $0x51
popq %rdx
leaq 0x2d0(%rsp), %rcx
movq %rbx, %rsi
callq 0x113b20
leaq 0x200(%rsp), %rdi
callq 0x113b56
leaq 0x10(%rsp), %rdi
pushq $0x1
popq %rsi
callq 0x113bfa
leaq 0x131dba(%rip), %rsi    # 0x24512d
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rdx
callq 0x1132d8
leaq 0x10(%rsp), %rdi
leaq 0xbf8(%rsp), %rsi
leaq 0x98(%rsp), %rdx
callq 0x113c1e
leaq 0xbf8(%rsp), %rdi
callq 0x1115d8
leaq 0x131d67(%rip), %rsi    # 0x24511d
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rdx
callq 0x1132d8
leaq 0x3c48(%rip), %rdx      # 0x11701a
leaq 0x10(%rsp), %rdi
leaq 0xbf8(%rsp), %rsi
callq 0x113c88
leaq 0xbf8(%rsp), %rdi
callq 0x1115d8
leaq 0x200(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x117042
leaq 0xbf8(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x113d3c
movw $0x101, 0x15d8(%rsp)    # imm = 0x101
leaq 0x131d03(%rip), %rsi    # 0x245129
leaq 0xb0(%rsp), %rdi
leaq 0x78(%rsp), %rdx
callq 0x1132d8
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x113e5a
leaq 0x131cdf(%rip), %rsi    # 0x245133
leaq 0x18(%rsp), %rdi
leaq 0xd(%rsp), %rdx
callq 0x1132d8
leaq 0x131ccd(%rip), %rsi    # 0x245137
leaq 0x38(%rsp), %rdi
leaq 0xc(%rsp), %rdx
callq 0x1132d8
leaq 0x2d0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x38(%rsp), %rdx
callq 0x113ea6
movq %rax, %rbx
leaq 0x131ca1(%rip), %rsi    # 0x24513b
leaq 0x58(%rsp), %rdi
leaq 0xb(%rsp), %rdx
callq 0x1132d8
leaq 0x20(%rbx), %rdi
leaq 0x58(%rsp), %rsi
callq 0x111550
leaq 0xbf8(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x113e4a
leaq 0x58(%rsp), %rdi
callq 0x1115d8
leaq 0x38(%rsp), %rdi
callq 0x1115d8
leaq 0x18(%rsp), %rdi
callq 0x1115d8
leaq 0x2d0(%rsp), %rdi
callq 0x113ed2
leaq 0xb0(%rsp), %rdi
callq 0x1115d8
leaq 0x131c57(%rip), %rsi    # 0x24515f
leaq 0xb0(%rsp), %rdi
leaq 0xd(%rsp), %rdx
callq 0x1132d8
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x113e5a
leaq 0x131bfd(%rip), %rsi    # 0x245133
leaq 0x18(%rsp), %rdi
leaq 0xc(%rsp), %rdx
callq 0x1132d8
leaq 0x131beb(%rip), %rsi    # 0x245137
leaq 0x38(%rsp), %rdi
leaq 0xb(%rsp), %rdx
callq 0x1132d8
leaq 0x13315a(%rip), %rsi    # 0x2466bc
leaq 0x58(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x1132d8
leaq 0x2d0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x38(%rsp), %rdx
leaq 0x58(%rsp), %rcx
callq 0x113ef2
movq %rax, %rbx
leaq 0x131bd2(%rip), %rsi    # 0x245169
leaq 0x78(%rsp), %rdi
leaq 0xe(%rsp), %rdx
callq 0x1132d8
leaq 0x20(%rbx), %rdi
leaq 0x78(%rsp), %rsi
callq 0x111550
leaq 0xbf8(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x113e4a
leaq 0x78(%rsp), %rdi
callq 0x1115d8
leaq 0x58(%rsp), %rdi
callq 0x1115d8
leaq 0x38(%rsp), %rdi
callq 0x1115d8
leaq 0x18(%rsp), %rdi
callq 0x1115d8
leaq 0x2d0(%rsp), %rdi
callq 0x113ed2
leaq 0xb0(%rsp), %rdi
callq 0x1115d8
leaq 0x131b87(%rip), %rsi    # 0x245196
leaq 0xb0(%rsp), %rdi
leaq 0x38(%rsp), %rdx
callq 0x1132d8
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x113e5a
leaq 0x131b67(%rip), %rsi    # 0x2451a4
leaq 0x18(%rsp), %rdi
leaq 0x58(%rsp), %rdx
callq 0x1132d8
leaq 0x2f0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x111550
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rsi
xorl %edx, %edx
callq 0x113e4a
leaq 0x18(%rsp), %rdi
callq 0x1115d8
leaq 0x2d0(%rsp), %rdi
callq 0x113ed2
leaq 0xb0(%rsp), %rdi
callq 0x1115d8
leaq 0x131fdc(%rip), %rsi    # 0x24567c
leaq 0xb0(%rsp), %rdi
leaq 0xd(%rsp), %rdx
callq 0x1132d8
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x113e5a
leaq 0x131a65(%rip), %rsi    # 0x245133
leaq 0x18(%rsp), %rdi
leaq 0xc(%rsp), %rdx
callq 0x1132d8
leaq 0x131a53(%rip), %rsi    # 0x245137
leaq 0x38(%rsp), %rdi
leaq 0xb(%rsp), %rdx
callq 0x1132d8
leaq 0x131f8b(%rip), %rsi    # 0x245685
leaq 0x58(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x1132d8
leaq 0x2d0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x38(%rsp), %rdx
leaq 0x58(%rsp), %rcx
callq 0x113ef2
movq %rax, %rbx
leaq 0x131f5a(%rip), %rsi    # 0x245689
leaq 0x78(%rsp), %rdi
leaq 0xe(%rsp), %rdx
callq 0x1132d8
leaq 0x20(%rbx), %rdi
leaq 0x78(%rsp), %rsi
callq 0x111550
leaq 0xbf8(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x113e4a
leaq 0x78(%rsp), %rdi
callq 0x1115d8
leaq 0x58(%rsp), %rdi
callq 0x1115d8
leaq 0x38(%rsp), %rdi
callq 0x1115d8
leaq 0x18(%rsp), %rdi
callq 0x1115d8
leaq 0x2d0(%rsp), %rdi
callq 0x113ed2
leaq 0xb0(%rsp), %rdi
callq 0x1115d8
leaq 0x132573(%rip), %rsi    # 0x245d1a
leaq 0xb0(%rsp), %rdi
leaq 0x38(%rsp), %rdx
callq 0x1132d8
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x113e5a
leaq 0x132552(%rip), %rsi    # 0x245d27
leaq 0x18(%rsp), %rdi
leaq 0x58(%rsp), %rdx
callq 0x1132d8
leaq 0x2f0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x111550
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rsi
xorl %edx, %edx
callq 0x113e4a
leaq 0x18(%rsp), %rdi
callq 0x1115d8
leaq 0x2d0(%rsp), %rdi
callq 0x113ed2
leaq 0xb0(%rsp), %rdi
callq 0x1115d8
leaq 0x132ade(%rip), %rsi    # 0x246316
leaq 0x18(%rsp), %rdi
leaq 0x2d0(%rsp), %rdx
callq 0x1132d8
leaq 0x38(%rsp), %rdi
callq 0x113f34
leaq 0x38(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x113f94
leaq 0xb0(%rsp), %rdi
pushq $0x7f
popq %rsi
callq 0x113ff0
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x114100
leaq 0xb0(%rsp), %rdi
callq 0x114718
leaq 0x2d0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x38(%rsp), %rdx
callq 0x114760
movq 0x38(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
leaq 0x2d0(%rsp), %rdi
callq 0x114be2
leaq 0x38(%rsp), %rdi
callq 0x114d1c
leaq 0x18(%rsp), %rdi
callq 0x1115d8
leaq 0xbf8(%rsp), %rdi
callq 0x114d32
leaq 0x10(%rsp), %rdi
callq 0x114d86
leaq 0x200(%rsp), %rdi
callq 0x114dc8
leaq 0x98(%rsp), %rdi
callq 0x114e3a
addq $0x15e0, %rsp           # imm = 0x15E0
popq %rbx
retq
movq %rax, %rbx
leaq 0xb0(%rsp), %rdi
callq 0x114718
jmp 0x1139e2
jmp 0x11392d
movq %rax, %rbx
jmp 0x1139e2
movq %rax, %rbx
jmp 0x1139ec
jmp 0x113995
jmp 0x113985
jmp 0x11398d
jmp 0x113995
jmp 0x113a0b
jmp 0x113a0b
jmp 0x11397b
jmp 0x1139f7
jmp 0x113985
jmp 0x11398d
jmp 0x113995
jmp 0x113985
jmp 0x11398d
jmp 0x113995
jmp 0x113a0b
jmp 0x113a0b
jmp 0x11397b
jmp 0x1139f7
jmp 0x113985
jmp 0x11398d
jmp 0x113995
jmp 0x11397b
movq %rax, %rbx
jmp 0x113a18
jmp 0x1139f7
movq %rax, %rbx
jmp 0x113a2c
movq %rax, %rbx
jmp 0x113a39
movq %rax, %rbx
jmp 0x113a46
jmp 0x1139ba
jmp 0x1139ba
jmp 0x1139a5
jmp 0x1139ba
movq %rax, %rbx
leaq 0xbf8(%rsp), %rdi
callq 0x1115d8
jmp 0x113a53
movq %rax, %rbx
jmp 0x113a53
movq %rax, %rbx
jmp 0x113a5d
movq %rax, %rbx
jmp 0x113a6a
movq %rax, %rbx
leaq 0x2d0(%rsp), %rdi
callq 0x114be2
leaq 0x38(%rsp), %rdi
callq 0x114d1c
leaq 0x18(%rsp), %rdi
jmp 0x113a41
jmp 0x1139f7
jmp 0x1139fc
movq %rax, %rbx
jmp 0x113a22
movq %rax, %rbx
leaq 0x78(%rsp), %rdi
callq 0x1115d8
jmp 0x113a0e
movq %rax, %rbx
leaq 0x58(%rsp), %rdi
callq 0x1115d8
leaq 0x38(%rsp), %rdi
callq 0x1115d8
leaq 0x18(%rsp), %rdi
callq 0x1115d8
leaq 0x2d0(%rsp), %rdi
callq 0x113ed2
leaq 0xb0(%rsp), %rdi
callq 0x1115d8
leaq 0xbf8(%rsp), %rdi
callq 0x114d32
leaq 0x10(%rsp), %rdi
callq 0x114d86
leaq 0x200(%rsp), %rdi
callq 0x114dc8
leaq 0x98(%rsp), %rdi
callq 0x114e3a
movq %rbx, %rdi
callq 0x111310