#include "Game.cuh"

/**
  *	Gets the index of the highest value in a list
  *	Parameter outputs: the list to look through
  *	Parameter numOutputs: the number of elements in
  *	the outputs list
  *	Returns: the index of the highest value in a list
  */

int getMaxIndex(double* outputs, int numOutputs){
	// Gets the index with the highest
	int maxIndex=0;
	for(int output=0; output<numOutputs; output++){
		if(outputs[maxIndex] <= outputs[output]){
			maxIndex=output;
		}
	}
	return maxIndex;
}

/**
  *	Changes an index into a move vector
  *	Parameter index: the index to change into
  *	a move vector
  *	Returns: a vector corresponding to the move to be
  *	made in the form (oldRow, oldCol, newRow, newCol)
  */

int* parseIndexToMove(int index){

	// Gets the actual move from the max
	int* move=(int*)(calloc(4, sizeof(int)));
	for(int movePart=0; movePart<4; movePart++){
		move[movePart]=index%8;
		index/=8;
	}
	return move;
}

/**
  *	Changes the move into an index (for the output list)
  *	This is the inverse of the parseIndexToMove function
  *	and makes a 1-1 correspondance between the functions
  *	Parameter move: the move vector (oldRow, oldCol, 
  *	newRow, newCol)
  *	Returns: the corresponding index of the move
  */

int parseMoveToIndex(int* move){
	int index=0;
	for(int part=0; part<4; part++){
		index+=move[3-part]*pow(8, 3-part);
	}
	return index;
}

/**
  *	Allows the user to input a move to play against the neural network
  *	Parameter board: the board to make a move on
  *	Parameter color: the player's color (that's making the move)
  *	Returns: the winner's color if there is one -1 otherwise
  */

int makePlayerTurn(Piece** board, int color){
	int winner=-1;
	int madeMove=0;
	char* buffer=(char*)calloc(80, sizeof(char));

	do{
		//Handles user input
		printf("Make a numerical move in the format: [oldRow oldCol newRow newCol]\n");

		int oldRow=-1;
		int oldCol=-1;
		int newRow=-1;
		int newCol=-1;
		
		fgets(buffer, 78, stdin);
		oldRow=buffer[0]-48;
		oldCol=buffer[2]-48;
		newRow=buffer[4]-48;
		newCol=buffer[6]-48;

		// Validates the move and gets a winner if there is one
		if(isValidMove(board, oldRow, oldCol, newRow, newCol, color)){
			if(movePiece(board, oldRow, oldCol, newRow, newCol)==KINGREWARD){
				winner=color;
			}
			madeMove=1;
		}

		// An invalid move was made
		else{
			printf("Invalid move made\n");
		}
	}while(!madeMove);

	free(buffer);

	return winner;
}

/**
  *	Makes the turn and updates the output vectors
  *	Parameter board: the board to make a turn on
  *	Parameter color: the color of the player whose turn it is
  *	Parameter turn: the turn number
  *	Parameter nn: the neural network to use
  *	Parameter inputVector: a vector with enough space to hold
  *	all one-hot encoded data values for the board
  *	Parameter output: the rewards corresponding to the 
  *	output of the neural network
  *	Parameter expected: the values that were rewarded
  *	Parameter chosens: the chosen moves
  *	Returns: whether or not there was a checkmate
  */

int makeTurn(Piece** board, int color, int turn, NeuralNet* nn, 
	double* inputVector, double*** output, double** expected, int* chosens){

	// Gets the expected output vector
	oneHotEncode(board, inputVector);
	feedForward(nn, &output[turn], inputVector);

	// Gets the next move
	int madeMove=0;
	int randomMove=((rand()+0.0)/RAND_MAX)<EXPLORATION;
	
	int winner=-1;

	do{

		// If there should be a random move made
		if(randomMove){

			// Gets the random move
			int random=rand();
			int randomIndex=random%nn->neurons[nn->layers-1];
			int* move=parseIndexToMove(randomIndex);

			// Validates, makes, and gets the reward for a move
			if(isValidMove(board, move[0], move[1], move[2], 
						move[3], color)){

				expected[turn][randomIndex]=movePiece(board, 
					move[0], move[1], move[2], move[3])+TURNDEFICIT;

				chosens[turn]=randomIndex;

				if(expected[turn][randomIndex]==KINGREWARD+TURNDEFICIT){
					winner=color;
				}

				madeMove=1;
			}

			// Penalizes invalid moves
			else{
				expected[turn][randomIndex]=-1;
			}

			free(move);

		}
		
		// Otherwise choose the best move
		else{

			int maxIndex=getMaxIndex(output[turn][nn->layers-1], 
					nn->neurons[nn->layers-1]);
			int* move=parseIndexToMove(maxIndex);
			
			// Verifies the move and gets the reward for the move
			if(isValidMove(board, move[0], move[1], move[2], 
						move[3], color)){
				
				// Updates the reward
				expected[turn][maxIndex]=
					movePiece(board, move[0], move[1], 
					move[2], move[3])+TURNDEFICIT;
				
				// Updates the chosen list
				chosens[turn]=maxIndex;

				if(expected[turn][maxIndex]==KINGREWARD+TURNDEFICIT){
					winner=color;
				}

				madeMove=1;
			}

			// Penalizes invalid moves
			else{
				expected[turn][maxIndex]=-1;
			}

			free(move);

			// Make a random move if the best move is invalid
			randomMove=1;	
		}

	}while(!madeMove);

	return winner;
}

