// File: /workspace/github_cpp_makefile_star2_O2/codeandkey[P]neocortex/src/position.cpp
// Function: neocortex::Position::make_move(neocortex::Move)
bool Position::make_move(Move move) {
	assert(!test_check(!color_to_move));

	State last_state = ply.back();
	ply.push_back(last_state);

	State& next_state = ply.back();

	next_state.last_move = move;
	
	if (color_to_move == piece::BLACK) {
		next_state.fullmove_number++;
	}

	next_state.halfmove_clock++;

	next_state.en_passant_square = square::null;
	next_state.captured_piece = piece::null;
	next_state.captured_square = square::null;
	next_state.was_en_passant = false;
	next_state.was_castle = false;

	/* End early on null move, flip color and update zobrist as well. */
	if (move == Move::null) {
		bool ret = !check(); // null moves illegal in check
		color_to_move = !color_to_move;

		next_state.key = 0;
		next_state.key ^= board.get_tt_key();
		next_state.key ^= zobrist::en_passant(next_state.en_passant_square);
		next_state.key ^= zobrist::castle(next_state.castle_rights);

		if (color_to_move == piece::BLACK) {
			next_state.key ^= zobrist::black_to_move();
		}

		return ret;
	}

	int dst_piece = board.get_piece(move.dst());
	int src_piece = board.remove(move.src());

	assert(piece::color(src_piece) == color_to_move);

	if (piece::type(src_piece) == piece::PAWN) {
		next_state.halfmove_clock = 0;
	}

	/* Check for EP capture */
	if (piece::type(src_piece) == piece::PAWN && move.dst() == last_state.en_passant_square) {
		/* EP, need to remove piece */
		int adv_dir = (color_to_move == piece::WHITE) ? NORTH : SOUTH;
		int capture_square = last_state.en_passant_square - adv_dir;
 		int removed = board.remove(capture_square);

		next_state.captured_piece = removed;
		next_state.captured_square = capture_square;
		next_state.halfmove_clock = 0;
		next_state.was_en_passant = true;

		assert(piece::type(removed) == piece::PAWN);
	}

	/* Move rook also if castling */
	if (piece::type(src_piece) == piece::KING && abs(square::file(move.src()) - square::file(move.dst())) > 1) {
		int is_ks = move.dst() > move.src();
		int castle_rank = (color_to_move == piece::WHITE) ? 0 : 7;
		int rook_file = is_ks ? 7 : 0;
		int rook_dstfile = is_ks ? 5 : 3;

		int rook_src = square::at(castle_rank, rook_file);
		int rook_dst = square::at(castle_rank, rook_dstfile);

		board.place(rook_dst, board.remove(rook_src));

		next_state.was_castle = true;
	}

	/* Test if destination is occupied */
	if (piece::is_valid(dst_piece)) {
		/* Normal capture */
		next_state.captured_piece = board.replace(move.dst(), src_piece);
		next_state.captured_square = move.dst();
		next_state.halfmove_clock = 0;

		/* no king captures */
		assert(piece::type(next_state.captured_piece) != piece::KING);
	} else {
		/* Quiet */
		board.place(move.dst(), src_piece);
	}

	/* Apply promotion */
	if (piece::is_type(move.ptype())) {
		board.replace(move.dst(), piece::make_piece(color_to_move, move.ptype()));
	}

	/* Revoke castling rights */
	if (piece::type(src_piece) == piece::KING) {
		int rights = (color_to_move == piece::WHITE) ? 0x3 : 0xC;
		next_state.castle_rights &= ~rights;
	}

	static const bitboard white_ks_revoke = bb::mask(square::at(0, 4)) | bb::mask(square::at(0, 7));
	static const bitboard white_qs_revoke = bb::mask(square::at(0, 4)) | bb::mask(square::at(0, 0));
	static const bitboard black_ks_revoke = bb::mask(square::at(7, 4)) | bb::mask(square::at(7, 7));
	static const bitboard black_qs_revoke = bb::mask(square::at(7, 4)) | bb::mask(square::at(7, 0));

	bitboard src_dst_mask = bb::mask(move.src()) | bb::mask(move.dst());

	if (src_dst_mask & white_ks_revoke) {
		next_state.castle_rights &= ~CASTLE_WHITE_K;
	}

	if (src_dst_mask & white_qs_revoke) {
		next_state.castle_rights &= ~CASTLE_WHITE_Q;
	}

	if (src_dst_mask & black_ks_revoke) {
		next_state.castle_rights &= ~CASTLE_BLACK_K;
	}

	if (src_dst_mask & black_qs_revoke) {
		next_state.castle_rights &= ~CASTLE_BLACK_Q;
	}

	/* Update en passant */
	if (piece::type(src_piece) == piece::PAWN && abs(square::rank(move.dst()) - square::rank(move.src())) > 1) {
		int epsq = move.dst() + ((color_to_move == piece::WHITE) ? SOUTH : NORTH);
		next_state.en_passant_square = epsq;

		if (color_to_move == piece::WHITE) {
			assert(epsq >= 16 && epsq <= 23);
		}
		else {
			assert(epsq >= 40 && epsq <= 47);
		}
	}

	/* Flip color to move */
	color_to_move = !color_to_move;

	/* Update zobrist key */
	next_state.key = 0;
	next_state.key ^= board.get_tt_key();
	next_state.key ^= zobrist::en_passant(next_state.en_passant_square);
	next_state.key ^= zobrist::castle(next_state.castle_rights);

	next_state.in_check = test_check(color_to_move);

	if (color_to_move == piece::BLACK) {
		next_state.key ^= zobrist::black_to_move();
	}

	/* Check that king is not in attack */
	return !test_check(!color_to_move);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rdi, %rbx
movq %rsi, (%rsp)
movl %edx, 0x8(%rsp)
xorl %esi, %esi
cmpl $0x0, 0x170(%rdi)
sete %sil
callq 0xce96
testb %al, %al
jne 0x86bc
leaq 0x158(%rbx), %rdi
movq 0x160(%rbx), %rax
movq -0x8(%rax), %rcx
leaq 0x10(%rsp), %rsi
movq %rcx, 0x30(%rsi)
movups -0x38(%rax), %xmm0
movups -0x28(%rax), %xmm1
movups -0x18(%rax), %xmm2
movaps %xmm2, 0x20(%rsi)
movaps %xmm1, 0x10(%rsi)
movaps %xmm0, (%rsi)
callq 0xce44
movq 0x160(%rbx), %r13
movl 0x8(%rsp), %eax
movl %eax, -0x30(%r13)
movq (%rsp), %rax
movq %rax, -0x38(%r13)
cmpl $0x1, 0x170(%rbx)
jne 0x82e6
incl -0x18(%r13)
incl -0x1c(%r13)
orl $-0x1, -0x2c(%r13)
orq $-0x1, -0x24(%r13)
andw $0x0, -0x10(%r13)
leaq 0x1e8c7(%rip), %rsi     # 0x26bc8
movq %rsp, %rdi
callq 0x6fee
testb %al, %al
je 0x836e
movq 0x150(%rbx), %rax
movq 0x160(%rbx), %rcx
cmpl $0x0, -0x14(%rcx)
setne %bpl
xorl %ecx, %ecx
cmpl $0x0, 0x170(%rbx)
sete %cl
movl %ecx, 0x170(%rbx)
movq %rax, -0x8(%r13)
movl -0x2c(%r13), %edi
callq 0x1279d
xorq %rax, -0x8(%r13)
movl -0x28(%r13), %edi
callq 0x12767
xorq %rax, -0x8(%r13)
cmpl $0x1, 0x170(%rbx)
jne 0x86a7
callq 0x127e1
xorq %rax, -0x8(%r13)
jmp 0x86a7
movslq 0x4(%rsp), %rax
movl 0x48(%rbx,%rax,4), %r15d
movl (%rsp), %esi
movq %rbx, %rdi
callq 0x5b86
movl %eax, %ebp
movl %eax, %edi
callq 0x6417
cmpl 0x170(%rbx), %eax
jne 0x86db
movl %ebp, %edi
callq 0x63ef
testl %eax, %eax
jne 0x83a8
andl $0x0, -0x1c(%r13)
movl %ebp, %edi
callq 0x63ef
testl %eax, %eax
jne 0x8400
movl 0x4(%rsp), %eax
cmpl 0x1c(%rsp), %eax
jne 0x8400
xorl %ecx, %ecx
cmpl $0x0, 0x170(%rbx)
setne %cl
shll $0x4, %ecx
leal (%rcx,%rax), %r14d
addl $-0x8, %r14d
movq %rbx, %rdi
movl %r14d, %esi
callq 0x5b86
movl %eax, -0x24(%r13)
movl %r14d, -0x20(%r13)
andl $0x0, -0x1c(%r13)
movb $0x1, -0x10(%r13)
movl %eax, %edi
callq 0x63ef
testl %eax, %eax
jne 0x87c6
movl %ebp, %edi
callq 0x63ef
cmpl $0x5, %eax
jne 0x849f
movl (%rsp), %edi
callq 0x50da
movl %eax, %r14d
movl 0x4(%rsp), %edi
callq 0x50da
subl %eax, %r14d
movl %r14d, %eax
negl %eax
cmovsl %r14d, %eax
cmpl $0x2, %eax
jb 0x849f
movl 0x4(%rsp), %eax
movl 0x170(%rbx), %r14d
testl %r14d, %r14d
pushq $0x7
popq %rcx
cmovnel %ecx, %r14d
xorl %esi, %esi
xorl %edx, %edx
cmpl (%rsp), %eax
setg %dl
cmovgl %ecx, %esi
movl %r15d, 0xc(%rsp)
leal 0x3(,%rdx,2), %r15d
movl %r14d, %edi
callq 0x5131
movl %eax, %r12d
movl %r14d, %edi
movl %r15d, %esi
movl 0xc(%rsp), %r15d
callq 0x5131
movl %eax, %r14d
movq %rbx, %rdi
movl %r12d, %esi
callq 0x5b86
movq %rbx, %rdi
movl %r14d, %esi
movl %eax, %edx
callq 0x5a44
movb $0x1, -0xf(%r13)
movl 0x4(%rsp), %esi
movq %rbx, %rdi
movl %ebp, %edx
cmpl $0xb, %r15d
ja 0x84ef
callq 0x5c54
movl %eax, -0x24(%r13)
movl 0x4(%rsp), %ecx
movl %ecx, -0x20(%r13)
andl $0x0, -0x1c(%r13)
movl %eax, %edi
callq 0x63ef
cmpl $0x5, %eax
jne 0x84f4
leaq 0xc90c(%rip), %rdi      # 0x14de3
leaq 0xc837(%rip), %rsi      # 0x14d15
leaq 0xc887(%rip), %rcx      # 0x14d6c
movl $0xdd, %edx
callq 0x41f0
callq 0x5a44
movl 0x8(%rsp), %esi
cmpl $0x5, %esi
ja 0x851a
movl 0x4(%rsp), %r14d
movl 0x170(%rbx), %edi
callq 0x7ae8
movq %rbx, %rdi
movl %r14d, %esi
movl %eax, %edx
callq 0x5c54
movl %ebp, %edi
callq 0x63ef
cmpl $0x5, %eax
jne 0x853c
xorl %eax, %eax
cmpl $0x0, 0x170(%rbx)
sete %al
leal (%rax,%rax,8), %eax
addl $-0xd, %eax
andl %eax, -0x28(%r13)
movb 0x1e6f6(%rip), %al      # 0x26c38
testb %al, %al
je 0x86fa
movb 0x1e6f8(%rip), %al      # 0x26c48
testb %al, %al
je 0x872a
movb 0x1e6fa(%rip), %al      # 0x26c58
testb %al, %al
je 0x875a
movb 0x1e6fc(%rip), %al      # 0x26c68
testb %al, %al
je 0x8790
movl (%rsp), %edi
callq 0x5103
movq %rax, %r14
movl 0x4(%rsp), %edi
callq 0x5103
orq %r14, %rax
testq %rax, 0x1e69e(%rip)     # 0x26c30
je 0x8599
andb $-0x2, -0x28(%r13)
testq %rax, 0x1e6a0(%rip)     # 0x26c40
je 0x85a7
andb $-0x3, -0x28(%r13)
testq %rax, 0x1e6a2(%rip)     # 0x26c50
je 0x85b5
andb $-0x5, -0x28(%r13)
testq %rax, 0x1e6a4(%rip)     # 0x26c60
je 0x85c3
andb $-0x9, -0x28(%r13)
movl %ebp, %edi
callq 0x63ef
testl %eax, %eax
je 0x85d6
movl 0x170(%rbx), %eax
jmp 0x8634
movl 0x4(%rsp), %edi
callq 0x50b1
movl %eax, %ebp
movl (%rsp), %edi
callq 0x50b1
subl %eax, %ebp
movl %ebp, %ecx
negl %ecx
cmovsl %ebp, %ecx
movl 0x170(%rbx), %eax
cmpl $0x2, %ecx
jb 0x8634
movl 0x4(%rsp), %ecx
xorl %edx, %edx
testl %eax, %eax
setne %dl
shll $0x4, %edx
addl %edx, %ecx
addl $-0x8, %ecx
movl %ecx, -0x2c(%r13)
andl $-0x8, %ecx
testl %eax, %eax
je 0x8629
cmpl $0x28, %ecx
jne 0x87e5
pushq $0x1
popq %rax
jmp 0x8634
xorl %eax, %eax
cmpl $0x10, %ecx
jne 0x8804
xorl %ecx, %ecx
testl %eax, %eax
sete %cl
movl %ecx, 0x170(%rbx)
movq 0x150(%rbx), %rax
movq %rax, -0x8(%r13)
movl -0x2c(%r13), %edi
callq 0x1279d
xorq %rax, -0x8(%r13)
movl -0x28(%r13), %edi
callq 0x12767
xorq %rax, -0x8(%r13)
movl 0x170(%rbx), %esi
movq %rbx, %rdi
callq 0xce96
movzbl %al, %eax
movl %eax, -0x14(%r13)
movl 0x170(%rbx), %eax
cmpl $0x1, %eax
jne 0x8695
callq 0x127e1
xorq %rax, -0x8(%r13)
movl 0x170(%rbx), %eax
xorl %esi, %esi
testl %eax, %eax
sete %sil
movq %rbx, %rdi
callq 0xce96
movl %eax, %ebp
xorb $0x1, %bpl
movl %ebp, %eax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0xc68d(%rip), %rdi      # 0x14d50
leaq 0xc64b(%rip), %rsi      # 0x14d15
leaq 0xc69b(%rip), %rcx      # 0x14d6c
movl $0x88, %edx
callq 0x41f0
leaq 0xc6b4(%rip), %rdi      # 0x14d96
leaq 0xc62c(%rip), %rsi      # 0x14d15
leaq 0xc67c(%rip), %rcx      # 0x14d6c
movl $0xb1, %edx
callq 0x41f0
leaq 0x1e537(%rip), %rdi     # 0x26c38
callq 0x4570
testl %eax, %eax
je 0x854a
movq $0x90, 0x1e517(%rip) # 0x26c30
leaq 0x1e518(%rip), %rdi     # 0x26c38
callq 0x41e0
jmp 0x854a
leaq 0x1e517(%rip), %rdi     # 0x26c48
callq 0x4570
testl %eax, %eax
je 0x8558
movq $0x11, 0x1e4f7(%rip) # 0x26c40
leaq 0x1e4f8(%rip), %rdi     # 0x26c48
callq 0x41e0
jmp 0x8558
leaq 0x1e4f7(%rip), %rdi     # 0x26c58
callq 0x4570
testl %eax, %eax
je 0x8566
movabsq $-0x7000000000000000, %rax # imm = 0x9000000000000000
movq %rax, 0x1e4d1(%rip)     # 0x26c50
leaq 0x1e4d2(%rip), %rdi     # 0x26c58
callq 0x41e0
jmp 0x8566
leaq 0x1e4d1(%rip), %rdi     # 0x26c68
callq 0x4570
testl %eax, %eax
je 0x8574
movabsq $0x1100000000000000, %rax # imm = 0x1100000000000000
movq %rax, 0x1e4ab(%rip)     # 0x26c60
leaq 0x1e4ac(%rip), %rdi     # 0x26c68
callq 0x41e0
jmp 0x8574
leaq 0xc5f2(%rip), %rdi      # 0x14dbf
leaq 0xc541(%rip), %rsi      # 0x14d15
leaq 0xc591(%rip), %rcx      # 0x14d6c
movl $0xc3, %edx
callq 0x41f0
leaq 0xc646(%rip), %rdi      # 0x14e32
leaq 0xc522(%rip), %rsi      # 0x14d15
leaq 0xc572(%rip), %rcx      # 0x14d6c
movl $0x10e, %edx            # imm = 0x10E
callq 0x41f0
leaq 0xc60e(%rip), %rdi      # 0x14e19
leaq 0xc503(%rip), %rsi      # 0x14d15
leaq 0xc553(%rip), %rcx      # 0x14d6c
movl $0x10b, %edx            # imm = 0x10B
callq 0x41f0
nop