// File: ATOMIC-LICHESS[P]ATOMKRAFT/position.cpp
// Function: Position::move_is_legal(Move, unsigned long) const
bool Position::move_is_legal(const Move m, Bitboard pinned) const {
  assert(is_ok());
  assert(pinned == pinned_pieces(sideToMove));
  NEW // don't test that since it might be a tested tt
  //NEW assert(color_of_piece_on(move_from(m)) != COLOR_NONE);

  Color us = sideToMove;
  Color them = opposite_color(sideToMove);
  Square from = move_from(m);
  Square to = move_to(m);
  Piece pc = piece_on(from);

  // Use a slower but simpler function for uncommon cases
  if (move_is_special(m))
      return move_is_legal(m);

  // If the from square is not occupied by a piece belonging to the side to
  // move, the move is obviously not legal.
  if (color_of_piece(pc) != us)
      return false;

  // The destination square cannot be occupied by a friendly piece
  if (color_of_piece_on(to) == us)
      return false;

  // Handle the special case of a pawn move
  if (type_of_piece(pc) == PAWN)
  {
      // Move direction must be compatible with pawn color
      int direction = to - from;
      if ((us == WHITE) != (direction > 0))
          return false;

      // We have already handled promotion moves, so destination
      // cannot be on the 8/1th rank.
      OLD if (square_rank(to) == RANK_8 || square_rank(to) == RANK_1) return false;
      
      STARTNEW
      // capture moves of pawns to the relative 8th rank are no longer special
      if ((square_rank(to) == RANK_8 || square_rank(to) == RANK_1) && color_of_piece_on(to) != them)
    	  return false;
      ENDNEW

      // Proceed according to the square delta between the origin and
      // destination squares.
      switch (direction)
      {
      case DELTA_NW:
      case DELTA_NE:
      case DELTA_SW:
      case DELTA_SE:
      // Capture. The destination square must be occupied by an enemy
      // piece (en passant captures was handled earlier).
          if (color_of_piece_on(to) != them)
              return false;
          break;

      case DELTA_N:
      case DELTA_S:
      // Pawn push. The destination square must be empty.
          if (!square_is_empty(to))
              return false;
          break;

      case DELTA_NN:
      // Double white pawn push. The destination square must be on the fourth
      // rank, and both the destination square and the square between the
      // source and destination squares must be empty.
      if (   square_rank(to) != RANK_4
          || !square_is_empty(to)
          || !square_is_empty(from + DELTA_N))
          return false;
          break;

      case DELTA_SS:
      // Double black pawn push. The destination square must be on the fifth
      // rank, and both the destination square and the square between the
      // source and destination squares must be empty.
          if (   square_rank(to) != RANK_5
              || !square_is_empty(to)
              || !square_is_empty(from + DELTA_S))
              return false;
          break;

      default:
          return false;
      }
  }
  else if (!bit_is_set(attacks_from(pc, from), to))
      return false;

  STARTOLD
  // The move is pseudo-legal, check if it is also legal
  return in_check() ? pl_move_is_evasion(m, pinned) : pl_move_is_legal(m, pinned);
  ENDOLD
  
  STARTNEW
  // The move is pseudo-legal, check if it is also legal
  // legal capture moves are not recognized by pl_move_is_evasion
  // king moves to opponent king as an evasion are recognized by pl_move_is_evasion
  // since it calls pl_move_is_legal if king moves
  // TODO: adjust pl_move_is_evasion, the way we do it here is slow
  if (type_of_piece_on(to) == PIECE_TYPE_NONE) {
	  // non capture move
	  return in_check() ? pl_move_is_evasion(m, pinned) : pl_move_is_legal(m, pinned);
  } else {
	  // capture move
	  return pl_move_is_legal(m, pinned);
  }

// Assembly:
subq $0x58, %rsp
movq %rdi, 0x48(%rsp)
movl %esi, 0x44(%rsp)
movq %rdx, 0x38(%rsp)
movq 0x48(%rsp), %rax
movq %rax, 0x18(%rsp)
movl 0x1090(%rax), %ecx
movl %ecx, 0x34(%rsp)
movl 0x1090(%rax), %edi
callq 0x122b0
movl %eax, 0x30(%rsp)
movl 0x44(%rsp), %edi
callq 0xf680
movl %eax, 0x2c(%rsp)
movl 0x44(%rsp), %edi
callq 0xf690
movq 0x18(%rsp), %rdi
movl %eax, 0x28(%rsp)
movl 0x2c(%rsp), %esi
callq 0xf530
movl %eax, 0x24(%rsp)
movl 0x44(%rsp), %edi
callq 0x3e710
testb $0x1, %al
jne 0x397b0
jmp 0x397c9
movq 0x18(%rsp), %rdi
movl 0x44(%rsp), %esi
callq 0x39680
andb $0x1, %al
movb %al, 0x57(%rsp)
jmp 0x39a3f
movl 0x24(%rsp), %edi
callq 0x3e730
cmpl 0x34(%rsp), %eax
je 0x397e2
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
movq 0x18(%rsp), %rdi
movl 0x28(%rsp), %esi
callq 0x3df80
cmpl 0x34(%rsp), %eax
jne 0x39800
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
movl 0x24(%rsp), %edi
callq 0x12990
cmpl $0x1, %eax
jne 0x3999a
movl 0x28(%rsp), %edi
movl 0x2c(%rsp), %esi
callq 0xe9c0
movl %eax, 0x20(%rsp)
cmpl $0x0, 0x34(%rsp)
sete %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, 0x20(%rsp)
setg %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
je 0x3984c
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
movl 0x28(%rsp), %edi
callq 0xce40
cmpl $0x7, %eax
je 0x39868
movl 0x28(%rsp), %edi
callq 0xce40
cmpl $0x0, %eax
jne 0x39886
movq 0x18(%rsp), %rdi
movl 0x28(%rsp), %esi
callq 0x3df80
cmpl 0x30(%rsp), %eax
je 0x39886
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
movl 0x20(%rsp), %eax
addl $0x10, %eax
movl %eax, %ecx
movq %rcx, 0x10(%rsp)
subl $0x20, %eax
ja 0x3998e
movq 0x10(%rsp), %rax
leaq 0x21387(%rip), %rcx     # 0x5ac30
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x18(%rsp), %rdi
movl 0x28(%rsp), %esi
callq 0x3df80
cmpl 0x30(%rsp), %eax
je 0x398d0
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
jmp 0x39998
movq 0x18(%rsp), %rdi
movl 0x28(%rsp), %esi
callq 0x29b30
testb $0x1, %al
jne 0x398f1
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
jmp 0x39998
movl 0x28(%rsp), %edi
callq 0xce40
cmpl $0x3, %eax
jne 0x39936
movq 0x18(%rsp), %rdi
movl 0x28(%rsp), %esi
callq 0x29b30
testb $0x1, %al
jne 0x39918
jmp 0x39936
movl 0x2c(%rsp), %edi
movl $0x8, %esi
callq 0xd780
movq 0x18(%rsp), %rdi
movl %eax, %esi
callq 0x29b30
testb $0x1, %al
jne 0x39940
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
jmp 0x39998
movl 0x28(%rsp), %edi
callq 0xce40
cmpl $0x4, %eax
jne 0x39982
movq 0x18(%rsp), %rdi
movl 0x28(%rsp), %esi
callq 0x29b30
testb $0x1, %al
jne 0x39964
jmp 0x39982
movl 0x2c(%rsp), %edi
movl $0xfffffff8, %esi       # imm = 0xFFFFFFF8
callq 0xd780
movq 0x18(%rsp), %rdi
movl %eax, %esi
callq 0x29b30
testb $0x1, %al
jne 0x3998c
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
jmp 0x39998
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
jmp 0x399c7
movq 0x18(%rsp), %rdi
movl 0x24(%rsp), %esi
movl 0x2c(%rsp), %edx
callq 0x38b30
movq %rax, %rdi
movl 0x28(%rsp), %esi
callq 0xd760
cmpq $0x0, %rax
jne 0x399c5
movb $0x0, 0x57(%rsp)
jmp 0x39a3f
jmp 0x399c7
movq 0x18(%rsp), %rdi
movl 0x28(%rsp), %esi
callq 0x11f10
cmpl $0x0, %eax
jne 0x39a26
movq 0x18(%rsp), %rdi
callq 0x2e600
testb $0x1, %al
jne 0x399ea
jmp 0x39a03
movq 0x18(%rsp), %rdi
movl 0x44(%rsp), %esi
movq 0x38(%rsp), %rdx
callq 0x39540
movb %al, 0xf(%rsp)
jmp 0x39a1a
movq 0x18(%rsp), %rdi
movl 0x44(%rsp), %esi
movq 0x38(%rsp), %rdx
callq 0x38e80
movb %al, 0xf(%rsp)
movb 0xf(%rsp), %al
andb $0x1, %al
movb %al, 0x57(%rsp)
jmp 0x39a3f
movq 0x18(%rsp), %rdi
movl 0x44(%rsp), %esi
movq 0x38(%rsp), %rdx
callq 0x38e80
andb $0x1, %al
movb %al, 0x57(%rsp)
movb 0x57(%rsp), %al
andb $0x1, %al
addq $0x58, %rsp
retq
nopw (%rax,%rax)