// File: /workspace/github_cpp_makefile_star2_O1/tlaloc1313[P]chess-project/main.cpp
// Function: main
int main(int argc, char const *argv[]) {

  //Clear screen
  for (int i = 0; i < 10; i++) {
    cout<<"\n\n\n\n\n\n\n\n\n\n";
  }

  cout<<"Welcome to Chess++, a chess interface developed in C++11.\n\nPress Enter/Return to continue...";
  cin.get();

  //Set first turn to white
  bool whiteTurn=1;
  int gameEnd = 0;
  char drawAccept = ' ';
  // Setup a game
  Board* gameBoard = new Board();
  setup(gameBoard);

	//Records if a player has used a cheat code
	bool whiteCheat = 0;
	bool blackCheat = 0;

  int inCheck = 0;
  int success, startPos, endPos;

  while (gameEnd == 0) {

    //50 Move Rules
    if (gameBoard->getMovesSince()>100) {
      cout << "50 Move Rule - Game is Drawn\n";
      gameEnd = 3;
      break;
    }

    draw(gameBoard, whiteTurn);
    //Display whose turn it is
    if (whiteTurn) {
      cout << "White to move:"<< std::endl;
    } else {
      cout<<"Black to move:" << std::endl;
    }

    //Assume move is unsuccessful
    success = 0;
    //Keep asking for moves until successful
    while (success !=1){
      cout << "From: ";
        startPos = inputFunc();
        if (startPos == -1){ // In case of invalid iostream (end of a test file)
          return 0;
        }

			//Cheat code - creates a queen of the current player in a random, unoccupied square
			//There is a 1 in 10 chance to create an opponent's queen
			if (startPos == 1000) {
				if ((whiteTurn && whiteCheat == 0) || (!whiteTurn && blackCheat == 0)) {
					unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();	//Current time in ms
					std::default_random_engine generator (seed);	//Generates uniformly distributed numbers
					std::uniform_int_distribution<int> sqrDist(0,63);	//Uniform int distribution from 0-63
					std::uniform_int_distribution<int> failDist(0,9);	//Uniform int distribution from 0-9
					bool free = 0;
					while (!free) {
            //Generates a number and checks that the square is free
						int randNum = sqrDist(generator);
						if (gameBoard->spaceOccupied(randNum) == 0) {
							free = 1;
							if (failDist(generator) == 0) {
								gameBoard->addPiece('q', randNum, !whiteTurn);	//Adds opponent's queen
								cout << "Bad luck...\n";
							} else {
								gameBoard->addPiece('q', randNum, whiteTurn);		//Adds player's queen
							}
							//Uses the cheat of the current player
							if (whiteTurn) {
								whiteCheat = 1;
							} else {
								blackCheat = 1;
							}
							draw(gameBoard, whiteTurn);
						}
					}
					break;
				} else {
					cout << "Nice try 😉\n";
					continue;
				}
			}

      //Resignation or Draw Offers:
      if (startPos == 800){ //Resignation
        if (whiteTurn){
          cout << "Black wins by resignation!\n";
          gameEnd = 2;
        } else {
          cout << "White wins by resignation!\n";
          gameEnd =  1;
        }
        break;
      }
      if (startPos == 801){ // Draw offer
        if (whiteTurn){
          cout << "White offers a draw. Black, do you accept? (y/n) ";
          cin >> drawAccept;
          if (drawAccept == 'y'){
            cout << "The game is drawn!\n";
            gameEnd = 3;
            break;
          } else {
            continue;
          }
        } else {
          cout << "Black offers a draw. White, do you accept? (y/n) ";
          cin >> drawAccept;
          if (drawAccept == 'y'){
            cout << "The game is drawn!\n";
            gameEnd = 3;
            break;
          } else {
            continue;
          }
        }
      }

      cout << "To: ";
      endPos = inputFunc();

      //CASTLING -- Returns -5 if castling through check
      if (startPos == 69) {
        success = 0; //Castling fails by default

        switch (endPos){

          //White castling queenside
          case 16:
            if (whiteTurn == 1){
              success = gameBoard->castle(1, 0);
            }
          break;

          //Black castling queenside
          case 23:
            if (whiteTurn == 0){
              success = gameBoard->castle(0, 0);
            }
          break;

          //White castling kingside
          case 48:
            if (whiteTurn == 1){
              success = gameBoard->castle(1, 1);
            }
          break;

          //Black castling kingside
          case 55:
            if (whiteTurn == 0){
              success = gameBoard->castle(0, 1);
            }
          break;
        }
      } else { //If no special move is being made, attempt to make normal move

        //Section checks if the move results in the player being in check.
        //Creates a copy of the board
				Board* gameBoardCopy = new Board(gameBoard->getPieceArray(), gameBoard->getActiveArray(), gameBoard->getPastPieces(), gameBoard->getPastMoves());
        //Makes the move on the copied board
      	success = gameBoardCopy->movePiece(startPos, endPos, whiteTurn);
        //Checks that the piece isn't in check after moving then deletes copy.
				if (success >= 1) {
					inCheck = gameBoardCopy->checkCheck(-1, -1);
				}
				delete gameBoardCopy;

				if (whiteTurn && (inCheck == 1 || inCheck == 3)) {
					std::cout << "White is in check. ";
					success = 0;
					inCheck = 0;
				} else if (!whiteTurn && (inCheck == 2 || inCheck == 3)) {
					std::cout << "Black is in check. ";
					success = 0;
					inCheck = 0;
				} else {
					gameBoard->movePiece(startPos, endPos, whiteTurn);
				}
      }

      // This section provides specific error messages in some cases.
      switch (success) {
        case 0:
        cout << "Invalid Move\n";
        break;
        case -5:
        cout << "Invalid Move - Cannot castle through, out of, or into check\n";
        break;
        case -4:
        cout << "Invalid Move - Illegal Castling\n";
        break;
      }
    }
    whiteTurn= !whiteTurn;
  }
  delete gameBoard;
  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movl $0xa, %r15d
movq 0x6bb3(%rip), %rbx      # 0x8fd0
leaq 0x3be0(%rip), %r14      # 0x6004
movl $0xa, %edx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2120
decl %r15d
jne 0x2424
movq 0x6b90(%rip), %r14      # 0x8fd0
leaq 0x3bc8(%rip), %rsi      # 0x600f
movl $0x5c, %edx
movq %r14, %rdi
callq 0x2120
movq 0x6b85(%rip), %rdi      # 0x8fe0
callq 0x2140
movb $0x20, -0x29(%rbp)
movl $0x280, %edi            # imm = 0x280
callq 0x2110
movq %rax, %rbx
movq %rax, %rdi
callq 0x3a3c
movq %rbx, %rdi
callq 0x3154
movl $0x0, -0x30(%rbp)
movb $0x1, %r13b
movl $0x0, -0x44(%rbp)
movl $0x0, -0x40(%rbp)
movq %rbx, -0x38(%rbp)
movq %rbx, %rdi
callq 0x4e94
cmpl $0x65, %eax
jge 0x296a
movzbl %r13b, %r15d
movl %r15d, %esi
andl $0x1, %esi
movq %rbx, %rdi
movl %esi, -0x3c(%rbp)
callq 0x2cf2
movl %r15d, -0x64(%rbp)
testb $0x1, %r15b
leaq 0x3bc7(%rip), %rsi      # 0x6099
leaq 0x3bb1(%rip), %rax      # 0x608a
cmovneq %rax, %rsi
movzbl -0x40(%rbp), %eax
movzbl -0x44(%rbp), %r15d
cmovnel %eax, %r15d
movl $0xe, %edx
movq %r14, %rdi
callq 0x2120
movq (%r14), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %r14, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20a0
xorl %ebx, %ebx
movl $0x6, %edx
movq %r14, %rdi
leaq 0x3b79(%rip), %rsi      # 0x60a8
callq 0x2120
callq 0x32f8
movl %eax, %r12d
cmpl $0x3e7, %eax            # imm = 0x3E7
jg 0x2563
cmpl $0x321, %r12d           # imm = 0x321
jne 0x25c0
movl $0x31, %edx
movq %r14, %rdi
testb $0x1, %r13b
je 0x258c
leaq 0x3ba2(%rip), %rsi      # 0x6103
jmp 0x2593
cmpl $0x3e8, %r12d           # imm = 0x3E8
jne 0x25d7
testb $0x1, %r15b
je 0x2812
movl $0xe, %edx
movq %r14, %rdi
leaq 0x3b37(%rip), %rsi      # 0x60bc
callq 0x2120
jmp 0x25b2
leaq 0x3bb6(%rip), %rsi      # 0x6149
callq 0x2120
movq 0x6a41(%rip), %rdi      # 0x8fe0
leaq -0x29(%rbp), %rsi
callq 0x2150
cmpb $0x79, -0x29(%rbp)
je 0x2939
testb $0x1, %bl
je 0x2520
jmp 0x2935
cmpl $-0x1, %r12d
je 0x298b
cmpl $0x320, %r12d           # imm = 0x320
je 0x27f4
movl $0x4, %edx
movq %r14, %rdi
leaq 0x3b95(%rip), %rsi      # 0x617b
callq 0x2120
callq 0x32f8
cmpl $0x45, %r12d
jne 0x262b
xorl %ebx, %ebx
cmpl $0x2f, %eax
movq -0x38(%rbp), %rdi
jg 0x2716
cmpl $0x10, %eax
movl -0x30(%rbp), %ecx
je 0x2773
cmpl $0x17, %eax
jne 0x279c
testb $0x1, %r13b
jne 0x279c
xorl %esi, %esi
jmp 0x277e
movl %eax, -0x54(%rbp)
movl $0x280, %edi            # imm = 0x280
callq 0x2110
movq %rax, -0x50(%rbp)
movq -0x38(%rbp), %rbx
movq %rbx, %rdi
callq 0x4ea0
movq %rax, -0x60(%rbp)
movq %rbx, %rdi
callq 0x4eaa
movq %rax, -0x78(%rbp)
leaq -0xa0(%rbp), %rdi
movq %rbx, %rsi
callq 0x4eb8
movq %rbx, %rsi
leaq -0xb8(%rbp), %rbx
movq %rbx, %rdi
callq 0x4ed8
movq -0x50(%rbp), %rdi
movq -0x60(%rbp), %rsi
movq -0x78(%rbp), %rdx
leaq -0xa0(%rbp), %rcx
movq %rbx, %r8
callq 0x3a8c
movq -0xb8(%rbp), %rdi
testq %rdi, %rdi
je 0x26a5
callq 0x20f0
movq -0xa0(%rbp), %rdi
testq %rdi, %rdi
je 0x26b6
callq 0x20f0
movq -0x50(%rbp), %rbx
movq %rbx, %rdi
movl %r12d, %esi
movl -0x54(%rbp), %edx
movl -0x3c(%rbp), %ecx
callq 0x3d88
movl %eax, -0x60(%rbp)
testl %eax, %eax
jle 0x26e7
movq %rbx, %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x4298
movl %eax, -0x30(%rbp)
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
movl -0x30(%rbp), %ecx
movl %ecx, %eax
andl $-0x3, %eax
cmpl $0x1, %eax
sete %al
andb %r13b, %al
cmpb $0x1, %al
jne 0x272d
movl $0x13, %edx
movq %r14, %rdi
leaq 0x3a6c(%rip), %rsi      # 0x6180
jmp 0x2768
cmpl $0x30, %eax
movl -0x30(%rbp), %ecx
je 0x2782
cmpl $0x37, %eax
jne 0x279c
testb $0x1, %r13b
jne 0x279c
xorl %esi, %esi
jmp 0x278d
movl %ecx, %eax
andl $-0x2, %eax
cmpl $0x2, %eax
setne %al
orb %r13b, %al
testb $0x1, %al
je 0x2759
movq -0x38(%rbp), %rdi
movl %r12d, %esi
movl -0x54(%rbp), %edx
movl -0x3c(%rbp), %ecx
callq 0x3d88
movl -0x30(%rbp), %ecx
movl -0x60(%rbp), %ebx
jmp 0x279c
movl $0x13, %edx
movq %r14, %rdi
leaq 0x3a2c(%rip), %rsi      # 0x6194
callq 0x2120
xorl %ecx, %ecx
xorl %ebx, %ebx
jmp 0x279c
testb $0x1, %r13b
je 0x279c
movl $0x1, %esi
xorl %edx, %edx
jmp 0x2792
testb $0x1, %r13b
je 0x279c
movl $0x1, %esi
movl $0x1, %edx
callq 0x4b4c
movl -0x30(%rbp), %ecx
movl %eax, %ebx
cmpl $-0x5, %ebx
movl %ecx, -0x30(%rbp)
je 0x27cf
cmpl $-0x4, %ebx
je 0x27be
testl %ebx, %ebx
jne 0x27e3
movl $0xd, %edx
movq %r14, %rdi
leaq 0x39ec(%rip), %rsi      # 0x61a8
jmp 0x27de
movl $0x20, %edx
movq %r14, %rdi
leaq 0x3a26(%rip), %rsi      # 0x61f3
jmp 0x27de
movl $0x3c, %edx
movq %r14, %rdi
leaq 0x39d8(%rip), %rsi      # 0x61b6
callq 0x2120
cmpl $0x1, %ebx
sete %bl
jne 0x2520
jmp 0x2935
movl $0x1b, %edx
movq %r14, %rdi
testb $0x1, %r13b
je 0x294a
leaq 0x38be(%rip), %rsi      # 0x60cb
jmp 0x2951
callq 0x2040
movl %eax, %ecx
movq %rcx, %rax
movabsq $0x200000005, %rdx      # imm = 0x200000005
mulq %rdx
movq %rdx, %rax
shlq $0x1f, %rax
subq %rax, %rdx
leaq (%rcx,%rdx), %rax
cmpq $0x1, %rax
adcq %rcx, %rdx
movq %rdx, -0x70(%rbp)
movabsq $0x3f00000000, %rax     # imm = 0x3F00000000
movq %rax, -0x88(%rbp)
movabsq $0x900000000, %rax      # imm = 0x900000000
movq %rax, -0x80(%rbp)
movl %r13d, %eax
notb %al
movzbl %al, %eax
andl $0x1, %eax
movl %eax, -0x50(%rbp)
xorl %ebx, %ebx
leaq -0x70(%rbp), %rsi
leaq -0x88(%rbp), %rdi
movq %rdi, %rdx
movq %rsi, %r12
callq 0x29e8
movl %eax, %r15d
movq -0x38(%rbp), %rdi
movl %eax, %esi
callq 0x3d78
testb %al, %al
je 0x28a1
movq %r12, %rsi
jmp 0x292c
leaq -0x80(%rbp), %rdi
movq %r12, %rsi
movq %rdi, %rdx
callq 0x29e8
testl %eax, %eax
je 0x28cd
movq -0x38(%rbp), %rbx
movq %rbx, %rdi
movl $0x71, %esi
movl %r15d, %edx
movl -0x3c(%rbp), %ecx
callq 0x3c2c
jmp 0x28f8
movq -0x38(%rbp), %rbx
movq %rbx, %rdi
movl $0x71, %esi
movl %r15d, %edx
movl -0x50(%rbp), %ecx
callq 0x3c2c
movl $0xc, %edx
movq %r14, %rdi
leaq 0x37bc(%rip), %rsi      # 0x60af
callq 0x2120
movl -0x40(%rbp), %ecx
movzbl %cl, %ecx
testb $0x1, %r13b
movl $0x1, %eax
cmovnel %eax, %ecx
movl %ecx, -0x40(%rbp)
movl -0x44(%rbp), %ecx
movzbl %cl, %ecx
cmovel %eax, %ecx
movl %ecx, -0x44(%rbp)
movl -0x64(%rbp), %esi
andl %eax, %esi
movq %rbx, %rdi
callq 0x2cf2
movb $0x1, %bl
leaq -0x70(%rbp), %rsi
testb $0x1, %bl
je 0x2875
movb $0x1, %al
jmp 0x2958
movl $0x13, %edx
movq %r14, %rdi
leaq 0x37ed(%rip), %rsi      # 0x6135
jmp 0x2951
leaq 0x3796(%rip), %rsi      # 0x60e7
callq 0x2120
xorl %eax, %eax
movq -0x38(%rbp), %rbx
xorb $0x1, %r13b
testb %al, %al
jne 0x249d
jmp 0x2982
movq 0x665f(%rip), %rdi      # 0x8fd0
leaq 0x36f4(%rip), %rsi      # 0x606c
movl $0x1d, %edx
callq 0x2120
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
xorl %eax, %eax
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %r14
movq -0xb8(%rbp), %rdi
testq %rdi, %rdi
je 0x29b8
callq 0x20f0
jmp 0x29b8
movq %rax, %r14
movq -0xa0(%rbp), %rdi
testq %rdi, %rdi
je 0x29d7
callq 0x20f0
jmp 0x29d7
movq %rax, %r14
movq %rbx, -0x50(%rbp)
jmp 0x29d7
movq %rax, %r14
movq -0x50(%rbp), %rdi
callq 0x20f0
movq %r14, %rdi
callq 0x21c0