Arduino Asteroids Game: Randomly!

game3

I wanted to post a video, but sadly the free version of WordPress doesn’t allow this. So, you can click here to watch the video of me playing “Asteroids Game!” on my Uno with the LCD Keypad Shield. Sorry for the low quality of the video, but I’m sure you’ll enjoy it all the same.

The game is complete, and you are welcome to head over to my GitLab and download the ino file and compile it yourself. Remember, you will need the LCD Keypad Shield library as well. Some stats about the game and program:

Sketch uses 7510 bytes (23%) of program storage space. Maximum is 32256 bytes.
Global variables use 473 bytes (23%) of dynamic memory, leaving 1575 bytes for local variables. Maximum is 2048 bytes.

Also, the entire game is programmed in less than 600 lines (would be significantly less without all the explanation blocks I put in there), and the ino file is less than 20 kb!

One of the biggest parts of the game is making sure that the asteroids show up in a random fashion. With only 4 asteroids, it is important that the pattern is not discernible by the player, or they will easily be able to win over and over again. Here is how I called it:

gameAsteroidOne = get_random(4);

I am calling the “get_random” function with an integer (in this case) of 4. That will make more sense once I show you the function:

int get_random (int addOn) {
srand(millis()+addOn); // Use time since turned on and add on number as seed for random number.
int r = rand() % 10; // Returns a random integer between 0 and 10.
r += 10; // Add 10 to keep it off of the display screen.
return r;
}

You see, computers can’t actually make random numbers, so you have to “seed” it with something to grow a number from. As a “seed” I input the time in milliseconds that the game has been running. From this it makes a “random” number from 1 to 10. It then adds 10 to that number to place the asteroid off of the screen, giving the appearance that it existed before and slowly came into view.

The problem is that sometimes the game loop runs fast enough where two asteroids are asking for a new random number at the exact same time. If they do, they will both receive the exact same “random” number. This will cause them to “overlap” or be in the same physical spot, which means that they will both go off screen at the same time, and request a new random number at the same time, receiving the same “random” number again. It’s a loop.

To solve this, I added the integer “addOn” to the milliseconds to make a new number. This “addOn” number is passed with each asteroid, and each one has a different number, creating a new instance of “seed” for the random number generator. That way no two should return the exact same “random” number. Although it can still happen.

Just like rolling two dice can sometimes give you the same number, the random function can still randomly return the same number. The smaller the number pool, a six sided dice would have a pool of 6, our game has a pool of 10, the more likely a repeat of a random number happens.

Another case scenario is when asteroid one, for say, goes off screen, while asteroid two is 2 steps behind. Asteroid one gets a random number of, let’s say 6, which added to 10 makes 16. Now the asteroids move. One is 15, two is 1. Then one is 14, and two is 0. Then one is 13, and two falls off screen, getting a new number, which randomly could be 3, which, when added to 10, makes 13, and the two asteroids now occupy the same space.

A programmer could add a check for this, and if the asteroids are in the same space, cause a new random number to be chosen, or add or subtract a number to it, but in this simple game, it happens so rarely that it isn’t really a problem. The player just gets a bonus when those two asteroids pass next time.

Either way, I hope that you have enjoyed the game itself, and more so the creation of it. The game is open source and feel free to put it to good use!

Linux – keep it simple.

Arduino Asteroids Game: Play mode and pause state!

Today was the big push! It took a while to figure out how to implement what I wanted to do, but now it’s done! The game play mode and pause state are completed! You can, of course, check out the full commits on my GitLab, but I plan to go over some of the most important parts here.

