// File: /workspace/github_cpp_makefile_star2_O2/ArashPartow[P]exprtk-extras/exprtk_game_of_life.cpp
// Function: void game_of_life<double>()
void game_of_life()
{
   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;

   const std::size_t width  = 60;
   const std::size_t height = 30;

   std::vector<T> world(width * height, T(0));
   rnd_01<T> rnd01;
   exprtk::rtl::io::package<T> io_package;

   symbol_table_t symbol_table;
   symbol_table.add_constant("width" , static_cast<T>(width ));
   symbol_table.add_constant("height", static_cast<T>(height));
   symbol_table.add_vector  ("world" , world);
   symbol_table.add_package (io_package);
   symbol_table.add_function("random", rnd01);
   symbol_table.add_function("sleep" ,
                             [](T time_ms) -> T
                             {
                               std::this_thread::sleep_for(
                               std::chrono::milliseconds(static_cast<std::size_t>(time_ms)));
                               return T(1);
                             });

   compositor_t compositor(symbol_table);

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


   compositor.add(
      function_t("point")
      .vars("x","y")
      .expression
      (
         " world[y * width + x]; "
      ));

   compositor.add(
      function_t("set_point")
      .vars("x","y","value")
      .expression
      (
         " world[y * width + x] := value; "
      ));

   compositor.add(
      function_t("render")
      .expression
      (
         " print('+');                                         "
         " for (var x := 0; x < width; x += 1) { print('-'); } "
         " println('+');                                       "
         "                                                     "
         " for (var y := 0; y < height; y += 1)                "
         " {                                                   "
         "    print('|');                                      "
         "    for (var x := 0; x < width; x += 1)              "
         "    {                                                "
         "       print( point(x,y) ? '*' : ' ' );              "
         "    };                                               "
         "    println('|');                                    "
         " };                                                  "
         "                                                     "
         " print('+');                                         "
         " for (var x := 0; x < width; x += 1) { print('-'); } "
         " println('+');                                       "
      ));

   compositor.add(
      function_t("evolve")
      .expression
      (
         " var next_world[world[]] := [0];                       "
         "                                                       "
         " for (var y := 0; y < height; y += 1)                  "
         " {                                                     "
         "    for (var x := 0; x < width; x += 1)                "
         "    {                                                  "
         "       var alive_count := point(x,y) ? -1 : 0;         "
         "                                                       "
         "       for (var y1 := y - 1; y1 <= y + 1; y1 += 1)     "
         "       {                                               "
         "          var curr_y := (y1 + height) % height;        "
         "                                                       "
         "          for (var x1 := x - 1; x1 <= x + 1; x1 += 1)  "
         "          {                                            "
         "             var curr_x := (x1 + width) % width;       "
         "                                                       "
         "             if (point(curr_x,curr_y))                 "
         "             {                                         "
         "                alive_count += 1;                      "
         "             }                                         "
         "          }                                            "
         "       };                                              "
         "                                                       "
         "       next_world[y * width + x] :=                    "
         "          switch                                       "
         "          {                                            "
         "             case alive_count == 2 and point(x,y) : 1; "
         "             case alive_count == 3 : 1;                "
         "             default               : 0;                "
         "          };                                           "
         "    }                                                  "
         " };                                                    "
         "                                                       "
         " world := next_world;                                  "
      ));

   const std::string game_of_life_driver =
      " /* Randomly setup the initial state of the world */ "
      " for (var x := 0; x < width; x += 1)                 "
      " {                                                   "
      "    for (var y := 0; y < height; y += 1)             "
      "    {                                                "
      "       set_point(x, y, (random() < 0.15) ? 1 : 0);   "
      "    }                                                "
      " };                                                  "
      "                                                     "
      " var num_generations := 200;                         "
      "                                                     "
      " for (var i := 0; i < num_generations; i += 1)       "
      " {                                                   "
      "    println('Generation: ', i);                      "
      "    render();                                        "
      "    evolve();                                        "
      "    sleep(200);                                      "
      " }                                                   ";

   expression_t expression;
   expression.register_symbol_table(symbol_table);

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

   expression.value();
}

