In: Electrical Engineering
This is a code for a bouncing ball on an 8X8 LED. How can i change the code to make it a ping pong game against AI by adding 1 potentionmeter to control it?
#include <TimerOne.h>//this is a library that uses timer 1 of the arduino to trigger interrupts in certain time intervals
//This defines a matrix defining a smiley face for the 8x8 LED
matrix display
#define BALL { \
{1, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0} \
}
/*Arduino pin --> Display pin----->8x8 matrix row and column
coordinates (1;1) origin
D2-------------->9---------------------->row 1
D3-------------->10-------------------->col 4
D4-------------->11-------------------->col 6
D5-------------->12--------------------->row 4
D6-------------->13-------------------->col 1
D7-------------->14--------------------->row 2
D8-------------->15-------------------->col 7
D9-------------->16-------------------->col 8
D10------------->4--------------------->col 3
D11------------->3--------------------->col 2
D12------------->2---------------------->row 7
D13------------->1---------------------->row 5
A0 (D14)-------->5---------------------->row 8
A1 (D15)-------->6--------------------->col 5
A2 (D16)-------->7---------------------->row 6
A3 (D17)-------->8---------------------->row 3
*/
//rows:
const int col[8] = {
2,7,17,5,13,16,12,14 };//these are the Arduino pins that connect to
the anodes (1-8) of the LEDs
//columns:
const int row[8] = {
6,11,10,3,15,4,8,9 };//these are the Arduino pins that connect to
the cathodes (1-8) of the LEDs
int x = 0;
int y = 0;
int dx = 1;
int dy = 1;
volatile byte c,r,flag,counter;//interrupt routine variables, they need to be specified as 'volatile'
// 2-dimensional array that contains the currently 'ON' LEDs in
the matrix ('1'='ON'); this is used in the refreshScreen() ISR
below:
byte pattern[8][8] = BALL;
unsigned long previousMillis = 0; //last time we switched
patterns [ms]
unsigned long interval = 1000; //time between switching [ms]
int currentPattern = 0; //0 for "Ball", 1 for "Ball2", 2 for
"Ball3", 3 for "Ball4"
void setup() {
// initialize the row and column pins as outputs
// iterate through the pins:
for (int pin = 0; pin < 8; pin++) {
// initialize the output pins:
pinMode(col[pin], OUTPUT);
digitalWrite(col[pin], HIGH);
pinMode(row[pin], OUTPUT);
digitalWrite(row[pin], LOW);
// take the col pins (i.e. the cathodes) high and the row pins
(anodes) low to ensure that
// the LEDS are off:
}
Timer1.initialize(100); // initialize timer1, and set a 100 us
second period for the interrupt interval (i.e. the ISR will be
called
//every 100 us - this seems to be a good frequency to achieve a
flicker-free LED display.
//experiment with this parameter. If it gets too small the ISR
starts 'eating up' all the processor time, and the main loop
becomes very slow
Timer1.attachInterrupt(refreshScreen); // attaches the
refreshScreen() function as 'Interrupt Service Routine' (ISR) to
the interrupt
//this means that every time 100 us have passed, the
refreshScreen() routine will be called.
}
//main loop...here we can simply busy ourselves with changing
the pattern[][] array; nothing deals with the LED display.
//this is all handled via the ISR
void loop() {
if (x>=7)
{ dx = -1;
dy = random(-1,1);
}
if(x<=0)
{
dx = 1;
dy = random(-1,1);
}
if (y>=7)
{dy = -1;
dx = random(-1,1);
}
if (y<=0)
{ dy = 1;
dx = random(-1,1);
}
pattern[x][y] = 0;
pattern[x+dx][y+dy]=1;
x=x+dx;
y=y+dy;
delay(50);
#include "LedControl.h"
#include "Timer.h"
#define POTPIN A5 // Potentiometer
#define PADSIZE 3
#define BALL_DELAY 200
#define GAME_DELAY 10
#define BOUNCE_VERTICAL 1
#define BOUNCE_HORIZONTAL -1
#define NEW_GAME_ANIMATION_SPEED 50
#define HIT_NONE 0
#define HIT_CENTER 1
#define HIT_LEFT 2
#define HIT_RIGHT 3
//#define DEBUG 1
byte sad[] = {
B00000000,
B01000100,
B00010000,
B00010000,
B00000000,
B00111000,
B01000100,
B00000000
};
byte smile[] = {
B00000000,
B01000100,
B00010000,
B00010000,
B00010000,
B01000100,
B00111000,
B00000000
};
Timer timer;
LedControl lc = LedControl(12,11,10,1);
byte direction; // Wind rose, 0 is north
int xball;
int yball;
int yball_prev;
byte xpad;
int ball_timer;
void setSprite(byte *sprite){
for(int r = 0; r < 8; r++){
lc.setRow(0, r, sprite[r]);
}
}
void newGame() {
lc.clearDisplay(0);
// initial position
xball = random(1, 7);
yball = 1;
direction = random(3, 6); // Go south
for(int r = 0; r < 8; r++){
for(int c = 0; c < 8; c++){
lc.setLed(0, r, c, HIGH);
delay(NEW_GAME_ANIMATION_SPEED);
}
}
setSprite(smile);
delay(1500);
lc.clearDisplay(0);
}
void setPad() {
xpad = map(analogRead(POTPIN), 0, 1020, 8 - PADSIZE, 0);
}
void debug(const char* desc){
#ifdef DEBUG
Serial.print(desc);
Serial.print(" XY: ");
Serial.print(xball);
Serial.print(", ");
Serial.print(yball);
Serial.print(" XPAD: ");
Serial.print(xpad);
Serial.print(" DIR: ");
Serial.println(direction);
#endif
}
int checkBounce() {
if(!xball || !yball || xball == 7 || yball == 6){
int bounce = (yball == 0 || yball == 6) ? BOUNCE_HORIZONTAL : BOUNCE_VERTICAL;
#ifdef DEBUG
debug(bounce == BOUNCE_HORIZONTAL ? "HORIZONTAL" : "VERTICAL");
#endif
return bounce;
}
return 0;
}
int getHit() {
if(yball != 6 || xball < xpad || xball > xpad + PADSIZE){
return HIT_NONE;
}
if(xball == xpad + PADSIZE / 2){
return HIT_CENTER;
}
return xball < xpad + PADSIZE / 2 ? HIT_LEFT : HIT_RIGHT;
}
bool checkLoose() {
return yball == 6 && getHit() == HIT_NONE;
}
void moveBall() {
debug("MOVE");
int bounce = checkBounce();
if(bounce) {
switch(direction){
case 0:
direction = 4;
break;
case 1:
direction = (bounce == BOUNCE_VERTICAL) ? 7 : 3;
break;
case 2:
direction = 6;
break;
case 6:
direction = 2;
break;
case 7:
direction = (bounce == BOUNCE_VERTICAL) ? 1 : 5;
break;
case 5:
direction = (bounce == BOUNCE_VERTICAL) ? 3 : 7;
break;
case 3:
direction = (bounce == BOUNCE_VERTICAL) ? 5 : 1;
break;
case 4:
direction = 0;
break;
}
debug("->");
}
// Check hit: modify direction is left or right
switch(getHit()){
case HIT_LEFT:
if(direction == 0){
direction = 7;
} else if (direction == 1){
direction = 0;
}
break;
case HIT_RIGHT:
if(direction == 0){
direction = 1;
} else if(direction == 7){
direction = 0;
}
break;
}
// Check orthogonal directions and borders ...
if((direction == 0 && xball == 0) || (direction == 4 && xball == 7)){
direction++;
}
if(direction == 0 && xball == 7){
direction = 7;
}
if(direction == 4 && xball == 0){
direction = 3;
}
if(direction == 2 && yball == 0){
direction = 3;
}
if(direction == 2 && yball == 6){
direction = 1;
}
if(direction == 6 && yball == 0){
direction = 5;
}
if(direction == 6 && yball == 6){
direction = 7;
}
// "Corner" case
if(xball == 0 && yball == 0){
direction = 3;
}
if(xball == 0 && yball == 6){
direction = 1;
}
if(xball == 7 && yball == 6){
direction = 7;
}
if(xball == 7 && yball == 0){
direction = 5;
}
yball_prev = yball;
if(2 < direction && direction < 6) {
yball++;
} else if(direction != 6 && direction != 2) {
yball--;
}
if(0 < direction && direction < 4) {
xball++;
} else if(direction != 0 && direction != 4) {
xball--;
}
xball = max(0, min(7, xball));
yball = max(0, min(6, yball));
debug("AFTER MOVE");
}
void gameOver() {
setSprite(sad);
delay(1500);
lc.clearDisplay(0);
}
void drawGame() {
if(yball_prev != yball){
lc.setRow(0, yball_prev, 0);
}
lc.setRow(0, yball, byte(1 << (xball)));
byte padmap = byte(0xFF >> (8 - PADSIZE) << xpad) ;
#ifdef DEBUG
//Serial.println(padmap, BIN);
#endif
lc.setRow(0, 7, padmap);
}
void setup() {
// The MAX72XX is in power-saving mode on startup,
// we have to do a wakeup call
pinMode(POTPIN, INPUT);
lc.shutdown(0,false);
// Set the brightness to a medium values
lc.setIntensity(0, 8);
// and clear the display
lc.clearDisplay(0);
randomSeed(analogRead(0));
#ifdef DEBUG
Serial.begin(9600);
Serial.println("Pong");
#endif
newGame();
ball_timer = timer.every(BALL_DELAY, moveBall);
}
void loop() {
timer.update();
// Move pad
setPad();
#ifdef DEBUG
Serial.println(xpad);
#endif
// Update screen
drawGame();
if(checkLoose()) {
debug("LOOSE");
gameOver();
newGame();
}
delay(GAME_DELAY);
}