if (gameState == 3) { // Play state.
// The player has entered play mode.

gameTime++;
if (gameTime > 1){
gameTime = 0;
gamePaused = false;
}

This portion allows the game to pause. An odd occurrence is that you cannot press the pause button and release it fast enough. It will essentially get pressed and check that it is pressed about 1000 times per second, so I needed to add an “unpause” delay, and this is how I did it. If the buttons were software buttons, I could have done this differently, but they are physical buttons, so I needed this to make it work every time.

gameShoot = true; // you have not shot yet this round.
gameAsteroidOne–; // First asteroid starting space.
gameAsteroidTwo–; // Second asteroid starting space.
gameAsteroidThree–; // Third asteroid starting space.
gameAsteroidFour–; // Fourth Asteroid starting space.

Here, we increment (or move) each asteroid by one space.

if (gameAsteroidOne == -1) {
if (gamePosition == 0) {
// Game over, you lose.
gameState = 6;
gameLineNum = 0;
} else {
gameScore++; // get a point!
gameSpeed = set_gameSpeed(gameScore);
gameAsteroidOne = get_random(4);
}
} // end gameAsteroidOne.

In this block, I am figuring out everything for asteroid number one. So, if it’s position (which we moved just the block before this) is now -1, then it is at the position on the screen where the player’s ship is. It now checks if it is on the same row as the ship (gamePosition is the position of the ship, 0 for upper, 1 for lower). If they both are on the same row, then a collision has occurred. So, you switch to the lose screen.

If they are not on the same row, then the player gets a point for passing the asteroid. Then the game speed is increased (there are some other factors that change it as well), and the asteroid is moved to a random new location.

if (gameAsteroidTwo == -1) {
if (gamePosition == 0) {
// Game over, you lose.
gameState = 6;
gameLineNum = 0;
} else {
gameScore++; // get a point!
gameSpeed = set_gameSpeed(gameScore);
gameAsteroidTwo = get_random(2);
}
} // end gameAsteroidTwo.

if (gameAsteroidThree == -1) {
if (gamePosition == 1) {
// Game over, you lose.
gameState = 6;
gameLineNum = 0;
} else {
gameScore++; // get a point!
gameSpeed = set_gameSpeed(gameScore);
gameAsteroidThree = get_random(3);
}
} // end gameAsteroidThree.

if (gameAsteroidFour == -1) {
if (gamePosition == 1) {
// Game over, you lose.
gameState = 6;
gameLineNum = 0;
} else {
gameScore++; // get a point!
gameSpeed = set_gameSpeed(gameScore);
gameAsteroidFour = get_random(1);
}
} // end gameAsteroidFour.

if (gameScore > 99){
// You win! Great job!
gameState = 5;
gameLineNum = 0;
}

These are the portions for asteroids two through four, which work identically to asteroid one. Note that there are two asteroids on row 0, and two asteroids on row 1. Four asteroids total. It seems rather limited, but it is appropriate for such a small screen.

// Set up our display.
// The space ship
String shipUpper = ” “;
String shipLower = ” “;
if (gamePosition == 0){
shipUpper = “>”;
shipLower = ” “;
} else {
shipUpper = ” “;
shipLower = “>”;
}

Here we check the location of the player’s space ship and set the upper and lower icons appropriate for the display.

// Upper blocks.
lcd.setCursor(0,0);
lcd.print(“00”);
lcd.setCursor(2,0);
lcd.print(gameBullets);
lcd.setCursor(3,0);
lcd.print(“|”);
lcd.setCursor(4,0);
lcd.print(shipUpper);

for (int a = 5; a < 17; a++){
lcd.setCursor(a,0);
if (a == gameAsteroidOne+5){
lcd.print(“*”);
} else if (a == gameAsteroidTwo+5){
lcd.print(“*”);
} else {
lcd.print(” “);
}
}

Now we draw the upper blocks. As you can see, I just set the LCD cursor to the correct spot and print the text to display what I want displayed. The “for” loop cycles through the remaining display area, or “asteroid field” and checks for asteroids. If there is one, it displays an asterisk, if not, then a blank space.

// Lower blocks.
lcd.setCursor(0,1);
lcd.print(gameScore);
if (gameScore < 10) {
lcd.setCursor(1,1);
lcd.print(” “);
} else if (gameScore < 100) {
lcd.setCursor(2,1);
lcd.print(” “);
}

lcd.setCursor(3,1);
lcd.print(“|”);
lcd.setCursor(4,1);
lcd.print(shipLower);

for (int a = 5; a < 17; a++){
lcd.setCursor(a,1);
if (a == gameAsteroidThree+5){
lcd.print(“*”);
} else if (a == gameAsteroidFour+5){
lcd.print(“*”);
} else {
lcd.print(” “);
}
}

Here we draw the lower line of the screen. It works basically the same as the upper line, but with the score instead of the number of bullets.

gameDelay = 0;
while (gameDelay < 1000){
// Add a delay in the loop.
delay(1);
gameDelay+=gameSpeed;
lcd_key = read_LCD_buttons(); // read the buttons

switch (lcd_key){

case btnRIGHT:{
// Shoot command
if (gameBullets > 0 && gameShoot) {
if (gamePosition == 0){
lcd.setCursor(5,0);
lcd.print(“————“);
gameBullets–;
gameShoot = false; // You already shot.
gameAsteroidOne = get_random(4);
gameAsteroidTwo = get_random(2);
} else {
lcd.setCursor(5,1);
lcd.print(“————“);
gameBullets–;
gameShoot = false; // You already shot.
gameAsteroidThree = get_random(3);
gameAsteroidFour = get_random(1);
}
}
break;
}
case btnLEFT:{
if (!gamePaused) {
gameState = 4;
gameLineNum = 0;
gamePaused = true;
}
break;
}
case btnUP:{
gamePosition = 0;
break;
}
case btnDOWN:{
gamePosition = 1;
break;
}
case btnSELECT:{
gameState = 0;
gameLineNum = 0;
break;
}
}
}
} // End gameState 3, play state.