/**
  *	Plays a single game
  *	Parameter nn1: the first neural network
  *	Parameter nn2: the second neural network
  *	Parameter playerColor: the color of the player (-1
  *	if no player)
  *	Parameter inputVector: the input vector allocated
  *	with enough room for the one-hot encoded values of
  *	the board
  *	Parameter output1: the output values for the first 
  *	neural network
  *	Parameter output2: the output values for the second
  *	neural network
  *	Parameter expected1: the reward values for the 
  *	first player
  *	Parameter expected2: the reward values for the 
  *	second player
  *	Parameter chosens1: the chosen move indices for the 
  *	first player
  *	Parameter chosens2: the chosen move indices for the
  *	second player
  *	Parameter whiteTurns: the number of turns for the 
  *	first player
  *	Parameter blackTurns: the number of turns for the 
  *	second player
  *	Returns: the winner of the game (-1 if tie)
  */

int playGame(NeuralNet* nn1, NeuralNet* nn2, int playerColor, double* inputVector, 
	double*** output1, double*** output2, double** expected1, 
	double** expected2, int* chosens1, int* chosens2, int* whiteTurns, 
	int* blackTurns){

	Piece** board=makeChessBoard();

	int winner;
	int color=0;
	do{

		// Makes the player's turn
		if(color == playerColor){
			printChessBoard(board);
			winner=makePlayerTurn(board, color);
		}

		// Makes white's turn
		else if(color==0){
			//printf("White %d\n", *whiteTurns);
			winner=makeTurn(board, color, *whiteTurns,  nn1, 
				inputVector, output1, expected1, chosens1);
			(*whiteTurns)++;
		}

		// Makes black's turn
		else{
			//printf("Black %d\n", *blackTurns);
			winner=makeTurn(board, color, *blackTurns, nn2, 
				inputVector, output2, expected2, chosens2);
			(*blackTurns)++;
		}

		color=(color+1)%2;
	}while(winner<0 && (*whiteTurns)<TURNS && (*blackTurns)<TURNS);

	printChessBoard(board);

	freeChessBoard(board);

	return winner;
}

/**
  *	Uses the bellman equation to alter the actual reward values that were 
  *	returned
  *	Parameter nn: the neural network of the corresponding player
  *	Parameter outputs: the outputs of the neural networks
  *	Parameter expected: the reward values
  *	Parameter chosens: the states that were chosen
  *	Parameter numOutputs: the max number of outputs that could be chosen
  *	Parameter won: whether or not the player corresponding to the reward
  *	values has won
  *	Parameter tie: whether or not the player corresponding to the reward
  *	values has tied
  *	Returns: nothing
  */

void alterExpected(NeuralNet* nn, double*** outputs, double** expected, 
	int* chosens, int numOutputs, int won, int tie){
	
	// The bellman equation to chain the actions together
	for(int output=numOutputs-1; output>=0; output--){
		
		// Changes the non-chosen values to the output from the neural network
		// so no erroneous changes are made
		for(int reward=0; reward<nn->neurons[nn->layers-1]; reward++){
			if(expected[output][reward]!=-1 && reward != chosens[output]){
				expected[output][reward]=outputs[output][nn->layers-1][reward];
			}
		}

		// Bellman equation on last state's chosen value
		if(output==numOutputs-1){
			if(won){
				expected[output][chosens[output]]+=DISCOUNT*WINREWARD;
			}
			else if(!tie){
				expected[output][chosens[output]]+=DISCOUNT*LOSSREWARD;
			}
		}

		// Bellman equation on every other state's chosen value
		else{
			expected[output][chosens[output]]+=
				DISCOUNT*expected[output+1][chosens[output+1]];
			chosens[output+1]=-1;
		}
	}
	chosens[0]=-1;
}

/**
  *	Trains the neural network
  *	Parameter nn1: the first neural network to train
  *	Parameter nn2: the second neural network to train
  *	Parameter playerColor: the color of the player (or 
  *	-1 if there is no player)
  *	Returns: nothing
  */

void train(NeuralNet* nn1, NeuralNet* nn2, int playerColor, char* file1, char* file2){
	// The inputs used for both neural network feedforwards
	double* sharedInputs=(double*)calloc(nn1 -> neurons[0], 
		sizeof(double*));

	// Gets the output Matrices for both sides of the neural nets
	double*** output1=makeExpected(nn1, TURNS);
	double*** output2=makeExpected(nn2, TURNS);

	// Gets the reward Matrices for both sides of the neural nets
	double** expected1=makeActual(nn1, TURNS);
	double** expected2=makeActual(nn2, TURNS);

	// Gets the chosens vectors denoting what move was chosen
	int* chosens1=(int*)calloc(TURNS, sizeof(int));
	int* chosens2=(int*)calloc(TURNS, sizeof(int));
	for(int output=0; output<TURNS; output++){
		chosens1[output]=-1;
		chosens2[output]=-1;
	}

	// Loops through infinite games and plays the game to train it
	for(int game=0; 1; game++){

		// Serializes the neural networks every 5 games
		if(game%5==0){
			printf("Serializing the neural networks\n");
			
			serializeNeuralNet(nn1, file1);
			serializeNeuralNet(nn2, file2);
		}

		int* whiteTurns=(int*)calloc(1, sizeof(int));
		int* blackTurns=(int*)calloc(1, sizeof(int));

		// Plays a game
		printf("Training on game %d\n", game);
		int winner=playGame(nn1, nn2, playerColor, sharedInputs, output1, output2, 
			expected1, expected2, chosens1, chosens2, whiteTurns, blackTurns);

		// Changes the rewards using the bellman equation
		alterExpected(nn1, output1, expected1, chosens1, *whiteTurns, winner==0, winner==-1);
		alterExpected(nn2, output2, expected2, chosens2, *blackTurns, winner==1, winner==-1);

		free(whiteTurns);
		free(blackTurns);

		// Backpropogates when there is no player
		if(playerColor==-1){
			printf("Backpropogating\n");
			backpropogate(nn1, output1, expected1, TURNS);
			backpropogate(nn2, output2, expected2, TURNS);
		}
	}
}

	.file	"tmpxft_0022cc7f_00000000-6_Game.cudafe1.cpp"
	.text
