// File: /workspace/github_cpp_makefile_star2_O3/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 $0x88, %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), %rdi      # 0x8fd0
leaq 0x3bc8(%rip), %rsi      # 0x600f
movl $0x5c, %edx
callq 0x2120
movq 0x6b88(%rip), %rdi      # 0x8fe0
callq 0x2140
movb $0x20, -0x29(%rbp)
movl $0x280, %edi            # imm = 0x280
callq 0x2110
movq %rax, %rbx
movq %rax, %rdi
callq 0x3a48
movq %rbx, %rdi
callq 0x3148
movq %rbx, -0x48(%rbp)
movq %rbx, %rdi
callq 0x4eea
cmpl $0x64, %eax
jle 0x24b0
movq 0x6b3a(%rip), %rdi      # 0x8fd0
leaq 0x3bcf(%rip), %rsi      # 0x606c
movl $0x1d, %edx
callq 0x2120
movq -0x48(%rbp), %rbx
jmp 0x2975
movb $0x1, %al
xorl %r13d, %r13d
xorl %r15d, %r15d
movl $0x0, -0x34(%rbp)
movzbl %al, %r14d
movl %r14d, %r12d
andl $0x1, %r12d
movq -0x48(%rbp), %rbx
movq %rbx, %rdi
movl %r12d, %esi
callq 0x2ce6
testb $0x1, %r14b
leaq 0x3bb5(%rip), %rsi      # 0x6099
leaq 0x3b9f(%rip), %rax      # 0x608a
cmovneq %rax, %rsi
movl %r13d, -0x30(%rbp)
movzbl %r13b, %eax
movl %r12d, %ecx
movl %r15d, -0x38(%rbp)
movzbl %r15b, %r12d
movl %ecx, %r15d
movl %r12d, -0x5c(%rbp)
movl %eax, -0x40(%rbp)
cmovnel %eax, %r12d
movl $0xe, %edx
movq 0x6ab4(%rip), %r14      # 0x8fd0
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
movl $0x6, %edx
movq %r14, %rdi
leaq 0x3b4e(%rip), %rsi      # 0x60a8
callq 0x2120
callq 0x32ec
movl %eax, %r13d
cmpl $0x3e7, %eax            # imm = 0x3E7
jg 0x258d
cmpl $0x321, %r13d           # imm = 0x321
jne 0x25e1
movl $0x31, %edx
movq %r14, %rdi
testl %r15d, %r15d
je 0x25b6
leaq 0x3b78(%rip), %rsi      # 0x6103
jmp 0x25bd
cmpl $0x3e8, %r13d           # imm = 0x3E8
jne 0x25f8
testb $0x1, %r12b
je 0x2819
movl $0xe, %edx
movq %r14, %rdi
leaq 0x3b0d(%rip), %rsi      # 0x60bc
callq 0x2120
jmp 0x254b
leaq 0x3b8c(%rip), %rsi      # 0x6149
callq 0x2120
movq 0x6a17(%rip), %rdi      # 0x8fe0
leaq -0x29(%rbp), %rsi
callq 0x2150
cmpb $0x79, -0x29(%rbp)
jne 0x254b
jmp 0x294f
cmpl $-0x1, %r13d
je 0x297e
cmpl $0x320, %r13d           # imm = 0x320
je 0x293a
movl $0x4, %edx
movq %r14, %rdi
leaq 0x3b74(%rip), %rsi      # 0x617b
callq 0x2120
callq 0x32ec
cmpl $0x45, %r13d
jne 0x2645
cmpl $0x2f, %eax
jg 0x2771
cmpl $0x10, %eax
je 0x27a1
cmpl $0x17, %eax
jne 0x274d
testl %r15d, %r15d
jne 0x274d
movq %rbx, %rdi
xorl %esi, %esi
jmp 0x27ae
movl %eax, -0x3c(%rbp)
movl $0x280, %edi            # imm = 0x280
callq 0x2110
movq %rax, -0x58(%rbp)
movq %rbx, %rdi
callq 0x4ef6
movq %rax, -0x50(%rbp)
movq %rbx, %rdi
callq 0x4f00
movq %rax, -0x68(%rbp)
leaq -0xb0(%rbp), %rdi
movq %rbx, %rsi
callq 0x4f0e
leaq -0x98(%rbp), %rdi
movq %rbx, %rsi
callq 0x4f2e
movq -0x58(%rbp), %rdi
movq -0x50(%rbp), %rsi
movq -0x68(%rbp), %rdx
leaq -0xb0(%rbp), %rcx
leaq -0x98(%rbp), %r8
callq 0x3a98
movq -0x98(%rbp), %rdi
testq %rdi, %rdi
je 0x26bc
callq 0x20f0
movq -0xb0(%rbp), %rdi
testq %rdi, %rdi
je 0x26cd
callq 0x20f0
movq -0x58(%rbp), %rbx
movq %rbx, %rdi
movl %r13d, %esi
movl -0x3c(%rbp), %edx
movl %r15d, %ecx
callq 0x3d94
movl %eax, -0x50(%rbp)
testl %eax, %eax
jle 0x26fe
movq %rbx, %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x429a
movl %eax, -0x34(%rbp)
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
testl %r15d, %r15d
je 0x271e
movl -0x34(%rbp), %eax
andl $-0x3, %eax
leaq 0x3a67(%rip), %rsi      # 0x6180
cmpl $0x1, %eax
je 0x2735
testl %r15d, %r15d
jne 0x2787
movl -0x34(%rbp), %eax
andl $-0x2, %eax
leaq 0x3a64(%rip), %rsi      # 0x6194
cmpl $0x2, %eax
jne 0x2787
movl $0x13, %edx
movq %r14, %rdi
callq 0x2120
movl $0x0, -0x34(%rbp)
movq -0x48(%rbp), %rbx
movl $0xd, %edx
movq %r14, %rdi
leaq 0x3a4c(%rip), %rsi      # 0x61a8
callq 0x2120
xorl %eax, %eax
cmpl $0x1, %eax
jne 0x254b
jmp 0x2915
cmpl $0x30, %eax
je 0x27b2
cmpl $0x37, %eax
jne 0x274d
testl %r15d, %r15d
jne 0x274d
movq %rbx, %rdi
xorl %esi, %esi
jmp 0x27bf
movq -0x48(%rbp), %rbx
movq %rbx, %rdi
movl %r13d, %esi
movl -0x3c(%rbp), %edx
movl %r15d, %ecx
callq 0x3d94
movl -0x50(%rbp), %eax
jmp 0x27c9
testl %r15d, %r15d
je 0x274d
movq %rbx, %rdi
movl $0x1, %esi
xorl %edx, %edx
jmp 0x27c4
testl %r15d, %r15d
je 0x274d
movq %rbx, %rdi
movl $0x1, %esi
movl $0x1, %edx
callq 0x4ba2
cmpl $-0x5, %eax
je 0x27fb
cmpl $-0x4, %eax
je 0x27dd
testl %eax, %eax
je 0x274d
jmp 0x2763
movl $0x20, %edx
movq %r14, %rdi
leaq 0x3a07(%rip), %rsi      # 0x61f3
callq 0x2120
movl $0xfffffffc, %eax       # imm = 0xFFFFFFFC
jmp 0x2763
movl $0x3c, %edx
movq %r14, %rdi
leaq 0x39ac(%rip), %rsi      # 0x61b6
callq 0x2120
movl $0xfffffffb, %eax       # imm = 0xFFFFFFFB
jmp 0x2763
callq 0x2040
movl %eax, %ecx
leaq (%rcx,%rcx,2), %rcx
shrq $0x20, %rcx
movl %eax, %edx
subl %ecx, %edx
shrl %edx
addl %ecx, %edx
shrl $0x1e, %edx
movl %edx, %ecx
shll $0x1f, %ecx
orl %edx, %ecx
leal (%rax,%rcx), %edx
cmpl $0x1, %edx
adcl %eax, %ecx
movq %rcx, -0x70(%rbp)
movabsq $0x3f00000000, %rax     # imm = 0x3F00000000
movq %rax, -0x80(%rbp)
movabsq $0x900000000, %rax      # imm = 0x900000000
movq %rax, -0x78(%rbp)
movl %r15d, -0x30(%rbp)
movl %r15d, %eax
xorb $0x1, %al
movzbl %al, %eax
movl %eax, -0x38(%rbp)
leaq -0x70(%rbp), %r12
movq %rbx, %r15
leaq -0x80(%rbp), %rbx
movq %rbx, %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x29da
movl %eax, %r13d
movq %r15, %rdi
movl %eax, %esi
callq 0x3d84
testb %al, %al
jne 0x287c
leaq -0x78(%rbp), %rdi
movq %r12, %rsi
movq %rdi, %rdx
callq 0x29da
movq %r15, %rbx
movq %r15, %rdi
movl $0x71, %esi
movl %r13d, %edx
testl %eax, %eax
je 0x28ca
movl -0x30(%rbp), %r15d
movl %r15d, %ecx
callq 0x3c38
jmp 0x28ea
movl -0x38(%rbp), %ecx
callq 0x3c38
movl $0xc, %edx
movq %r14, %rdi
leaq 0x37ce(%rip), %rsi      # 0x60af
callq 0x2120
movl -0x30(%rbp), %r15d
movl -0x40(%rbp), %r12d
testl %r15d, %r15d
movl $0x1, %eax
cmovnel %eax, %r12d
movl -0x5c(%rbp), %r13d
cmovel %eax, %r13d
movq %rbx, %rdi
movl %r15d, %esi
callq 0x2ce6
movl %r12d, -0x30(%rbp)
movl %r13d, -0x38(%rbp)
xorb $0x1, %r15b
movq %rbx, %rdi
callq 0x4eea
cmpl $0x64, %eax
movl %r15d, %eax
movl -0x30(%rbp), %r13d
movl -0x38(%rbp), %r15d
jle 0x24bf
jmp 0x248f
movq 0x668f(%rip), %rdi      # 0x8fd0
testl %r15d, %r15d
je 0x2964
leaq 0x377e(%rip), %rsi      # 0x60cb
jmp 0x296b
movq 0x667a(%rip), %rdi      # 0x8fd0
leaq 0x37d8(%rip), %rsi      # 0x6135
movl $0x13, %edx
jmp 0x2970
leaq 0x377c(%rip), %rsi      # 0x60e7
movl $0x1b, %edx
callq 0x2120
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
xorl %eax, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %r14
movq -0x98(%rbp), %rdi
testq %rdi, %rdi
je 0x29ab
callq 0x20f0
jmp 0x29ab
movq %rax, %r14
movq -0xb0(%rbp), %rdi
testq %rdi, %rdi
je 0x29c1
callq 0x20f0
jmp 0x29c1
movq %rax, %r14
movq -0x58(%rbp), %rdi
jmp 0x29cd
movq %rax, %r14
movq %rbx, %rdi
callq 0x20f0
movq %r14, %rdi
callq 0x21c0