The remainder is the delayed “while” loop, which checks the status of the buttons every millisecond and increments towards ending this “round” of display. Because it is using a counter that is based on game speed, the game will speed up as the game increases. At first, an entire game loop takes about 1 second, then .5 seconds, then .33 seconds, and finally, .25 seconds towards the end of the game.

The pause mode is much simpler:

if (gameState == 4) { // Pause state.
// The player paused the game.
lcd_key = read_LCD_buttons(); // read the buttons

switch (lcd_key){

case btnLEFT:{
gameState = 3;
gameLineNum = 0;
break;
}
case btnSELECT:{
gameState = 0;
gameLineNum = 0;
break;
}
}
} // End gameState 4, pause state.

The pause mode doesn’t actually draw anything, which is good, because then the screen displays what it was displaying last. Hence the game still visually appears, but no calculations are made to move anything.

Next post I’ll discuss the random number generator and some background information, as well as try to post a video of the game being played. If you have an LCD Keypad Shield and Arduino Uno, feel free to download my GitLab repository and play the game! You will need the LCD Keypad Shield library as well. Be sure to let me know if you tried it out!

Linux – keep it simple.

Arduino Asteroids Game: Win some, Lose some!

It isn’t really a game if you can’t win or lose. You need some driving force to make the game worth playing. With that, I also needed a way to inform the user that they either won or lost the game. Hence enter these win and lose game states. Almost identical to the credits or information screens, these win/lose screens just display that the winner won or the loser lost.

Feel free to check out the latest commit on this, but there isn’t much to see that is different from the info/credits commits.

Linux – keep it simple.

Arduino Asteroids Game: Info and Credit Screens!

While not very exciting from the gamer standpoint, the information and credits screens are really important for several reasons. The main one being that it tells you how to play the game. It also lets you know how to contact the developer and who made the game. In the event you want to find more great material to play with!

Essentially, I have set up a scrolling screen that scrolls information over and over again. Pretty boring. However, I found a useful gem that I’d like to share with you here.

You see, as the information scrolls by, you might decide to click a button to do something, e.g., go back to the main menu, start the game, or what not. Well, the original method I was using was:

  • Loop through displayed data.
  • Check if they clicked a button.
  • Add 1.5 second delay.

This is a problem because you may have to hold the button for 1.5 seconds before it is picked up by the program. So, how do we include a delay, but constantly check for button presses? Well, with a “while” loop of course! Check it out:

gameDelay = 0;
      while (gameDelay < 2000){
       // Add a delay in the loop.
       delay(1);
       gameDelay++;
     lcd_key = read_LCD_buttons();   // read the buttons
  
       switch (lcd_key){ // depending on which button was pushed, we perform an action
    
           case btnSELECT:{
                 gameState = 0;
                 gameLineNum = 0;
                 break;
           }
       }
       }