#APP

#NO_APP
	.type	_ZL26__cudaUnregisterBinaryUtilv, @function
_ZL26__cudaUnregisterBinaryUtilv:
.LFB2037:
	.cfi_startproc
	endbr64
	movq	_ZL20__cudaFatCubinHandle(%rip), %rdi
	jmp	__cudaUnregisterFatBinary@PLT
	.cfi_endproc
.LFE2037:
	.size	_ZL26__cudaUnregisterBinaryUtilv, .-_ZL26__cudaUnregisterBinaryUtilv
	.globl	_Z11getMaxIndexPdi
	.type	_Z11getMaxIndexPdi, @function
_Z11getMaxIndexPdi:
.LFB2027:
	.cfi_startproc
	endbr64
	xorl	%eax, %eax
	xorl	%edx, %edx
.L3:
	cmpl	%eax, %esi
	jle	.L9
	movslq	%edx, %rcx
	movsd	(%rdi,%rax,8), %xmm0
	ucomisd	(%rdi,%rcx,8), %xmm0
	cmovnb	%eax, %edx
	incq	%rax
	jmp	.L3
.L9:
	movl	%edx, %eax
	ret
	.cfi_endproc
.LFE2027:
	.size	_Z11getMaxIndexPdi, .-_Z11getMaxIndexPdi
	.globl	_Z16parseIndexToMovei
	.type	_Z16parseIndexToMovei, @function
_Z16parseIndexToMovei:
.LFB2028:
	.cfi_startproc
	endbr64
	pushq	%rbx
	.cfi_def_cfa_offset 16
	.cfi_offset 3, -16
	movl	$4, %esi
	movl	%edi, %ebx
	movl	$4, %edi
	call	calloc@PLT
	xorl	%esi, %esi
	movl	$8, %edi
	movq	%rax, %rcx
.L11:
	movl	%ebx, %eax
	cltd
	idivl	%edi
	movl	%edx, (%rcx,%rsi,4)
	incq	%rsi
	movl	%eax, %ebx
	cmpq	$4, %rsi
	jne	.L11
	movq	%rcx, %rax
	popq	%rbx
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE2028:
	.size	_Z16parseIndexToMovei, .-_Z16parseIndexToMovei
	.globl	_Z16parseMoveToIndexPi
	.type	_Z16parseMoveToIndexPi, @function
_Z16parseMoveToIndexPi:
.LFB2029:
	.cfi_startproc
	endbr64
	pushq	%r12
	.cfi_def_cfa_offset 16
	.cfi_offset 12, -16
	xorl	%r12d, %r12d
	pushq	%rbp
	.cfi_def_cfa_offset 24
	.cfi_offset 6, -24
	movl	$3, %ebp
	pushq	%rbx
	.cfi_def_cfa_offset 32
	.cfi_offset 3, -32
	leaq	12(%rdi), %rbx
	subq	$16, %rsp
	.cfi_def_cfa_offset 48
.L15:
	cvtsi2sdl	(%rbx), %xmm2
	movsd	.LC0(%rip), %xmm0
	subq	$4, %rbx
	cvtsi2sdl	%ebp, %xmm1
	decl	%ebp
	movsd	%xmm2, 8(%rsp)
	call	pow@PLT
	movaps	%xmm0, %xmm1
	cvtsi2sdl	%r12d, %xmm0
	mulsd	8(%rsp), %xmm1
	addsd	%xmm1, %xmm0
	cvttsd2sil	%xmm0, %r12d
	cmpl	$-1, %ebp
	jne	.L15
	addq	$16, %rsp
	.cfi_def_cfa_offset 32
	movl	%r12d, %eax
	popq	%rbx
	.cfi_def_cfa_offset 24
	popq	%rbp
	.cfi_def_cfa_offset 16
	popq	%r12
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE2029:
	.size	_Z16parseMoveToIndexPi, .-_Z16parseMoveToIndexPi
	.section	.rodata.str1.1,"aMS",@progbits,1
.LC1:
	.string	"Make a numerical move in the format: [oldRow oldCol newRow newCol]\n"
.LC3:
	.string	"Invalid move made\n"
	.text
	.globl	_Z14makePlayerTurnPP1pi
	.type	_Z14makePlayerTurnPP1pi, @function
_Z14makePlayerTurnPP1pi:
.LFB2030:
	.cfi_startproc
	endbr64
	pushq	%r15
	.cfi_def_cfa_offset 16
	.cfi_offset 15, -16
	leaq	.LC1(%rip), %r15
	pushq	%r14
	.cfi_def_cfa_offset 24
	.cfi_offset 14, -24
	pushq	%r13
	.cfi_def_cfa_offset 32
	.cfi_offset 13, -32
	pushq	%r12
	.cfi_def_cfa_offset 40
	.cfi_offset 12, -40
	movq	%rdi, %r12
	movl	$80, %edi
	pushq	%rbp
	.cfi_def_cfa_offset 48
	.cfi_offset 6, -48
	movl	%esi, %ebp
	movl	$1, %esi
	pushq	%rbx
	.cfi_def_cfa_offset 56
	.cfi_offset 3, -56
	subq	$24, %rsp
	.cfi_def_cfa_offset 80
	call	calloc@PLT
	movq	%rax, %rbx
