345 lines
6.8 KiB
C++
345 lines
6.8 KiB
C++
#include <allegro.h>
|
|
#include <cstdlib>
|
|
#include <time.h>
|
|
#include "../src/NeuronNetwork/Learning/QLearning.h"
|
|
#include <sys/time.h>
|
|
|
|
int learningGames=6000;
|
|
|
|
int ball_x = 320;
|
|
int ball_y = 240;
|
|
|
|
int ball_tempX = 320;
|
|
int ball_tempY = 240;
|
|
|
|
int p1_x = 20;
|
|
int p1_y = 210;
|
|
|
|
int p1_tempX = 20;
|
|
int p1_tempY = 210;
|
|
|
|
int p2_x = 620;
|
|
int p2_y = 210;
|
|
|
|
int p2_tempX = 620;
|
|
int p2_tempY = 210;
|
|
|
|
int i=0;
|
|
|
|
long game=0;
|
|
int q=0;
|
|
int speed=1;
|
|
|
|
bool randomLearner=0;
|
|
|
|
int dir; //This will keep track of the circles direction
|
|
//1= up and left, 2 = down and left, 3= up and right, 4 = down and right
|
|
|
|
BITMAP *buffer; //This will be our temporary bitmap for double buffering
|
|
|
|
class X: public Shin::NeuronNetwork::Problem
|
|
{
|
|
public:
|
|
X(int p1,int ballX,int ballY,int p2)//, int ballY)
|
|
{
|
|
data.push_back((float)p1/480.0);
|
|
data.push_back((float)ballX/640.0);
|
|
data.push_back((float)ballY/480.0);
|
|
}
|
|
};
|
|
|
|
Shin::NeuronNetwork::Learning::QLearning l(3,15,3);
|
|
|
|
std::vector <std::pair<Shin::NeuronNetwork::Problem,int>> p1x;
|
|
|
|
void propagateOKtoP1(double quality=10)
|
|
{
|
|
l.learnDelayed(p1x,quality);
|
|
p1x.clear();
|
|
}
|
|
|
|
void moveBall(){
|
|
|
|
ball_tempX = ball_x;
|
|
ball_tempY = ball_y;
|
|
|
|
if (dir == 1 && ball_x > 5 && ball_y > 5){
|
|
|
|
if( ball_x == p1_x + 15 && ball_y >= p1_y && ball_y <= p1_y + 60){
|
|
dir = rand()% 2 + 3;
|
|
propagateOKtoP1(100);
|
|
}else{
|
|
--ball_x;
|
|
--ball_y;
|
|
}
|
|
|
|
} else if (dir == 2 && ball_x > 5 && ball_y < 475){
|
|
|
|
if( ball_x == p1_x + 15 && ball_y >= p1_y && ball_y <= p1_y + 60){
|
|
dir = rand()% 2 + 3;
|
|
propagateOKtoP1(100);
|
|
}else{
|
|
--ball_x;
|
|
++ball_y;
|
|
}
|
|
|
|
} else if (dir == 3 && ball_x < 635 && ball_y > 5){
|
|
|
|
if( ball_x + 5 == p2_x && ball_y >= p2_y && ball_y <= p2_y + 60){
|
|
dir = rand()% 2 + 1;
|
|
}else{
|
|
++ball_x;
|
|
--ball_y;
|
|
}
|
|
|
|
} else if (dir == 4 && ball_x < 635 && ball_y < 475){
|
|
|
|
if( ball_x + 5 == p2_x && ball_y >= p2_y && ball_y <= p2_y + 60){
|
|
dir = rand()% 2 + 1;
|
|
}else{
|
|
++ball_x;
|
|
++ball_y;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (dir == 1 || dir == 3) ++dir;
|
|
else if (dir == 2 || dir == 4) --dir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
char p1Move(){
|
|
|
|
X p=X(p1_y,ball_x,ball_y,p2_y);
|
|
|
|
if(game <learningGames)
|
|
{
|
|
if(randomLearner)
|
|
{
|
|
register int tmp=game%3;
|
|
if(rand()%5==0)
|
|
{
|
|
tmp=(tmp+rand())%3;
|
|
}
|
|
if(tmp==1)
|
|
{
|
|
p1x.push_back(std::pair<Shin::NeuronNetwork::Problem,int>(p,2));//,ball_tempX,ball_tempY));
|
|
return 1;
|
|
}else if(tmp==0)
|
|
{
|
|
p1x.push_back(std::pair<Shin::NeuronNetwork::Problem,int>(p,0));//,ball_tempX,ball_tempY));
|
|
return -1;
|
|
}else
|
|
{
|
|
p1x.push_back(std::pair<Shin::NeuronNetwork::Problem,int>(p,1));//,ball_tempX,ball_tempY));
|
|
return 0;
|
|
}
|
|
}else
|
|
{
|
|
if( p1_tempY > ball_y && p1_y > 0){
|
|
p1x.push_back(std::pair<Shin::NeuronNetwork::Problem,int>(p,0));//,ball_tempX,ball_tempY));
|
|
return -1;
|
|
} else if( p1_tempY < ball_y && p1_y < 420){
|
|
p1x.push_back(std::pair<Shin::NeuronNetwork::Problem,int>(p,2));//,ball_tempX,ball_tempY));
|
|
return 1;
|
|
}else
|
|
{
|
|
p1x.push_back(std::pair<Shin::NeuronNetwork::Problem,int>(p,1));//,ball_tempX,ball_tempY));
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
int j=l.getChoice(p);
|
|
|
|
p1x.push_back(std::pair<Shin::NeuronNetwork::Problem,int>(p,j));//,ball_tempX,ball_tempY));
|
|
|
|
return j-1;
|
|
}
|
|
|
|
char p2Move(){
|
|
if(game >= learningGames)
|
|
{
|
|
if(key[KEY_UP])
|
|
return 1;
|
|
else if( key[KEY_DOWN])
|
|
return -1;
|
|
else
|
|
return 0;
|
|
}else
|
|
{
|
|
if(rand()%10==0)
|
|
{
|
|
return (rand()%3)-1;
|
|
}
|
|
if( p2_tempY > ball_y){
|
|
return -1;
|
|
} else if( p2_tempY < ball_y){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void startNew(){
|
|
|
|
clear_keybuf();
|
|
if(game==learningGames)
|
|
textout_ex( screen, font, "Player 1 learned! Push a button to start a game.", 160, 240, makecol( 255, 0, 0), makecol( 0, 0, 0));
|
|
|
|
if(game >= learningGames)
|
|
readkey();
|
|
|
|
clear_to_color( buffer, makecol( 0, 0, 0));
|
|
ball_x = 350;
|
|
ball_y = rand()%481;
|
|
|
|
p1_x = 20;
|
|
p1_y = 210;
|
|
|
|
p2_x = 620;
|
|
p2_y = 210;
|
|
|
|
}
|
|
|
|
|
|
void checkWin(){
|
|
|
|
int won=0;
|
|
if ( ball_x < p1_x){
|
|
won=1;
|
|
game++;
|
|
textout_ex( screen, font, "Player 2 Wins!", 320, 240, makecol( 255, 0, 0), makecol( 0, 0, 0));
|
|
propagateOKtoP1(-100);
|
|
startNew();
|
|
|
|
} else if ( ball_x > p2_x){
|
|
game++;
|
|
won=1;
|
|
textout_ex( screen, font, "Player 1 Wins!", 320, 240, makecol( 255, 0, 0), makecol( 0, 0, 0));
|
|
propagateOKtoP1(100);
|
|
startNew();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void setupGame(){
|
|
|
|
acquire_screen();
|
|
rectfill( buffer, p1_x, p1_y, p1_x + 10, p1_y + 60, makecol ( 0, 0, 255));
|
|
rectfill( buffer, p2_x, p2_y, p2_x + 10, p2_y + 60, makecol ( 0, 0, 255));
|
|
circlefill ( buffer, ball_x, ball_y, 5, makecol( 128, 255, 0));
|
|
draw_sprite( screen, buffer, 0, 0);
|
|
release_screen();
|
|
srand( time(NULL));
|
|
dir = rand() % 4 + 1;
|
|
|
|
}
|
|
|
|
|
|
int main(int argc, char**argv)
|
|
{
|
|
allegro_init();
|
|
install_keyboard();
|
|
set_color_depth(16);
|
|
set_gfx_mode( GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
|
|
|
|
l.setLearningCoeficient(0.01,0.01);
|
|
if(argc>=4 && argv[3][0]=='o')
|
|
{
|
|
std::cerr << "USING Optical Backpropagation\n";
|
|
l.opticalBackPropagation();
|
|
}
|
|
if(argc>=3)
|
|
{
|
|
std::cerr << "Setting learning coefficients to:" << atof(argv[1]) << "," << atof(argv[2]) << "\n";
|
|
l.setLearningCoeficient(atof(argv[1]),atof(argv[2]));
|
|
}
|
|
if(argc >=5)
|
|
{
|
|
std::cerr << "Setting learning games to:" << atof(argv[4]) << "\n";
|
|
learningGames=atof(argv[4]);
|
|
}
|
|
if(argc >=6 && argv[5][0]=='r')
|
|
{
|
|
std::cerr << "Setting random learning\n";
|
|
randomLearner=1;
|
|
}
|
|
buffer = create_bitmap( 640, 480);
|
|
setupGame();
|
|
speed=51;
|
|
int sleepTime=1000;
|
|
while(!key[KEY_ESC])
|
|
{
|
|
q++;
|
|
if(key[KEY_T])
|
|
{
|
|
std::cout << "ADDING next 500 learning games\n";
|
|
usleep(500000);
|
|
learningGames+=500;
|
|
}
|
|
if(game < learningGames)
|
|
{
|
|
if( key[KEY_UP] && speed < 200){
|
|
speed+=5;
|
|
}else if( key[KEY_DOWN] && speed >1 ){
|
|
speed-=5;
|
|
}
|
|
if(speed <= 0)
|
|
{
|
|
speed=1;
|
|
}
|
|
}else
|
|
{
|
|
speed=1;
|
|
}
|
|
|
|
register char p1dir=p1Move();
|
|
register char p2dir=p2Move();
|
|
|
|
p1_tempY = p1_y;
|
|
p2_tempY = p2_y;
|
|
|
|
if(p1dir < 0 && p1_y > 0){
|
|
--p1_y;
|
|
} else if( p1dir > 0 && p1_y < 420){
|
|
++p1_y;
|
|
}
|
|
if(p2dir > 0 && p2_y > 0){
|
|
--p2_y;
|
|
} else if( p2dir < 0 && p2_y < 420){
|
|
++p2_y;
|
|
}
|
|
moveBall();
|
|
if(key[KEY_PLUS_PAD] && sleepTime >=10)
|
|
sleepTime-=50;
|
|
else if(key[KEY_MINUS_PAD] && sleepTime <=15000)
|
|
sleepTime+=50;
|
|
|
|
if(i%speed==0)
|
|
{
|
|
acquire_screen();
|
|
rectfill( buffer, p1_tempX, p1_tempY, p1_tempX + 10, p1_tempY + 60, makecol ( 0, 0, 0));
|
|
rectfill( buffer, p1_x, p1_y, p1_x + 10, p1_y + 60, makecol ( 0, 0, 255));
|
|
|
|
rectfill( buffer, p2_tempX, p2_tempY, p2_tempX + 10, p2_tempY + 60, makecol ( 0, 0, 0));
|
|
rectfill( buffer, p2_x, p2_y, p2_x + 10, p2_y + 60, makecol ( 0, 0, 255));
|
|
|
|
circlefill ( buffer, ball_tempX, ball_tempY, 5, makecol( 0, 0, 0));
|
|
circlefill ( buffer, ball_x, ball_y, 5, makecol( 128, 255, 0));
|
|
draw_sprite( screen, buffer, 0, 0);
|
|
release_screen();
|
|
usleep(sleepTime);
|
|
}
|
|
checkWin();
|
|
i++;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
END_OF_MAIN()
|