So, instead of 2 seconds of delay all at once, I have a while loop that delays 1 ms, checks for button pushes, and then repeats for 2000 times, or roughly 2 seconds. This allows the player to press the button at any time, and only delays by 1 ms before reading it. Not only is this more functional, but it looks cooler in code too!

You can check out the full commit for the credits screen and info screens on my GitLab if you want more information.

Linux – keep it simple.

Arduino Asteroids Game: Start Screen!

Alright! Now that we’ve defined our game, finished the storyboard, and decided what it is we want to do with our game, it’s time to get started. Of course, the start screen is probably the best place to do that! So, I’ve completed game state 0, the start screen.

Not a lot you can do here, but it does flash every second between “Select = Start” and “Right = Info”. If you push one of those buttons, the game state changes to the appropriate number. I had to use this flashing option because the display is actually only 16×2, and I originally thought it was 18×2. Essentially the screen was too short for the information I wanted to present. However, the flashing options is nice because it shows that the display is active.

Makes me want to play it!

You can check out the latest commit on my GitLab, and here is game state 0:

if (gameState == 0) { // start screen state.
// The initial start screen. Let’s set all game variables for a new game.
// Game variables:
gameState = 0; // The state of game play.
gameBullets = 9; // Number of bullets remaining.
gameSpeed = 1; // The speed of the game.
gameScore = 0; // Number of asteroids destroyed or past.
gamePosition = 0; // Your space ships location, 0 for up, 1 for down.
gameAsteroidOne = 14; // First asteroid starting space.
gameAsteroidTwo = 25; // Second asteroid starting space.
gameAsteroidThree = 17; // Third asteroid starting space.
gameAsteroidFour = 23; // Fourth Asteroid starting space.

lcd.setCursor(0,1); // move to the begining of the second line
if (gameLineNum != 0){
lcd.print(” Right = Info “);
gameLineNum = 0;
} else {
lcd.print(” Select = Start “);
gameLineNum = 1;
}

lcd_key = read_LCD_buttons(); // read the buttons

switch (lcd_key){// depending on which button was pushed, we perform an action

case btnRIGHT:{
gameState = 1;
break;
}
case btnSELECT:{
gameState = 3;
break;
}
}
// Add a delay in the loop.
delay(1000);
} // End gameState 0, asteroids start screen.

As you can see, the most important thing game state 0 does is set all the variables back to the default.

Linux – keep it simple.

Arduino Asteroids Game!

The humble beginnings of a simple asteroid avoidance game.

Okay, so I said that I would try making a little game with this LCD keypad, and I really meant it! I give you: “Asteroids Game!”

Well, at least the start of it. As you can see from the pictures, I’ve only really done two things: Storyboard and named the game. Making a storyboard is a very important part of creating a good game. As you can see in my hand written notes, that this entire game’s storyboard can be contained on one page (only because it is so simple).

The key part of storyboard work is showing how the screens will interface with each other, as you move from one game state to another. Consider our simple asteroid avoidance game, we will need 7 game states or screens:

/*
* Game states:
* 0 = Asteroid start screen
* 1 = Credits
* 2 = How to info
* 3 = Play mode
* 4 = Pause mode
* 5 = win screen
* 6 = lose screen
*/

The storyboard also sets the game dynamics, goals, and back story. Essentially, you pilot a fighter space craft and must drive through some sort of asteroid field. You must get past 100 asteroids to get to the other side. You will apparently have a limited amount of ammo with which you may destroy asteroids, the rest you have to move to avoid. Also, it will get faster and faster as you go through the field of asteroids.

Sounds pretty epic on an 18×2 screen!

The general controls are also defined in this storyboard: during menus or information, you can scroll and also start the game or go back to other menus or information. During the game play, you can move your ship up or down, shoot, pause, and quit to the main menu. Also I submitted the layout for the game play:

     ***        *          *         *************

– Bullets  END  Space  Field of asteroids coming at you……….