.L23:
	movq	%r15, %rsi
	movl	$2, %edi
	xorl	%eax, %eax
	call	__printf_chk@PLT
	movq	stdin(%rip), %rcx
	movl	$78, %edx
	movq	%rbx, %rdi
	movl	$80, %esi
	call	__fgets_chk@PLT
	movsbl	2(%rbx), %r13d
	movsbl	(%rbx), %esi
	movl	%ebp, %r9d
	movsbl	4(%rbx), %r14d
	movsbl	6(%rbx), %r8d
	movq	%r12, %rdi
	subl	$48, %r13d
	subl	$48, %esi
	subl	$48, %r14d
	subl	$48, %r8d
	movl	%r13d, %edx
	movl	%esi, 8(%rsp)
	movl	%r14d, %ecx
	movl	%r8d, 12(%rsp)
	call	_Z11isValidMovePP1piiiii@PLT
	movl	8(%rsp), %esi
	movl	12(%rsp), %r8d
	testl	%eax, %eax
	je	.L19
	movl	%r14d, %ecx
	movl	%r13d, %edx
	movq	%r12, %rdi
	call	_Z9movePiecePP1piiii@PLT
	ucomisd	.LC2(%rip), %xmm0
	jp	.L22
	je	.L20
	jmp	.L22
.L19:
	leaq	.LC3(%rip), %rsi
	movl	$2, %edi
	xorl	%eax, %eax
	call	__printf_chk@PLT
	jmp	.L23
.L22:
	orl	$-1, %ebp
.L20:
	movq	%rbx, %rdi
	call	free@PLT
	addq	$24, %rsp
	.cfi_def_cfa_offset 56
	movl	%ebp, %eax
	popq	%rbx
	.cfi_def_cfa_offset 48
	popq	%rbp
	.cfi_def_cfa_offset 40
	popq	%r12
	.cfi_def_cfa_offset 32
	popq	%r13
	.cfi_def_cfa_offset 24
	popq	%r14
	.cfi_def_cfa_offset 16
	popq	%r15
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE2030:
	.size	_Z14makePlayerTurnPP1pi, .-_Z14makePlayerTurnPP1pi
	.globl	_Z8makeTurnPP1piiP2nnPdPPS4_S5_Pi
	.type	_Z8makeTurnPP1piiP2nnPdPPS4_S5_Pi, @function
_Z8makeTurnPP1piiP2nnPdPPS4_S5_Pi:
.LFB2031:
	.cfi_startproc
	endbr64
	pushq	%r15
	.cfi_def_cfa_offset 16
	.cfi_offset 15, -16
	pushq	%r14
	.cfi_def_cfa_offset 24
	.cfi_offset 14, -24
	pushq	%r13
	.cfi_def_cfa_offset 32
	.cfi_offset 13, -32
	movq	%r8, %r13
	pushq	%r12
	.cfi_def_cfa_offset 40
	.cfi_offset 12, -40
	movslq	%edx, %r12
	pushq	%rbp
	.cfi_def_cfa_offset 48
	.cfi_offset 6, -48
	movq	%r9, %rbp
	pushq	%rbx
	.cfi_def_cfa_offset 56
	.cfi_offset 3, -56
	movq	%rcx, %rbx
	subq	$56, %rsp
	.cfi_def_cfa_offset 112
	movl	%esi, 12(%rsp)
	movq	%r8, %rsi
	movq	%rdi, (%rsp)
	call	_Z12oneHotEncodePP1pPd@PLT
	leaq	0(,%r12,8), %rax
	movq	%r13, %rdx
	movq	%rbx, %rdi
	movq	%rax, 32(%rsp)
	addq	%rbp, %rax
	xorl	%r13d, %r13d
	movq	%rax, %rsi
	movq	%rax, 16(%rsp)
	call	_Z11feedForwardP2nnPPPdS1_@PLT
	call	rand@PLT
	movsd	.LC5(%rip), %xmm1
	cvtsi2sdl	%eax, %xmm0
	movq	120(%rsp), %rax
	divsd	.LC4(%rip), %xmm0
	comisd	%xmm0, %xmm1
	leaq	(%rax,%r12,4), %rax
	movq	%rax, 24(%rsp)
	seta	%r13b
	orl	$-1, %r12d
.L34:
	movq	32(%rsp), %r14
	addq	112(%rsp), %r14
	testl	%r13d, %r13d
	je	.L26
	call	rand@PLT
	movslq	(%rbx), %rcx
	movq	8(%rbx), %rsi
	cltd
	idivl	-4(%rsi,%rcx,4)
	movslq	%edx, %rbp
	movl	%ebp, %edi
	call	_Z16parseIndexToMovei
	movl	12(%rsp), %r9d
	movq	(%rsp), %rdi
	movl	8(%rax), %ecx
	movl	4(%rax), %edx
	movq	%rax, %r15
	movl	12(%rax), %r8d
	movl	(%rax), %esi
	call	_Z11isValidMovePP1piiiii@PLT
	testl	%eax, %eax
	je	.L27
	movl	4(%r15), %edx
	movl	8(%r15), %ecx
	movl	12(%r15), %r8d
	movl	(%r15), %esi
	movq	(%rsp), %rdi
	call	_Z9movePiecePP1piiii@PLT
	subsd	.LC5(%rip), %xmm0
	movq	(%r14), %rax
	movslq	%ebp, %rdx
	ucomisd	.LC6(%rip), %xmm0
	movsd	%xmm0, (%rax,%rdx,8)
	movq	24(%rsp), %rax
	movl	%ebp, (%rax)
	jp	.L28
	cmove	12(%rsp), %r12d
	jmp	.L28
