function AI() {

	this.moves = [0,1,2,3];
	this.brain = new deepqlearn.Brain(19,4, {
		epsilon_test_time: 0.1,
		epsilon_min: 0.1,
		experience_size: 300000
	});
	this.previousMove = 0;	
	this.previousMoved = false;
}

AI.prototype.getMaxVal = function() {
	var max = 0;
	this.grid.cells.forEach(function(row){
		row.forEach( function( curVal ){
			if( curVal && curVal.value > max )
				max = curVal.value;
		});
	});

	if( StateManager.maxVal < max ){
		StateManager.maxVal = max;
		document.getElementById('max-value').innerHTML = 'Max Value is: ' + max;
	}

	return max;
}

AI.prototype.getEmptyCount = function() {

	var count = 0;
	this.grid.cells.forEach(function(row) {
		row.forEach( function( curVal ) {
			if( curVal )
				return;
			
			count++;
		});
	});

	return count;

}

AI.prototype.buildInputs = function(score, moved, timesMoved, pMove) {

	var inputs = [];

	var max = this.getMaxVal();

	this.grid.cells.forEach(function(row, index) {
		row.forEach( function( curVal ) {
			
			if( curVal ){
				inputs.push( ( 1 + ( -1 / curVal.value ) ) );
			}else{
				inputs.push(0);
			}
		});
	});

	inputs.push( ( this.previousMove > 0 ) ? this.previousMove / 4      : 0 );
	inputs.push( ( score > 0 )             ? ( 1 + ( -1 / score ) )     : 0 );
	inputs.push( ( moved )                 ? 1                          : 0 );
	inputs.push( ( this.getEmptyCount() > 0 ) ? this.getEmptyCount()    : 0 );

//	console.log('Inputs: ', inputs);
	return inputs;

}

AI.prototype.getBest = function(grid, meta) {
	this.grid = grid;
	var inputs = this.buildInputs( meta.score, meta.moved );
	var action = this.brain.forward( inputs );
	
	var move = {
		move: this.moves[action]
	};

	this.previousMove = move.move;
	
	return move;

}

AI.prototype.setMoved = function(moved){
	this.previousMoved = moved;
}

AI.prototype.reward = function(meta) {

	var max = this.getMaxVal();	
	if( meta.over && meta.won ){

		reward = 1;

	}else if( meta.score != meta.previous ) {

		reward  = ( 1 + (-1 / ( meta.score - meta.previous ) ) );
	//	reward += ( ( meta.empty > 0 ) ? ( meta.empty / 16 ) : 0 );
	//	reward /= 4;

	}else{

		reward = -(0.5);

	}

	if( meta.over && !meta.won ){
//		console.log('Inverting Reward due to Loss');
		reward *= -1;
	}
//	console.log('Reward: ', reward );
	this.brain.backward( reward );
	this.brain.visSelf(document.getElementById('brainInfo'));

}

AI.prototype.rewardMultiple = function(meta){

	var max = this.getMaxVal();
	var scoreReward = ( 1 + (-1 / (meta.score - meta.previous ) ) );
	var maxReward = ( 1 + ( ( -1 * max ) / meta.score ) );
	var movesReward = ( ( meta.timesMoved > 0 ) ? ( 1 + (-1 / meta.timesMoved ) ) : 0);
	var emptyReward = ( ( meta.empty > 0 ) ? ( 1 + (-1 / meta.empty ) ) : 0 );

	this.brain.backward( scoreReward );
	this.brain.backward( maxReward );
	this.brain.backward( movesReward );
	this.brain.backward( emptyReward );
	this.brain.visSelf(document.getElementById('brainInfo'));

}

@@ -2114,24 +2114,26 @@
 %0A%0A%09%7Delse%7B%0A%0A%09
+//
 %09reward = -(
@@ -2144,16 +2144,18 @@
 ;%0A%0A%09%7D%0A%0A%09
+//
 if( meta
@@ -2226,16 +2226,18 @@
 oss');%0A%09
+//
 %09reward 
@@ -2244,16 +2244,18 @@
 *= -1;%0A%09
+//
 %7D%0A//%09con

No negative reward