– Score    END   ship    Field of asteroids coming at you……….

It’s  a little hard to show on this diagram, but the storyboard picture makes it more clear. The first row will comprise of three digits for available bullets, the “end” of the play field, the upper space where your ship can be, and then 13 spaces for asteroids to hurl towards you.

The second row will be three digits to keep track of your score (the asteroids past or destroyed), the “end” of the play field, the lower space where your ship can be, and then 13 spaces for asteroids to hurl towards you.

I hope you enjoy this little adventure into gaming and Arduino programming. I’m looking forward to it myself. You can check out my work on my Gitlab as we go along, and this work falls under an open source license, so feel free to learn from it and make even better games/use out of it!

Linux – keep it simple.

Finished, picoEngine?

picoEngineComplet

Today I released version 1.0 of picoEngine.

That’s right! My UCI compatible chess engine is now released as picoEngine version 1.0! You can view the tag on my GitLab. Now you too can download and compile picoEngine for yourself! It comes with a generic 64 bit version that I tested on Ubuntu 18.04 with both Arena and PyChess interfaces. Here’s the information on this release:

Version 1.0

Features:

  • UCI compatible engine!
  • Accepts both FEN and MovePos standard inputs.
  • Up to 8 ply weighted moves.
  • Has an optional random move mode for easy chess players.
  • Fast, even at 8 ply only takes a second on a modern 64 bit machine.
  • Light weight, it only takes 2 MB of ram to run this engine.
  • Small size, the (Linux 64 bit) compiled engine is only 364.2 KB in size.
  • Small source code, the entire source repository is less than 1.3 MB in size.
  • Can output moves and engine evaluation (only displayed by interfaces that support it).

I hope you enjoy it! If the prebuilt doesn’t work, just review the read me for simple compiling instructions, involving just one command. (I like to keep things simple.)

Linux – keep it simple.

picoEngine: Fixing FEN + Moves!

fenplusmoves

Today I was able to finally put the nail in the coffin of the FEN + Moves bug in picoEngine! It felt great to close that long standing issue. You can even check out the commit for all the details, but as usual, I’ll talk about the pertinent part here.

The reason this is important is because many chess programs allow you to set up a position on the board, and then seek the engine’s advice on a next best move. Initially, while meeting the UCI (Universal Chess Interface) standard, I enabled picoEngine to accept either “movepos” ( a move by move insertion from the program to my chess engine ), or “FEN” ( a string of numbers and letters that represents the current board ). What I didn’t realize is that some chess programs did not do what I expected per the UCI guidelines.

The way I understood it by reading the UCI guidelines, was that the controlling chess program (say Arena, in our case) would choose before hand to either send “movepos” with a list of moves to get the board set up, or it would send “FEN” with a string of the board setup for each move. I understood that if you set up the board in an unusual position, it would need to send FEN commands to my engine. That made sense.

What I thought would happen for further moves, however, did not. I thought, since it started as a FEN command game, then every turn, it would send the FEN string of the new board. Some chess programs do this. In the case of many programs, such as Arena, it did something quite unexpected to me. For further moves, it would send the FEN to set the board, then a string of the moves after that setup. So it was doing both movepos and FEN all at the same time!

Knowing that now was an easy fix. Simply read the FEN to get the current position, and if you have follow on moves, then apply the movepos rules on them. What gave me the biggest hiccup, however, was a slight miscalculation on my part. I was feeding the FEN into the engine in such a way that the board came out mirrored! Here was the code I used to fix it:

From this:

	int j = stringBoard.length();	
        for (int i = 0; i < j; i++) {
	if (i < 64){ m_theBoard[63 - i] = stringBoard.at(i); }
	}

To this:

 

        for (int i = 0; i < 8; i++) {
		m_theBoard[i+0] = stringBoard.at(i+56);
		m_theBoard[i+8] = stringBoard.at(i+48);
		m_theBoard[i+16] = stringBoard.at(i+40);
		m_theBoard[i+24] = stringBoard.at(i+32);
		m_theBoard[i+32] = stringBoard.at(i+24);
		m_theBoard[i+40] = stringBoard.at(i+16);
		m_theBoard[i+48] = stringBoard.at(i+8);
		m_theBoard[i+56] = stringBoard.at(i+0);
	}