.L27:
	movq	(%r14), %rax
	movq	.LC7(%rip), %rsi
	xorl	%r13d, %r13d
	movq	%rsi, (%rax,%rbp,8)
.L28:
	movq	%r15, %rdi
	call	free@PLT
	movl	%r13d, %eax
	jmp	.L30
.L26:
	movslq	(%rbx), %rax
	movq	8(%rbx), %rdx
	movq	16(%rsp), %rdi
	movl	-4(%rdx,%rax,4), %esi
	movq	(%rdi), %rdx
	movq	-8(%rdx,%rax,8), %rdi
	call	_Z11getMaxIndexPdi
	movl	%eax, %edi
	movl	%eax, %ebp
	call	_Z16parseIndexToMovei
	movl	12(%rsp), %r9d
	movq	(%rsp), %rdi
	movl	8(%rax), %ecx
	movl	4(%rax), %edx
	movq	%rax, %r13
	movl	12(%rax), %r8d
	movl	(%rax), %esi
	call	_Z11isValidMovePP1piiiii@PLT
	movslq	%ebp, %r9
	testl	%eax, %eax
	je	.L31
	movl	8(%r13), %ecx
	movl	4(%r13), %edx
	movq	%r9, 40(%rsp)
	movl	12(%r13), %r8d
	movl	0(%r13), %esi
	movq	(%rsp), %rdi
	call	_Z9movePiecePP1piiii@PLT
	subsd	.LC5(%rip), %xmm0
	movq	(%r14), %rax
	movq	40(%rsp), %r9
	ucomisd	.LC6(%rip), %xmm0
	movsd	%xmm0, (%rax,%r9,8)
	movq	24(%rsp), %rax
	movl	%ebp, (%rax)
	jp	.L41
	jne	.L41
	movl	12(%rsp), %r12d
	jmp	.L41
.L31:
	movq	(%r14), %rdx
	movq	.LC7(%rip), %rsi
	movq	%rsi, (%rdx,%r9,8)
	jmp	.L32
.L41:
	movl	$1, %eax
.L32:
	movq	%r13, %rdi
	movl	%eax, 40(%rsp)
	call	free@PLT
	movl	40(%rsp), %eax
.L30:
	movl	$1, %r13d
	testl	%eax, %eax
	je	.L34
	addq	$56, %rsp
	.cfi_def_cfa_offset 56
	movl	%r12d, %eax
	popq	%rbx
	.cfi_def_cfa_offset 48
	popq	%rbp
	.cfi_def_cfa_offset 40
	popq	%r12
	.cfi_def_cfa_offset 32
	popq	%r13
	.cfi_def_cfa_offset 24
	popq	%r14
	.cfi_def_cfa_offset 16
	popq	%r15
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE2031:
	.size	_Z8makeTurnPP1piiP2nnPdPPS4_S5_Pi, .-_Z8makeTurnPP1piiP2nnPdPPS4_S5_Pi
	.globl	_Z8playGameP2nnS0_iPdPPS1_S3_S2_S2_PiS4_S4_S4_
	.type	_Z8playGameP2nnS0_iPdPPS1_S3_S2_S2_PiS4_S4_S4_, @function
_Z8playGameP2nnS0_iPdPPS1_S3_S2_S2_PiS4_S4_S4_:
.LFB2032:
	.cfi_startproc
	endbr64
	pushq	%r15
	.cfi_def_cfa_offset 16
	.cfi_offset 15, -16
	movq	%r9, %r15
	pushq	%r14
	.cfi_def_cfa_offset 24
	.cfi_offset 14, -24
	movq	%r8, %r14
	pushq	%r13
	.cfi_def_cfa_offset 32
	.cfi_offset 13, -32
	movl	%edx, %r13d
	pushq	%r12
	.cfi_def_cfa_offset 40
	.cfi_offset 12, -40
	pushq	%rbp
	.cfi_def_cfa_offset 48
	.cfi_offset 6, -48
	pushq	%rbx
	.cfi_def_cfa_offset 56
	.cfi_offset 3, -56
	xorl	%ebx, %ebx
	subq	$40, %rsp
	.cfi_def_cfa_offset 96
	movq	%rdi, 16(%rsp)
	movq	128(%rsp), %r12
	movq	%rsi, 24(%rsp)
	movq	136(%rsp), %rbp
	movq	%rcx, 8(%rsp)
	call	_Z14makeChessBoardv@PLT
	movq	%rax, (%rsp)
.L47:
	cmpl	%r13d, %ebx
	jne	.L43
	movq	(%rsp), %rdi
	call	_Z15printChessBoardPP1p@PLT
	movq	(%rsp), %rdi
	movl	%ebx, %esi
	call	_Z14makePlayerTurnPP1pi
	jmp	.L44
.L43:
	testl	%ebx, %ebx
	jne	.L45
	pushq	112(%rsp)
	.cfi_remember_state
	.cfi_def_cfa_offset 104
	movl	(%r12), %edx
	movq	%r14, %r9
	xorl	%esi, %esi
	pushq	104(%rsp)
	.cfi_def_cfa_offset 112
	movq	24(%rsp), %r8
	movq	32(%rsp), %rcx
	movq	16(%rsp), %rdi
	call	_Z8makeTurnPP1piiP2nnPdPPS4_S5_Pi
	incl	(%r12)
	jmp	.L50
