Code
First create a html file and name it pingpong.html
<div id='mainContent'></div>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.11.2"> </script>
<script src="pingpong.js"></script>
We could reuse a code of a pingpong and we can add AI by tensorflow js:
Now we just need to add the pong game code. I am going to just go in order of the script itself. To begin, we want to defined our model:
// Model Definition
const model = tf.sequential();
model.add(tf.layers.dense({units: 256, inputShape: [8]})); //input is a 1x8
model.add(tf.layers.dense({units: 512, inputShape: [256], activation:"sigmoid"}));
model.add(tf.layers.dense({units: 256, inputShape: [512], activation:"sigmoid"}));
model.add(tf.layers.dense({units: 3, inputShape: [256]})); //returns a 1x3
const learningRate = 0.001;
const optimizer = tf.train.adam(learningRate);
model.compile({loss: 'meanSquaredError', optimizer: optimizer});
For this game of Pong, we're going to take in the following elements as input features:
Player paddle x
Computer paddle x
Ball x
Ball y
previous ball x
previous ball y
previous player paddle x
previous computer paddle x
Eventually, we'll have a model that outputs 3 things: Move left, do nothing, move right, which will translate to: [1,0,0], [0,1,0] or [0,0,1]. We'll then find the argmax of that, and pass that as a -1, 0, or 1, so the above function moves at a multiple of 4 that many pixels. So, if the model outputs a [1,0,0], the argmax is 0. To translate the argmax to a -1,0, or 1, we do -1. We subtract 1 from 0, getting -1.
Then -1 is passed to the ai_update function, where -1 is multipleid by 4 to be -4, and the paddle is moved -4 pixels on the x-axis (4 pixels left).
Now, in order to train the AI, we need to be able to collect data, so we store it to variables:
function AI(){
this.previous_data = null;
this.training_data = [[], [], []];
this.last_data_object = null;
this.turn = 0;
this.grab_data = true;
this.flip_table = true;
}
Then save them to an array every frame:
// Custom code:
// Saved data per frame
AI.prototype.save_data = function(player, computer, ball){
if(!this.grab_data)
return;
// First frame (no prior data):
if(this.previous_data == null){
data = this.flip_table ? [width - computer.x, width - player.x, width - ball.x, height - ball.y] : [player.x, computer.x, ball.x, ball.y];
this.previous_data = data;
return;
}
// table is rotated to learn from player, but apply to computer position:
if(this.flip_table){
data_xs = [width - computer.x, width - player.x, width - ball.x, height - ball.y];
index = ((width - player.x) > this.previous_data[1])?0:(((width - player.x) == this.previous_data[1])?1:2);
}else{
data_xs = [player.x, computer.x, ball.x, ball.y];
index = (player.x < this.previous_data[0])?0:((player.x == this.previous_data[0])?1:2);
}
this.last_data_object = [...this.previous_data, ...data_xs];
this.training_data[index].push(this.last_data_object);
this.previous_data = data_xs;
}
Deciding whether to play as ai
AI.prototype.new_turn = function(){
this.previous_data = null;
this.turn++;
console.log('new turn: ' + this.turn);
//hm games til train?
if(this.turn > 1){
this.train();
computer.ai_plays = true;
this.reset();
}
}
And then code to make predictions:
// TensorFlow JS code:
AI.prototype.predict_move = function(){
console.log('predicting');
if(this.last_data_object != null){
//use this.last_data_object for input data
//do prediction here
//return -1/0/1
prediction = model.predict(tf.tensor([this.last_data_object]));
return tf.argMax(prediction, 1).dataSync()-1;
}
}
Last updated
Was this helpful?