The picoEngine is really coming along nicely! I think it is playable now, and I’m just about done working on it. It’s still not very bright yet, but it is getting better!

Linux – keep it simple.

Choice by chance, picoEngine?

choiceply2

Today I added another set of options to picoEngine. Since it can now think through up to 8 ply, I needed to give it an option to choose how many ply you want it to think through. The commit is simple enough, which you can check out, but here is the gist of it:

	cout << "option name Ply type combo default 8 var 1 var 2 var 3 var 4 var 5 var 6 var 7 var 8" << endl;
	// End of Options
	cout << "uciok" << endl;
}
                styleRandom = false;
                cout << "Normal Mode." << endl;
            }
    if (std::string::npos != setString.find("1"))
            {
                chosenPly = 1;
                cout << "Ply 1." << endl;
            }

With further blocks for 1 through 8. I could have used case, but this worked well enough. Now just to make it smarter….

Linux – keep it simple.

Think deep, picoEngine!

8Ply

Okay, so I’ve been going on and on about making picoEngine think through multiple ply, and it really has been a challenge. I think this latest commit finally fixed it with the ability to think through up to 8 ply. That might seem like a lot, but the grandmaster level chess player is thinking through 16 ply.

A ply, for those who are wondering, is a move, so 8 ply is 4 complete turns of 8 moves. I’m certainly no grandmaster, but I’ve been beating this thing at 8 ply like it’s nobody’s business, so, despite thinking deep, it is not thinking well.

Either way, be sure to check out the commit, as I completely rewrote the ply thought process today. Here is some highlights with notes:

string makeMoves (string proposedMove, string boardPositions){
	string boardReturned = boardPositions;
	try{
		int first =((proposedMove.at(0) - 'a' + 1) + (((proposedMove.at(1) - '1') * 8) - 1));
		int second =((proposedMove.at(2) - 'a' + 1) + (((proposedMove.at(3) - '1') * 8) - 1));
		boardPositions[second] = boardPositions[first];
		boardPositions[first] = '-';
		boardReturned = boardPositions;
	} catch (...) {
	cout << " Exception " << endl;
	} // End try/catch block
	return boardReturned;
}

The above code allows the engine to use the board and make a move with it.

playBoard = makeMoves(proposedMove, originalBoard);
				currentEval = evaluations.getEval(playBoard);
				cout << " current eval and ply " << currentEval << " " << plyMoves << endl;
				if (whoseTurn) {
					if (currentEval > 9000) {cout << " ply  ends 10000." << endl;
					chosenMove = proposedMove;
					return chosenMove;
					}} else {
						if (currentEval < -9000) {cout << " ply  ends -10000." << endl;
					chosenMove = proposedMove;
					return chosenMove;
					}} 
				if (plyMoves-1 < 1){ 
						cout << " ply  ends 1." << endl;
					if (whoseTurn){
						// White's turn, higher is better.
						if ( currentEval > bestEval ) {
							chosenMove = proposedMove; 
							bestEval = currentEval;
							cout <<"info depth " << plyMoves << " score cp "<< currentEval << " pv " << chosenMove  << endl; //<< " comment " << boardPositions 
							} else if ( currentEval == bestEval && (int)time(0)%2 == 0) {
							chosenMove = proposedMove; 
							bestEval = currentEval;
							cout <<"info depth " << plyMoves << " score cp "<< currentEval << " pv " << chosenMove  << endl; //<< " comment " << boardPositions 
						}
						}

Here we see the general concept. We look at each available move, we determine the evaluation of that board after the move, we check if that is better or worse than what we had previously. With the weighted system, the “best” move wins.

The shortcomings I’ve seen while playing against picoEngine is probably related to poor evaluation criteria. It can only gauge the moves based on two things right now: movement and material. Hopefully I can get it smarter.

I did test it out, and it will checkmate itself if you have it play against itself in Arena. So that is good, it knows *how* to win, even if it is not very good at it.

Linux – keep it simple.