// File: 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
subq $0x100, %rsp            # imm = 0x100
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0x0, -0x14(%rbp)
cmpl $0xa, -0x14(%rbp)
jge 0x2534
movq 0xcab3(%rip), %rdi      # 0xefd0
leaq 0x7b80(%rip), %rsi      # 0xa0a4
callq 0x2140
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0x2510
movq 0xca95(%rip), %rdi      # 0xefd0
leaq 0x7b6d(%rip), %rsi      # 0xa0af
callq 0x2140
movq 0xca92(%rip), %rdi      # 0xefe0
callq 0x2180
movb $0x1, -0x15(%rbp)
movl $0x0, -0x1c(%rbp)
movb $0x20, -0x1d(%rbp)
movl $0x280, %edi            # imm = 0x280
callq 0x2150
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xc8(%rbp)
callq 0x4850
jmp 0x2580
movq -0xc8(%rbp), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rdi
callq 0x3ac0
movb $0x0, -0x35(%rbp)
movb $0x0, -0x36(%rbp)
movl $0x0, -0x3c(%rbp)
cmpl $0x0, -0x1c(%rbp)
jne 0x2c4b
movq -0x28(%rbp), %rdi
callq 0x68a0
cmpl $0x64, %eax
jle 0x25f7
movq 0xca0e(%rip), %rdi      # 0xefd0
leaq 0x7b43(%rip), %rsi      # 0xa10c
callq 0x2140
movl $0x3, -0x1c(%rbp)
jmp 0x2c4b
movq -0xc8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x2130
jmp 0x2c7c
movq -0x28(%rbp), %rdi
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %esi
callq 0x3610
testb $0x1, -0x15(%rbp)
je 0x2632
movq 0xc9bb(%rip), %rdi      # 0xefd0
leaq 0x7b0e(%rip), %rsi      # 0xa12a
callq 0x2140
movq %rax, %rdi
movq 0xc995(%rip), %rsi      # 0xefc0
callq 0x2160
jmp 0x2654
movq 0xc997(%rip), %rdi      # 0xefd0
leaq 0x7af9(%rip), %rsi      # 0xa139
callq 0x2140
movq %rax, %rdi
movq 0xc971(%rip), %rsi      # 0xefc0
callq 0x2160
movl $0x0, -0x40(%rbp)
cmpl $0x1, -0x40(%rbp)
je 0x2c3c
movq 0xc964(%rip), %rdi      # 0xefd0
leaq 0x7ad5(%rip), %rsi      # 0xa148
callq 0x2140
callq 0x3c80
movl %eax, -0x44(%rbp)
cmpl $-0x1, -0x44(%rbp)
jne 0x2692
movl $0x0, -0x4(%rbp)
jmp 0x2c70
cmpl $0x3e8, -0x44(%rbp)     # imm = 0x3E8
jne 0x27fb
testb $0x1, -0x15(%rbp)
je 0x26b2
movb -0x35(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x26cd
testb $0x1, -0x15(%rbp)
jne 0x27e3
movb -0x36(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x27e3
callq 0x2030
movq %rax, -0x60(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x2c90
movq %rax, -0x58(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x2cb0
movl %eax, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
movl %eax, %esi
leaq -0x68(%rbp), %rdi
callq 0x2cd0
leaq -0x70(%rbp), %rdi
xorl %esi, %esi
movl $0x3f, %edx
callq 0x2d00
leaq -0x78(%rbp), %rdi
xorl %esi, %esi
movl $0x9, %edx
callq 0x2d00
movb $0x0, -0x79(%rbp)
movb -0x79(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x272f
jmp 0x27de
leaq -0x70(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x2d30
movl %eax, -0x80(%rbp)
movq -0x28(%rbp), %rdi
movl -0x80(%rbp), %esi
callq 0x4d70
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x27d9
movb $0x1, -0x79(%rbp)
leaq -0x78(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x2d30
cmpl $0x0, %eax
jne 0x279f
movq -0x28(%rbp), %rdi
movl -0x80(%rbp), %edx
movb -0x15(%rbp), %al
xorb $-0x1, %al
andb $0x1, %al
movzbl %al, %ecx
movl $0x71, %esi
callq 0x4b00
movq 0xc83f(%rip), %rdi      # 0xefd0
leaq 0x79b7(%rip), %rsi      # 0xa14f
callq 0x2140
jmp 0x27b8
movq -0x28(%rbp), %rdi
movl -0x80(%rbp), %edx
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %ecx
movl $0x71, %esi
callq 0x4b00
testb $0x1, -0x15(%rbp)
je 0x27c4
movb $0x1, -0x35(%rbp)
jmp 0x27c8
movb $0x1, -0x36(%rbp)
movq -0x28(%rbp), %rdi
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %esi
callq 0x3610
jmp 0x2721
jmp 0x2c3c
movq 0xc7e6(%rip), %rdi      # 0xefd0
leaq 0x796b(%rip), %rsi      # 0xa15c
callq 0x2140
jmp 0x265b
cmpl $0x320, -0x44(%rbp)     # imm = 0x320
jne 0x2845
testb $0x1, -0x15(%rbp)
je 0x2826
movq 0xc7bf(%rip), %rdi      # 0xefd0
leaq 0x7953(%rip), %rsi      # 0xa16b
callq 0x2140
movl $0x2, -0x1c(%rbp)
jmp 0x2840
movq 0xc7a3(%rip), %rdi      # 0xefd0
leaq 0x7953(%rip), %rsi      # 0xa187
callq 0x2140
movl $0x1, -0x1c(%rbp)
jmp 0x2c3c
cmpl $0x321, -0x44(%rbp)     # imm = 0x321
jne 0x28f8
testb $0x1, -0x15(%rbp)
je 0x28a8
movq 0xc771(%rip), %rdi      # 0xefd0
leaq 0x793d(%rip), %rsi      # 0xa1a3
callq 0x2140
movq 0xc76e(%rip), %rdi      # 0xefe0
leaq -0x1d(%rbp), %rsi
callq 0x21a0
movsbl -0x1d(%rbp), %eax
cmpl $0x79, %eax
jne 0x28a3
movq 0xc745(%rip), %rdi      # 0xefd0
leaq 0x7943(%rip), %rsi      # 0xa1d5
callq 0x2140
movl $0x3, -0x1c(%rbp)
jmp 0x2c3c
jmp 0x265b
movq 0xc721(%rip), %rdi      # 0xefd0
leaq 0x7933(%rip), %rsi      # 0xa1e9
callq 0x2140
movq 0xc71e(%rip), %rdi      # 0xefe0
leaq -0x1d(%rbp), %rsi
callq 0x21a0
movsbl -0x1d(%rbp), %eax
cmpl $0x79, %eax
jne 0x28f3
movq 0xc6f5(%rip), %rdi      # 0xefd0
leaq 0x78f3(%rip), %rsi      # 0xa1d5
callq 0x2140
movl $0x3, -0x1c(%rbp)
jmp 0x2c3c
jmp 0x265b
movq 0xc6d1(%rip), %rdi      # 0xefd0
leaq 0x7915(%rip), %rsi      # 0xa21b
callq 0x2140
callq 0x3c80
movl %eax, -0x48(%rbp)
cmpl $0x45, -0x44(%rbp)
jne 0x29dd
movl $0x0, -0x40(%rbp)
movl -0x48(%rbp), %eax
addl $-0x10, %eax
movl %eax, %ecx
movq %rcx, -0xd0(%rbp)
subl $0x27, %eax
ja 0x29d8
movq -0xd0(%rbp), %rax
leaq 0x76ba(%rip), %rcx      # 0xa004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x2973
movq -0x28(%rbp), %rdi
movl $0x1, %esi
xorl %edx, %edx
callq 0x6480
movl %eax, -0x40(%rbp)
jmp 0x29d8
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x2992
movq -0x28(%rbp), %rdi
xorl %edx, %edx
movl %edx, %esi
callq 0x6480
movl %eax, -0x40(%rbp)
jmp 0x29d8
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x29b4
movq -0x28(%rbp), %rdi
movl $0x1, %edx
movl %edx, %esi
callq 0x6480
movl %eax, -0x40(%rbp)
jmp 0x29d8
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x29d6
movq -0x28(%rbp), %rdi
xorl %esi, %esi
movl $0x1, %edx
callq 0x6480
movl %eax, -0x40(%rbp)
jmp 0x29d8
jmp 0x2bd1
movl $0x280, %edi            # imm = 0x280
callq 0x2150
movq %rax, -0xe0(%rbp)
movb $0x1, -0xb9(%rbp)
movq -0x28(%rbp), %rdi
callq 0x68c0
movq %rax, -0xd8(%rbp)
jmp 0x2a07
movq -0x28(%rbp), %rdi
callq 0x68e0
movq %rax, -0xe8(%rbp)
jmp 0x2a19
movq -0x28(%rbp), %rsi
leaq -0xa0(%rbp), %rdi
callq 0x6900
jmp 0x2a2b
movq -0x28(%rbp), %rsi
leaq -0xb8(%rbp), %rdi
callq 0x6940
jmp 0x2a3d
movq -0xe8(%rbp), %rdx
movq -0xd8(%rbp), %rsi
movq -0xe0(%rbp), %rdi
leaq -0xa0(%rbp), %rcx
leaq -0xb8(%rbp), %r8
callq 0x48e0
jmp 0x2a67
movb $0x0, -0xb9(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x2d60
leaq -0xa0(%rbp), %rdi
callq 0x2dc0
movq -0xe0(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x88(%rbp), %rdi
movl -0x44(%rbp), %esi
movl -0x48(%rbp), %edx
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %ecx
callq 0x4db0
movl %eax, -0x40(%rbp)
cmpl $0x1, -0x40(%rbp)
jl 0x2b2b
movq -0x88(%rbp), %rdi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
movl %edx, %esi
callq 0x5590
movl %eax, -0x3c(%rbp)
jmp 0x2b2b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
jmp 0x2b0f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
jmp 0x2b03
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x2d60
leaq -0xa0(%rbp), %rdi
callq 0x2dc0
testb $0x1, -0xb9(%rbp)
jne 0x2b1a
jmp 0x2b26
movq -0xe0(%rbp), %rdi
callq 0x2130
jmp 0x2c7c
movq -0x88(%rbp), %rax
movq %rax, -0xf0(%rbp)
cmpq $0x0, %rax
je 0x2b4c
movq -0xf0(%rbp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
testb $0x1, -0x15(%rbp)
je 0x2b81
cmpl $0x1, -0x3c(%rbp)
je 0x2b5e
cmpl $0x3, -0x3c(%rbp)
jne 0x2b81
movq 0xc46b(%rip), %rdi      # 0xefd0
leaq 0x76b4(%rip), %rsi      # 0xa220
callq 0x2140
movl $0x0, -0x40(%rbp)
movl $0x0, -0x3c(%rbp)
jmp 0x2bcf
testb $0x1, -0x15(%rbp)
jne 0x2bb6
cmpl $0x2, -0x3c(%rbp)
je 0x2b93
cmpl $0x3, -0x3c(%rbp)
jne 0x2bb6
movq 0xc436(%rip), %rdi      # 0xefd0
leaq 0x7693(%rip), %rsi      # 0xa234
callq 0x2140
movl $0x0, -0x40(%rbp)
movl $0x0, -0x3c(%rbp)
jmp 0x2bcd
movq -0x28(%rbp), %rdi
movl -0x44(%rbp), %esi
movl -0x48(%rbp), %edx
movb -0x15(%rbp), %al
andb $0x1, %al
movzbl %al, %ecx
callq 0x4db0
jmp 0x2bcf
jmp 0x2bd1
movl -0x40(%rbp), %eax
movl %eax, -0xf4(%rbp)
subl $-0x5, %eax
je 0x2c0f
jmp 0x2be1
movl -0xf4(%rbp), %eax
subl $-0x4, %eax
je 0x2c24
jmp 0x2bee
movl -0xf4(%rbp), %eax
testl %eax, %eax
jne 0x2c37
jmp 0x2bfa
movq 0xc3cf(%rip), %rdi      # 0xefd0
leaq 0x7640(%rip), %rsi      # 0xa248
callq 0x2140
jmp 0x2c37
movq 0xc3ba(%rip), %rdi      # 0xefd0
leaq 0x7639(%rip), %rsi      # 0xa256
callq 0x2140
jmp 0x2c37
movq 0xc3a5(%rip), %rdi      # 0xefd0
leaq 0x7661(%rip), %rsi      # 0xa293
callq 0x2140
jmp 0x265b
movb -0x15(%rbp), %al
xorb $-0x1, %al
andb $0x1, %al
movb %al, -0x15(%rbp)
jmp 0x25a3
movq -0x28(%rbp), %rax
movq %rax, -0x100(%rbp)
cmpq $0x0, %rax
je 0x2c69
movq -0x100(%rbp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
movq -0x30(%rbp), %rdi
callq 0x2270
nopw %cs:(%rax,%rax)
nop