.L45:
	.cfi_restore_state
	pushq	120(%rsp)
	.cfi_def_cfa_offset 104
	movl	0(%rbp), %edx
	movq	%r15, %r9
	movl	$1, %esi
	pushq	112(%rsp)
	.cfi_def_cfa_offset 112
	movq	24(%rsp), %r8
	movq	40(%rsp), %rcx
	movq	16(%rsp), %rdi
	call	_Z8makeTurnPP1piiP2nnPdPPS4_S5_Pi
	incl	0(%rbp)
.L50:
	popq	%rdx
	.cfi_def_cfa_offset 104
	popq	%rcx
	.cfi_def_cfa_offset 96
.L44:
	xorl	$1, %ebx
	testl	%eax, %eax
	jns	.L46
	cmpl	$74, (%r12)
	jg	.L46
	cmpl	$74, 0(%rbp)
	jle	.L47
.L46:
	movq	(%rsp), %rdi
	movl	%eax, 8(%rsp)
	call	_Z15printChessBoardPP1p@PLT
	movq	(%rsp), %rdi
	call	_Z14freeChessBoardPP1p@PLT
	movl	8(%rsp), %eax
	addq	$40, %rsp
	.cfi_def_cfa_offset 56
	popq	%rbx
	.cfi_def_cfa_offset 48
	popq	%rbp
	.cfi_def_cfa_offset 40
	popq	%r12
	.cfi_def_cfa_offset 32
	popq	%r13
	.cfi_def_cfa_offset 24
	popq	%r14
	.cfi_def_cfa_offset 16
	popq	%r15
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE2032:
	.size	_Z8playGameP2nnS0_iPdPPS1_S3_S2_S2_PiS4_S4_S4_, .-_Z8playGameP2nnS0_iPdPPS1_S3_S2_S2_PiS4_S4_S4_
	.globl	_Z13alterExpectedP2nnPPPdS2_Piiii
	.type	_Z13alterExpectedP2nnPPPdS2_Piiii, @function
_Z13alterExpectedP2nnPPPdS2_Piiii:
.LFB2033:
	.cfi_startproc
	endbr64
	pushq	%r15
	.cfi_def_cfa_offset 16
	.cfi_offset 15, -16
	decl	%r8d
	movsd	.LC7(%rip), %xmm1
	movq	%rsi, %r10
	pushq	%r14
	.cfi_def_cfa_offset 24
	.cfi_offset 14, -24
	movsd	.LC9(%rip), %xmm2
	movq	%rdx, %rsi
	movslq	%r8d, %rax
	pushq	%r13
	.cfi_def_cfa_offset 32
	.cfi_offset 13, -32
	movq	%rcx, %rdx
	pushq	%r12
	.cfi_def_cfa_offset 40
	.cfi_offset 12, -40
	pushq	%rbp
	.cfi_def_cfa_offset 48
	.cfi_offset 6, -48
	pushq	%rbx
	.cfi_def_cfa_offset 56
	.cfi_offset 3, -56
	movl	56(%rsp), %r11d
.L52:
	movl	%eax, %r14d
	testl	%eax, %eax
	js	.L59
	movslq	(%rdi), %rcx
	movq	8(%rdi), %rbx
	leaq	-8(,%rcx,8), %r12
	movl	-4(%rbx,%rcx,4), %r13d
	xorl	%ecx, %ecx
.L60:
	movl	%ecx, %r15d
	cmpl	%ecx, %r13d
	jle	.L64
	movq	(%rsi,%rax,8), %rbx
	leaq	0(,%rcx,8), %rbp
	addq	%rbp, %rbx
	ucomisd	(%rbx), %xmm1
	jp	.L61
	je	.L53
.L61:
	cmpl	%r15d, (%rdx,%rax,4)
	je	.L53
	movq	(%r10,%rax,8), %r15
	movq	(%r15,%r12), %r15
	movsd	(%r15,%rbp), %xmm0
	movsd	%xmm0, (%rbx)
.L53:
	incq	%rcx
	jmp	.L60
.L64:
	cmpl	%r8d, %r14d
	jne	.L56
	testl	%r9d, %r9d
	je	.L57
	movslq	(%rdx,%rax,4), %rbx
	movq	(%rsi,%rax,8), %rcx
	movsd	.LC8(%rip), %xmm0
	leaq	(%rcx,%rbx,8), %rcx
	addsd	(%rcx), %xmm0
	jmp	.L63
.L57:
	testl	%r11d, %r11d
	jne	.L58
	movslq	(%rdx,%rax,4), %rbx
	movq	(%rsi,%rax,8), %rcx
	leaq	(%rcx,%rbx,8), %rcx
	movsd	(%rcx), %xmm0
	subsd	.LC8(%rip), %xmm0
.L63:
	movsd	%xmm0, (%rcx)
	jmp	.L58
.L56:
	movslq	(%rdx,%rax,4), %rbx
	movq	(%rsi,%rax,8), %rcx
	movslq	4(%rdx,%rax,4), %rbp
	leaq	(%rcx,%rbx,8), %rcx
	movq	8(%rsi,%rax,8), %rbx
	movsd	(%rbx,%rbp,8), %xmm0
	mulsd	%xmm2, %xmm0
	addsd	(%rcx), %xmm0
	movsd	%xmm0, (%rcx)
	movl	$-1, 4(%rdx,%rax,4)
.L58:
	decq	%rax
	jmp	.L52
