// File: /workspace/github_cpp_makefile_star2_O2/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 $0x78, %rsp
pushq $0xa
popq %r15
movq 0x6bd8(%rip), %rbx      # 0x8fd0
leaq 0x3c05(%rip), %r14      # 0x6004
subl $0x1, %r15d
jb 0x2412
movq %rbx, %rdi
movq %r14, %rsi
callq 0x20f0
jmp 0x23ff
movq 0x6bb7(%rip), %rdi      # 0x8fd0
leaq 0x3bef(%rip), %rsi      # 0x600f
callq 0x20f0
movq 0x6bb4(%rip), %rdi      # 0x8fe0
callq 0x2120
movb $0x20, -0x2a(%rbp)
movl $0x280, %edi            # imm = 0x280
callq 0x2100
movq %rax, %rbx
movq %rax, %rdi
callq 0x357c
movq %rbx, %rdi
callq 0x2e78
movb $0x1, -0x29(%rbp)
movl $0x0, -0x44(%rbp)
movq 0x6b6c(%rip), %r14      # 0x8fd0
movl $0x0, -0x40(%rbp)
xorl %r15d, %r15d
xorl %eax, %eax
testl %eax, %eax
jne 0x28b7
movq %rbx, %rdi
callq 0x485e
cmpl $0x65, %eax
jge 0x28a4
movl %r15d, -0x30(%rbp)
movzbl -0x29(%rbp), %r15d
movl %r15d, %esi
andl $0x1, %esi
movq %rbx, %rdi
movl %esi, -0x3c(%rbp)
callq 0x2b37
movl %r15d, -0x4c(%rbp)
testb $0x1, %r15b
leaq 0x3be7(%rip), %rsi      # 0x6099
leaq 0x3bd1(%rip), %rax      # 0x608a
cmovneq %rax, %rsi
movzbl -0x44(%rbp), %eax
movzbl -0x40(%rbp), %r15d
cmovnel %eax, %r15d
movq %r14, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x2090
xorl %r12d, %r12d
cmpl $0x1, %r12d
je 0x289c
movq %r14, %rdi
leaq 0x3bb7(%rip), %rsi      # 0x60a8
callq 0x20f0
callq 0x2fec
cmpl $0x321, %eax            # imm = 0x321
je 0x2527
movl %eax, %r13d
cmpl $0x3e8, %eax            # imm = 0x3E8
jne 0x2563
testb $0x1, %r15b
je 0x2793
movq %r14, %rdi
leaq 0x3b9c(%rip), %rsi      # 0x60bc
callq 0x20f0
jmp 0x24e7
testb $0x1, -0x29(%rbp)
je 0x2539
movq %r14, %rdi
leaq 0x3bcc(%rip), %rsi      # 0x6103
jmp 0x2543
movq %r14, %rdi
leaq 0x3c06(%rip), %rsi      # 0x6149
callq 0x20f0
movq 0x6a91(%rip), %rdi      # 0x8fe0
leaq -0x2a(%rbp), %rsi
callq 0x2140
cmpb $0x79, -0x2a(%rbp)
jne 0x24e7
jmp 0x277d
cmpl $-0x1, %r13d
je 0x28c0
cmpl $0x320, %r13d           # imm = 0x320
je 0x275d
movq %r14, %rdi
leaq 0x3bf7(%rip), %rsi      # 0x617b
callq 0x20f0
callq 0x2fec
cmpl $0x45, %r13d
jne 0x25d0
xorl %r12d, %r12d
cmpl $0x37, %eax
je 0x2703
cmpl $0x17, %eax
je 0x26e4
cmpl $0x30, %eax
je 0x26f3
cmpl $0x10, %eax
jne 0x2709
testb $0x1, -0x29(%rbp)
je 0x2709
movq %rbx, %rdi
pushq $0x1
popq %rsi
jmp 0x26ef
movl %eax, -0x48(%rbp)
movl $0x280, %edi            # imm = 0x280
callq 0x2100
movq %rax, %r12
movq %rbx, %rdi
callq 0x486a
movq %rax, -0x38(%rbp)
movq %rbx, %rdi
callq 0x4874
movq %rax, -0x60(%rbp)
leaq -0xa0(%rbp), %rdi
movq %rbx, %rsi
callq 0x4882
leaq -0x88(%rbp), %rdi
movq %rbx, %rsi
callq 0x48a2
movq %r12, %rdi
movq -0x38(%rbp), %rsi
movq -0x60(%rbp), %rdx
movq %r12, -0x38(%rbp)
leaq -0xa0(%rbp), %r12
movq %r12, %rcx
leaq -0x88(%rbp), %r8
callq 0x35c2
leaq -0x88(%rbp), %rdi
callq 0x2a3c
movq %r12, %rdi
callq 0x2a28
movq -0x38(%rbp), %rdi
movl %r13d, %esi
movl -0x48(%rbp), %edx
movl -0x3c(%rbp), %ecx
callq 0x385c
movl %eax, %r12d
testl %eax, %eax
jle 0x2679
movq -0x38(%rbp), %rdi
pushq $-0x1
popq %rdx
movl %edx, %esi
callq 0x3d10
movl %eax, -0x30(%rbp)
movq -0x38(%rbp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
movl -0x30(%rbp), %ecx
movl %ecx, %eax
andl $-0x3, %eax
cmpl $0x1, %eax
sete %al
leaq 0x3ae8(%rip), %rsi      # 0x6180
testb %al, -0x29(%rbp)
jne 0x26c9
movl %ecx, %eax
andl $-0x2, %eax
cmpl $0x2, %eax
setne %al
orb -0x29(%rbp), %al
leaq 0x3ae2(%rip), %rsi      # 0x6194
testb $0x1, %al
je 0x26c9
movq %rbx, %rdi
movl %r13d, %esi
movl -0x48(%rbp), %edx
movl -0x3c(%rbp), %ecx
callq 0x385c
jmp 0x2722
movq %r14, %rdi
callq 0x20f0
xorl %r12d, %r12d
leaq 0x3acd(%rip), %rsi      # 0x61a8
movl $0x0, -0x30(%rbp)
jmp 0x2750
testb $0x1, -0x29(%rbp)
jne 0x2709
movq %rbx, %rdi
xorl %esi, %esi
xorl %edx, %edx
jmp 0x271a
testb $0x1, -0x29(%rbp)
je 0x2709
movq %rbx, %rdi
pushq $0x1
popq %rdx
movl %edx, %esi
jmp 0x271a
testb $0x1, -0x29(%rbp)
je 0x2712
leaq 0x3a98(%rip), %rsi      # 0x61a8
jmp 0x2750
movq %rbx, %rdi
xorl %esi, %esi
pushq $0x1
popq %rdx
callq 0x4560
movl %eax, %r12d
cmpl $-0x5, %r12d
je 0x2749
cmpl $-0x4, %r12d
je 0x2740
leaq 0x3a73(%rip), %rsi      # 0x61a8
testl %r12d, %r12d
jne 0x24dd
jmp 0x2750
leaq 0x3aac(%rip), %rsi      # 0x61f3
jmp 0x2750
leaq 0x3a66(%rip), %rsi      # 0x61b6
movq %r14, %rdi
callq 0x20f0
jmp 0x24dd
testb $0x1, -0x29(%rbp)
je 0x287d
movq %r14, %rdi
leaq 0x395a(%rip), %rsi      # 0x60cb
callq 0x20f0
pushq $0x2
jmp 0x288e
movq %r14, %rdi
leaq 0x39ae(%rip), %rsi      # 0x6135
callq 0x20f0
pushq $0x3
jmp 0x288e
callq 0x2030
xorl %r13d, %r13d
xorl %edx, %edx
movl $0x7fffffff, %ecx       # imm = 0x7FFFFFFF
divl %ecx
cmpl $0x1, %edx
adcl $0x0, %edx
movq %rdx, -0x58(%rbp)
movabsq $0x3f00000000, %rax     # imm = 0x3F00000000
movq %rax, -0x70(%rbp)
movabsq $0x900000000, %rax      # imm = 0x900000000
movq %rax, -0x68(%rbp)
movb -0x29(%rbp), %al
notb %al
movzbl %al, %eax
andl $0x1, %eax
movl %eax, -0x38(%rbp)
leaq -0x58(%rbp), %r15
testb $0x1, %r13b
jne 0x2879
leaq -0x70(%rbp), %rdi
movq %r15, %rsi
callq 0x2912
movl %eax, %r12d
movq %rbx, %rdi
movl %eax, %esi
callq 0x384c
movl %eax, %r13d
testb %al, %al
jne 0x2870
leaq -0x68(%rbp), %rdi
movq %r15, %rsi
callq 0x2912
movq %rbx, %rdi
pushq $0x71
popq %rsi
movl %r12d, %edx
testl %eax, %eax
je 0x2829
movl -0x3c(%rbp), %ecx
callq 0x370e
jmp 0x2840
movl -0x38(%rbp), %ecx
callq 0x370e
movq %r14, %rdi
leaq 0x3874(%rip), %rsi      # 0x60af
callq 0x20f0
movl -0x44(%rbp), %eax
movzbl %al, %eax
testb $0x1, -0x29(%rbp)
pushq $0x1
popq %rcx
cmovnel %ecx, %eax
movl %eax, -0x44(%rbp)
movl -0x40(%rbp), %eax
movzbl %al, %eax
cmovel %ecx, %eax
movl %eax, -0x40(%rbp)
movl -0x4c(%rbp), %esi
andl %ecx, %esi
movq %rbx, %rdi
callq 0x2b37
leaq -0x58(%rbp), %r15
xorb $0x1, %r13b
jmp 0x27dc
xorl %eax, %eax
jmp 0x288f
movq %r14, %rdi
leaq 0x3860(%rip), %rsi      # 0x60e7
callq 0x20f0
pushq $0x1
popq %rax
movl -0x30(%rbp), %r15d
xorb $0x1, -0x29(%rbp)
jmp 0x2470
movl -0x30(%rbp), %r15d
xorl %eax, %eax
jmp 0x2893
movq 0x6725(%rip), %rdi      # 0x8fd0
leaq 0x37ba(%rip), %rsi      # 0x606c
callq 0x20f0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
xorl %eax, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq -0x38(%rbp), %r12
movq %rax, %r14
leaq -0x88(%rbp), %rdi
callq 0x2a3c
jmp 0x28e9
movq %rax, %r14
leaq -0xa0(%rbp), %rdi
callq 0x2a28
jmp 0x2902
movq %rax, %r14
movq %rbx, %rdi
jmp 0x2905
movq %rax, %r14
movq %r12, %rdi
callq 0x20e0
movq %r14, %rdi
callq 0x21b0