// Assembly:
pushq %rbx
subq $0x29a0, %rsp           # imm = 0x29A0
leaq 0x15e0(%rsp), %rdx
andq $0x0, (%rdx)
leaq 0x78(%rsp), %rdi
leaq 0xbf8(%rsp), %rcx
movl $0x708, %esi            # imm = 0x708
callq 0x113b60
leaq 0x15e0(%rsp), %rdi
callq 0x113bb6
leaq 0x200(%rsp), %rdi
callq 0x113c92
leaq 0x8(%rsp), %rdi
pushq $0x1
popq %rsi
callq 0x113d36
leaq 0x132d4d(%rip), %rsi    # 0x246129
leaq 0xbf8(%rsp), %rdi
leaq 0xb0(%rsp), %rdx
callq 0x113348
movabsq $0x404e000000000000, %rax # imm = 0x404E000000000000
leaq 0x2d0(%rsp), %rdx
movq %rax, (%rdx)
leaq 0x8(%rsp), %rdi
leaq 0xbf8(%rsp), %rsi
callq 0x113d5a
leaq 0xbf8(%rsp), %rdi
callq 0x111648
leaq 0x132d03(%rip), %rsi    # 0x24612f
leaq 0xbf8(%rsp), %rdi
leaq 0xb0(%rsp), %rdx
callq 0x113348
movabsq $0x403e000000000000, %rax # imm = 0x403E000000000000
leaq 0x2d0(%rsp), %rdx
movq %rax, (%rdx)
leaq 0x8(%rsp), %rdi
leaq 0xbf8(%rsp), %rsi
callq 0x113d5a
leaq 0xbf8(%rsp), %rdi
callq 0x111648
leaq 0x132cba(%rip), %rsi    # 0x246136
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rdx
callq 0x113348
leaq 0x8(%rsp), %rdi
leaq 0xbf8(%rsp), %rsi
leaq 0x78(%rsp), %rdx
callq 0x113dd6
leaq 0xbf8(%rsp), %rdi
callq 0x111648
leaq 0x200(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x117b38
leaq 0x132c6e(%rip), %rsi    # 0x24613c
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rdx
callq 0x113348
leaq 0x8(%rsp), %rdi
leaq 0xbf8(%rsp), %rsi
leaq 0x15e0(%rsp), %rdx
callq 0x113e40
leaq 0xbf8(%rsp), %rdi
callq 0x111648
leaq 0x132c32(%rip), %rsi    # 0x246143
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rdx
callq 0x113348
leaq 0x529d(%rip), %rdx      # 0x1187ca
leaq 0x8(%rsp), %rdi
leaq 0xbf8(%rsp), %rsi
callq 0x113ea0
leaq 0xbf8(%rsp), %rdi
callq 0x111648
leaq 0xbf8(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x113f54
movw $0x101, 0x15d8(%rsp)    # imm = 0x101
leaq 0x132bf6(%rip), %rsi    # 0x246165
leaq 0xb0(%rsp), %rdi
leaq 0x90(%rsp), %rdx
callq 0x113348
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x114072
leaq 0x132ae1(%rip), %rsi    # 0x246081
leaq 0x18(%rsp), %rdi
leaq 0x7(%rsp), %rdx
callq 0x113348
leaq 0x133c54(%rip), %rsi    # 0x24720a
leaq 0x38(%rsp), %rdi
leaq 0x6(%rsp), %rdx
callq 0x113348
leaq 0x2d0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x38(%rsp), %rdx
callq 0x1140be
movq %rax, %rbx
leaq 0x132b63(%rip), %rsi    # 0x246149
leaq 0x58(%rsp), %rdi
leaq 0x5(%rsp), %rdx
callq 0x113348
leaq 0x20(%rbx), %rdi
leaq 0x58(%rsp), %rsi
callq 0x1115c0
leaq 0xbf8(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x114062
leaq 0x58(%rsp), %rdi
callq 0x111648
leaq 0x38(%rsp), %rdi
callq 0x111648
leaq 0x18(%rsp), %rdi
callq 0x111648
leaq 0x2d0(%rsp), %rdi
callq 0x1140ea
leaq 0xb0(%rsp), %rdi
callq 0x111648
leaq 0x132b0d(%rip), %rsi    # 0x246161
leaq 0xb0(%rsp), %rdi
leaq 0x7(%rsp), %rdx
callq 0x113348
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x114072
leaq 0x1329ff(%rip), %rsi    # 0x246081
leaq 0x18(%rsp), %rdi
leaq 0x6(%rsp), %rdx
callq 0x113348
leaq 0x133b72(%rip), %rsi    # 0x24720a
leaq 0x38(%rsp), %rdi
leaq 0x5(%rsp), %rdx
callq 0x113348
leaq 0x133b46(%rip), %rsi    # 0x2471f4
leaq 0x58(%rsp), %rdi
leaq 0x17(%rsp), %rdx
callq 0x113348
leaq 0x2d0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x38(%rsp), %rdx
leaq 0x58(%rsp), %rcx
callq 0x11410a
movq %rax, %rbx
leaq 0x132a88(%rip), %rsi    # 0x24616b
leaq 0x90(%rsp), %rdi
leaq 0x16(%rsp), %rdx
callq 0x113348
leaq 0x20(%rbx), %rdi
leaq 0x90(%rsp), %rsi
callq 0x1115c0
leaq 0xbf8(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x114062
leaq 0x90(%rsp), %rdi
callq 0x111648
leaq 0x58(%rsp), %rdi
callq 0x111648
leaq 0x38(%rsp), %rdi
callq 0x111648
leaq 0x18(%rsp), %rdi
callq 0x111648
leaq 0x2d0(%rsp), %rdi
callq 0x1140ea
leaq 0xb0(%rsp), %rdi
callq 0x111648
leaq 0x132a28(%rip), %rsi    # 0x24618c
leaq 0xb0(%rsp), %rdi
leaq 0x38(%rsp), %rdx
callq 0x113348
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x114072
leaq 0x132a01(%rip), %rsi    # 0x246193
leaq 0x18(%rsp), %rdi
leaq 0x58(%rsp), %rdx
callq 0x113348
leaq 0x2f0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x1115c0
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rsi
xorl %edx, %edx
callq 0x114062
leaq 0x18(%rsp), %rdi
callq 0x111648
leaq 0x2d0(%rsp), %rdi
callq 0x1140ea
leaq 0xb0(%rsp), %rdi
callq 0x111648
leaq 0x132d24(%rip), %rsi    # 0x246519
leaq 0xb0(%rsp), %rdi
leaq 0x38(%rsp), %rdx
callq 0x113348
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x114072
leaq 0x132cfd(%rip), %rsi    # 0x246520
leaq 0x18(%rsp), %rdi
leaq 0x58(%rsp), %rdx
callq 0x113348
leaq 0x2f0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x1115c0
leaq 0xbf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rsi
xorl %edx, %edx
callq 0x114062
leaq 0x18(%rsp), %rdi
callq 0x111648
leaq 0x2d0(%rsp), %rdi
callq 0x1140ea
leaq 0xb0(%rsp), %rdi
callq 0x111648
leaq 0x1333e9(%rip), %rsi    # 0x246c6f
leaq 0x18(%rsp), %rdi
leaq 0x2d0(%rsp), %rdx
callq 0x113348
leaq 0x38(%rsp), %rdi
callq 0x11414c
leaq 0x38(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x1141ac
leaq 0xb0(%rsp), %rdi
pushq $0x7f
popq %rsi
callq 0x114208
leaq 0x2d0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x114318
leaq 0xb0(%rsp), %rdi
callq 0x114930
leaq 0x2d0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x38(%rsp), %rdx
callq 0x114978
movq 0x38(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
leaq 0x2d0(%rsp), %rdi
callq 0x114dfa
leaq 0x38(%rsp), %rdi
callq 0x114f34
leaq 0x18(%rsp), %rdi
callq 0x111648
leaq 0xbf8(%rsp), %rdi
callq 0x114f4a
leaq 0x8(%rsp), %rdi
callq 0x114f9e
leaq 0x200(%rsp), %rdi
callq 0x114fe0
leaq 0x78(%rsp), %rdi
callq 0x115024
addq $0x29a0, %rsp           # imm = 0x29A0
popq %rbx
retq
movq %rax, %rbx
leaq 0xb0(%rsp), %rdi
callq 0x114930
jmp 0x113a24
jmp 0x113978
movq %rax, %rbx
jmp 0x113a24
movq %rax, %rbx
jmp 0x113a2e
jmp 0x1139c9
jmp 0x1139b9
jmp 0x1139c1
jmp 0x1139c9
jmp 0x1139b9
jmp 0x1139c1
jmp 0x1139c9
jmp 0x113a4e
jmp 0x113a4e
jmp 0x1139af
jmp 0x113a37
jmp 0x1139b9
jmp 0x1139c1
jmp 0x1139c9
jmp 0x1139af
movq %rax, %rbx
jmp 0x113a5b
jmp 0x113a37
movq %rax, %rbx
jmp 0x113a6f
movq %rax, %rbx
jmp 0x113a7c
movq %rax, %rbx
jmp 0x113a89
jmp 0x1139fa
jmp 0x1139e5
jmp 0x1139fa
jmp 0x1139e5
jmp 0x1139fa
jmp 0x1139fa
jmp 0x1139e5
jmp 0x1139fa
jmp 0x1139e5
jmp 0x1139fa
movq %rax, %rbx
leaq 0xbf8(%rsp), %rdi
callq 0x111648
jmp 0x113a96
movq %rax, %rbx
jmp 0x113a96
movq %rax, %rbx
jmp 0x113aa0
jmp 0x113a0c
movq %rax, %rbx
jmp 0x113aad
movq %rax, %rbx
leaq 0x2d0(%rsp), %rdi
callq 0x114dfa
leaq 0x38(%rsp), %rdi
callq 0x114f34
leaq 0x18(%rsp), %rdi
jmp 0x113a84
jmp 0x113a37
movq %rax, %rbx
jmp 0x113a65
movq %rax, %rbx
leaq 0x90(%rsp), %rdi
callq 0x111648
jmp 0x113a51
movq %rax, %rbx
leaq 0x58(%rsp), %rdi
callq 0x111648
leaq 0x38(%rsp), %rdi
callq 0x111648
leaq 0x18(%rsp), %rdi
callq 0x111648
leaq 0x2d0(%rsp), %rdi
callq 0x1140ea
leaq 0xb0(%rsp), %rdi
callq 0x111648
leaq 0xbf8(%rsp), %rdi
callq 0x114f4a
leaq 0x8(%rsp), %rdi
callq 0x114f9e
leaq 0x200(%rsp), %rdi
callq 0x114fe0
leaq 0x78(%rsp), %rdi
callq 0x115024
movq %rbx, %rdi
callq 0x111340