.L59:
	popq	%rbx
	.cfi_def_cfa_offset 48
	popq	%rbp
	.cfi_def_cfa_offset 40
	movl	$-1, (%rdx)
	popq	%r12
	.cfi_def_cfa_offset 32
	popq	%r13
	.cfi_def_cfa_offset 24
	popq	%r14
	.cfi_def_cfa_offset 16
	popq	%r15
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE2033:
	.size	_Z13alterExpectedP2nnPPPdS2_Piiii, .-_Z13alterExpectedP2nnPPPdS2_Piiii
	.section	.rodata.str1.1
.LC10:
	.string	"Serializing the neural networks\n"
.LC11:
	.string	"Training on game %d\n"
.LC12:
	.string	"Backpropogating\n"
	.text
	.globl	_Z5trainP2nnS0_iPcS1_
	.type	_Z5trainP2nnS0_iPcS1_, @function
_Z5trainP2nnS0_iPcS1_:
.LFB2034:
	.cfi_startproc
	endbr64
	pushq	%r15
	.cfi_def_cfa_offset 16
	.cfi_offset 15, -16
	pushq	%r14
	.cfi_def_cfa_offset 24
	.cfi_offset 14, -24
	pushq	%r13
	.cfi_def_cfa_offset 32
	.cfi_offset 13, -32
	pushq	%r12
	.cfi_def_cfa_offset 40
	.cfi_offset 12, -40
	pushq	%rbp
	.cfi_def_cfa_offset 48
	.cfi_offset 6, -48
	pushq	%rbx
	.cfi_def_cfa_offset 56
	.cfi_offset 3, -56
	movq	%rdi, %rbx
	subq	$88, %rsp
	.cfi_def_cfa_offset 144
	movq	8(%rdi), %rax
	movq	%rsi, 8(%rsp)
	movl	$8, %esi
	movslq	(%rax), %rdi
	movq	%rcx, 56(%rsp)
	movl	%edx, 44(%rsp)
	movq	%r8, 64(%rsp)
	call	calloc@PLT
	movl	$75, %esi
	movq	%rbx, %rdi
	movq	%rax, 48(%rsp)
	call	_Z12makeExpectedP2nni@PLT
	movq	8(%rsp), %rdi
	movl	$75, %esi
	movq	%rax, 16(%rsp)
	call	_Z12makeExpectedP2nni@PLT
	movl	$75, %esi
	movq	%rbx, %rdi
	movq	%rax, 24(%rsp)
	call	_Z10makeActualP2nni@PLT
	movq	8(%rsp), %rdi
	movl	$75, %esi
	movq	%rax, 32(%rsp)
	call	_Z10makeActualP2nni@PLT
	movl	$4, %esi
	movl	$75, %edi
	movq	%rax, %r13
	call	calloc@PLT
	movl	$75, %edi
	movl	$4, %esi
	movq	%rax, %rbp
	call	calloc@PLT
	movl	$300, %ecx
	movq	%rbp, %rdi
	movq	%rax, %r12
	movb	$-1, %al
	rep stosb
	movl	$300, %ecx
	movq	%r12, %rdi
	rep stosb
	xorl	%ecx, %ecx
	movl	%ecx, 40(%rsp)
.L68:
	movl	40(%rsp), %eax
	movl	$5, %ecx
	cltd
	idivl	%ecx
	testl	%edx, %edx
	jne	.L66
	leaq	.LC10(%rip), %rsi
	movl	$2, %edi
	xorl	%eax, %eax
	call	__printf_chk@PLT
	movq	56(%rsp), %rsi
	movq	%rbx, %rdi
	call	_Z18serializeNeuralNetP2nnPc@PLT
	movq	64(%rsp), %rsi
	movq	8(%rsp), %rdi
	call	_Z18serializeNeuralNetP2nnPc@PLT
.L66:
	movl	$4, %esi
	movl	$1, %edi
	call	calloc@PLT
	movl	$4, %esi
	movl	$1, %edi
	movq	%rax, %r15
	call	calloc@PLT
	movl	40(%rsp), %edx
	movl	$2, %edi
	leaq	.LC11(%rip), %rsi
	movq	%rax, %r14
	xorl	%eax, %eax
	call	__printf_chk@PLT
	pushq	%r14
	.cfi_def_cfa_offset 152
	movq	%rbx, %rdi
	pushq	%r15
	.cfi_def_cfa_offset 160
	pushq	%r12
	.cfi_def_cfa_offset 168
	pushq	%rbp
	.cfi_def_cfa_offset 176
	pushq	%r13
	.cfi_def_cfa_offset 184
	pushq	72(%rsp)
	.cfi_def_cfa_offset 192
	movq	72(%rsp), %r9
	movq	64(%rsp), %r8
	movq	96(%rsp), %rcx
	movl	92(%rsp), %edx
	movq	56(%rsp), %rsi
	call	_Z8playGameP2nnS0_iPdPPS1_S3_S2_S2_PiS4_S4_S4_
	addq	$40, %rsp
	.cfi_def_cfa_offset 152
	xorl	%r10d, %r10d
	movl	(%r15), %r8d
	cmpl	$-1, %eax
	movl	%eax, 84(%rsp)
	movq	%rbp, %rcx
	movq	%rbx, %rdi
	sete	%r10b
	testl	%eax, %eax
	pushq	%r10
	.cfi_def_cfa_offset 160
	sete	%r9b
	movq	48(%rsp), %rdx
	movq	32(%rsp), %rsi
	movzbl	%r9b, %r9d
	movl	%r10d, 88(%rsp)
	call	_Z13alterExpectedP2nnPPPdS2_Piiii
	movl	92(%rsp), %eax
	movl	(%r14), %r8d
	xorl	%r9d, %r9d
	movl	88(%rsp), %r10d
	movq	40(%rsp), %rsi
	movq	%r13, %rdx
	movq	%r12, %rcx
	decl	%eax
	movq	24(%rsp), %rdi
	sete	%r9b
	movl	%r10d, (%rsp)
	call	_Z13alterExpectedP2nnPPPdS2_Piiii
	movq	%r15, %rdi
	call	free@PLT
	movq	%r14, %rdi
	call	free@PLT
	popq	%rax
	.cfi_def_cfa_offset 152
	popq	%rdx
	.cfi_def_cfa_offset 144
	cmpl	$-1, 44(%rsp)
	jne	.L67
	leaq	.LC12(%rip), %rsi
	movl	$2, %edi
	xorl	%eax, %eax
	call	__printf_chk@PLT
	movq	32(%rsp), %rdx
	movq	16(%rsp), %rsi
	movq	%rbx, %rdi
	movl	$75, %ecx
	call	_Z13backpropogateP2nnPPPdS2_i@PLT
	movq	24(%rsp), %rsi
	movq	8(%rsp), %rdi
	movq	%r13, %rdx
	movl	$75, %ecx
	call	_Z13backpropogateP2nnPPPdS2_i@PLT
