// File: czinn[P]homeworlds/negamax.cc
// Function: Negamax::negamax(Game const*, int, int, int)
int Negamax::negamax(const Game *game, int depth, int a, int b) {
  int olda = a;

  int h = game->hash();
  if (transpositions.count(h) > 0) {
    Transposition t = transpositions[h];
    if (t.depth >= depth) {
      if (t.flag == EXACT) {
        return t.value;
      } else if (t.flag == LOWERBOUND) {
        a = std::max(a, t.value);
      } else if (t.flag == UPPERBOUND) {
        a = std::min(b, t.value);
      }
      if (a >= b) {
        return t.value;
      }
    }
  }

  if (depth == 0 || game->winner() != 0) {
    return heuristic(game);
  }

  int best = -10000000;
  std::vector<Turn*> turns = get_turns(game);
  std::sort(turns.begin(), turns.end(),
      [this](const Turn *a, const Turn *b) {
        int ha = a->game->hash();
        int hb = b->game->hash();
        int sa = this->transpositions.count(ha) > 0 ? this->transpositions[ha].value : 0;
        int sb = this->transpositions.count(hb) > 0 ? this->transpositions[hb].value : 0;
        return sa > sb;
      });
  int num = 0;
  for (const Turn *turn : turns) {
    int value = -negamax(turn->game, depth - 1, -b, -a);
    best = std::max(best, value);
    a = std::max(a, value);
    num++;
    if (a >= b) {
      break;
    }
  }
  for (Turn *turn : turns) {
    delete turn;
  }

  Transposition t{best, depth};
  if (best <= olda) {
    t.flag = UPPERBOUND;
  } else if (best >= b) {
    t.flag = LOWERBOUND;
  } else {
    t.flag = EXACT;
  }
  transpositions[h] = t;

  return best;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x110, %rsp            # imm = 0x110
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
movl %ecx, -0x20(%rbp)
movl %r8d, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0xe0(%rbp)
movl -0x20(%rbp), %eax
movl %eax, -0x28(%rbp)
movq -0x18(%rbp), %rdi
callq 0x3f60
movq -0xe0(%rbp), %rdi
movl %eax, -0x2c(%rbp)
addq $0x8, %rdi
leaq -0x2c(%rbp), %rsi
callq 0x16c70
cmpq $0x0, %rax
jbe 0x1415f
movq -0xe0(%rbp), %rdi
addq $0x8, %rdi
leaq -0x2c(%rbp), %rsi
callq 0x16ca0
movq (%rax), %rcx
movq %rcx, -0x38(%rbp)
movl 0x8(%rax), %eax
movl %eax, -0x30(%rbp)
movl -0x34(%rbp), %eax
cmpl -0x1c(%rbp), %eax
jl 0x1415d
cmpl $0x0, -0x30(%rbp)
jne 0x14112
movl -0x38(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x14456
cmpl $0x1, -0x30(%rbp)
jne 0x1412c
leaq -0x38(%rbp), %rsi
leaq -0x20(%rbp), %rdi
callq 0x16a40
movl (%rax), %eax
movl %eax, -0x20(%rbp)
jmp 0x14146
cmpl $0x2, -0x30(%rbp)
jne 0x14144
leaq -0x38(%rbp), %rsi
leaq -0x24(%rbp), %rdi
callq 0x16cd0
movl (%rax), %eax
movl %eax, -0x20(%rbp)
jmp 0x14146
jmp 0x14148
movl -0x20(%rbp), %eax
cmpl -0x24(%rbp), %eax
jl 0x1415b
movl -0x38(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x14456
jmp 0x1415d
jmp 0x1415f
cmpl $0x0, -0x1c(%rbp)
je 0x14173
movq -0x18(%rbp), %rdi
callq 0x3c80
cmpl $0x0, %eax
je 0x1418b
movq -0xe0(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x14470
movl %eax, -0x4(%rbp)
jmp 0x14456
movq -0xe0(%rbp), %rsi
movl $0xff676980, -0x3c(%rbp) # imm = 0xFF676980
movq -0x18(%rbp), %rdx
leaq -0x58(%rbp), %rdi
movq %rdi, -0xe8(%rbp)
callq 0x13a10
movq -0xe8(%rbp), %rdi
callq 0x16980
movq -0xe8(%rbp), %rdi
movq %rax, -0x60(%rbp)
callq 0x169b0
movq %rax, %rcx
movq -0xe0(%rbp), %rax
movq %rcx, -0x68(%rbp)
movq %rax, -0x70(%rbp)
movq -0x60(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq -0x70(%rbp), %rdx
callq 0x144e0
jmp 0x141ee
movl $0x0, -0x80(%rbp)
leaq -0x58(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x88(%rbp), %rdi
callq 0x16980
movq %rax, -0x90(%rbp)
movq -0x88(%rbp), %rdi
callq 0x169b0
movq %rax, -0x98(%rbp)
leaq -0x90(%rbp), %rdi
leaq -0x98(%rbp), %rsi
callq 0x169e0
testb $0x1, %al
jne 0x14242
jmp 0x1431f
leaq -0x90(%rbp), %rdi
callq 0x16a20
movq -0xe0(%rbp), %rdi
movq (%rax), %rax
movq %rax, -0xa0(%rbp)
movq -0xa0(%rbp), %rax
movq (%rax), %rsi
movl -0x1c(%rbp), %edx
decl %edx
movl -0x24(%rbp), %ecx
negl %ecx
movl -0x20(%rbp), %r8d
negl %r8d
callq 0x14080
movl %eax, -0xec(%rbp)
jmp 0x14287
movl -0xec(%rbp), %eax
negl %eax
movl %eax, -0xa4(%rbp)
leaq -0x3c(%rbp), %rdi
leaq -0xa4(%rbp), %rsi
callq 0x16a40
movq %rax, -0xf8(%rbp)
jmp 0x142ae
movq -0xf8(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x3c(%rbp)
leaq -0x20(%rbp), %rdi
leaq -0xa4(%rbp), %rsi
callq 0x16a40
movq %rax, -0x100(%rbp)
jmp 0x142d3
movq -0x100(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x20(%rbp)
movl -0x80(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x80(%rbp)
movl -0x20(%rbp), %eax
cmpl -0x24(%rbp), %eax
jl 0x1430c
jmp 0x1431f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x16c10
jmp 0x14462
jmp 0x1430e
leaq -0x90(%rbp), %rdi
callq 0x16a80
jmp 0x14226
leaq -0x58(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0xb0(%rbp), %rdi
callq 0x16980
movq %rax, -0xb8(%rbp)
movq -0xb0(%rbp), %rdi
callq 0x169b0
movq %rax, -0xc0(%rbp)
leaq -0xb8(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x169e0
testb $0x1, %al
jne 0x14369
jmp 0x143c0
leaq -0xb8(%rbp), %rdi
callq 0x16a20
movq (%rax), %rax
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
movq %rax, -0x108(%rbp)
cmpq $0x0, %rax
je 0x143b0
movq -0x108(%rbp), %rdi
callq 0x13580
movq -0x108(%rbp), %rdi
movl $0x58, %esi
callq 0x3240
jmp 0x143b2
leaq -0xb8(%rbp), %rdi
callq 0x16a80
jmp 0x14350
movl -0x3c(%rbp), %eax
movl %eax, -0xd4(%rbp)
movl -0x1c(%rbp), %eax
movl %eax, -0xd0(%rbp)
movl $0x0, -0xcc(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x28(%rbp), %eax
jg 0x143f0
movl $0x2, -0xcc(%rbp)
jmp 0x14410
movl -0x3c(%rbp), %eax
cmpl -0x24(%rbp), %eax
jl 0x14404
movl $0x1, -0xcc(%rbp)
jmp 0x1440e
movl $0x0, -0xcc(%rbp)
jmp 0x14410
movq -0xe0(%rbp), %rdi
addq $0x8, %rdi
leaq -0x2c(%rbp), %rsi
callq 0x16ca0
movq %rax, -0x110(%rbp)
jmp 0x1442d
movq -0x110(%rbp), %rax
movq -0xd4(%rbp), %rcx
movq %rcx, (%rax)
movl -0xcc(%rbp), %ecx
movl %ecx, 0x8(%rax)
movl -0x3c(%rbp), %eax
movl %eax, -0x4(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x16c10
movl -0x4(%rbp), %eax
addq $0x110, %rsp            # imm = 0x110
popq %rbp
retq
movq -0x78(%rbp), %rdi
callq 0x33c0
nopl (%rax,%rax)