.L67:
	incl	40(%rsp)
	jmp	.L68
	.cfi_endproc
.LFE2034:
	.size	_Z5trainP2nnS0_iPcS1_, .-_Z5trainP2nnS0_iPcS1_
	.section	.text.startup,"ax",@progbits
	.type	_ZL24__sti____cudaRegisterAllv, @function
_ZL24__sti____cudaRegisterAllv:
.LFB2060:
	.cfi_startproc
	endbr64
	pushq	%rax
	.cfi_def_cfa_offset 16
	leaq	_ZL15__fatDeviceText(%rip), %rdi
	call	__cudaRegisterFatBinary@PLT
	movq	%rax, %rdi
	movq	%rax, _ZL20__cudaFatCubinHandle(%rip)
	call	__cudaRegisterFatBinaryEnd@PLT
	leaq	_ZL26__cudaUnregisterBinaryUtilv(%rip), %rdi
	popq	%rdx
	.cfi_def_cfa_offset 8
	jmp	atexit@PLT
	.cfi_endproc
.LFE2060:
	.size	_ZL24__sti____cudaRegisterAllv, .-_ZL24__sti____cudaRegisterAllv
	.section	.init_array,"aw"
	.align 8
	.quad	_ZL24__sti____cudaRegisterAllv
	.section	.nvFatBinSegment,"aw"
	.align 8
	.type	_ZL15__fatDeviceText, @object
	.size	_ZL15__fatDeviceText, 24
_ZL15__fatDeviceText:
	.long	1180844977
	.long	1
	.quad	fatbinData
	.quad	0
	.local	_ZL20__cudaFatCubinHandle
	.comm	_ZL20__cudaFatCubinHandle,8,8
	.section	.rodata.cst8,"aM",@progbits,8
	.align 8
.LC0:
	.long	0
	.long	1075838976
	.align 8
.LC2:
	.long	0
	.long	1078198272
	.align 8
.LC4:
	.long	-4194304
	.long	1105199103
	.align 8
.LC5:
	.long	-1717986918
	.long	1069128089
	.align 8
.LC6:
	.long	858993459
	.long	1078194995
	.align 8
.LC7:
	.long	0
	.long	-1074790400
	.align 8
.LC8:
	.long	0
	.long	1077477376
	.align 8
.LC9:
	.long	0
	.long	1070596096
	.ident	"GCC: (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

#ifndef GAME
#define GAME

#include "VerifyMove.cuh"
#include "./../NeuralNetwork/Backpropogation.cuh"
#include "./../NeuralNetwork/FeedForward.cuh"
#include "./../NeuralNetwork/NeuralNetwork.cuh"
#include "./../Serialize/SerializeDeserialize.cuh"

#define TURNS 75
#define EXPLORATION .1
#define DISCOUNT .25
#define WINREWARD 100
#define LOSSREWARD -100
#define TURNDEFICIT -.1


void train(NeuralNet* nn1, NeuralNet* nn2, int playerColor, char* file1, char* file2);

#endif

	.text
	.file	"Game.hip"
	.type	__hip_cuid_,@object             # @__hip_cuid_
	.bss
	.globl	__hip_cuid_
__hip_cuid_:
	.byte	0                               # 0x0
	.size	__hip_cuid_, 1

	.ident	"AMD clang version 18.0.0git (https://github.com/RadeonOpenCompute/llvm-project roc-6.3.2 25012 e5bf7e55c91490b07c49d8960fa7983d864936c4)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym __hip_cuid_

	.text
	.p2alignl 7, 3214868480
	.fill 96, 4, 3214868480
	.type	__hip_cuid_,@object             ; @__hip_cuid_
	.section	.bss,"aw",@nobits
	.globl	__hip_cuid_
__hip_cuid_:
	.byte	0                               ; 0x0
	.size	__hip_cuid_, 1

	.ident	"AMD clang version 18.0.0git (https://github.com/RadeonOpenCompute/llvm-project roc-6.3.2 25012 e5bf7e55c91490b07c49d8960fa7983d864936c4)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym __hip_cuid_
	.amdgcn_target "amdgcn-amd-amdhsa--gfx1100"
	.amdgpu_metadata
---
amdhsa.kernels:  []
amdhsa.target:   amdgcn-amd-amdhsa--gfx1100
amdhsa.version:
  - 1
  - 2
...

	.end_amdgpu_metadata
