Putting Coder for Raspberry Pi through its paces

Coding Coders

The development environment is divided into five parts. The four text-editing tabs, from left to right, are: HTML for your app's web page markup, CSS for the style sheets, JS for your app's front-end programming logic, and Node, which is where you can play with the Node.js-based web server and create server-side logic (e.g., connections to databases and so on).

The folder icon opens the Media panel (Figure 5). You can upload snippets, such as sounds, icons, and sprites, from here to use later in your app. Unfortunately, Coder does not offer a preview of any of the uploaded files, so you'll have to give them really descriptive names to avoid getting confused later on.

Figure 5: The Media panel allows you to upload assets (images, sounds, etc.) to use in your app.

The eye icon shows your app running alongside the code you are developing (Figure 6). The app is reloaded every time you change something in your code, so you can test your modifications immediately.

Figure 6: You can run your app alongside your code to see how it's going.

Finally, the gear icon lets you configure the name, author, and color scheme of your app. You can also delete and export your app from here – I'll talk more about that last feature later.

Mine Coder

Because Coder is meant to help you code, let's code! I already wrote a version of the Game of Life in JavaScript elsewhere [4], so I decided to go with another of my favorite time-wasters: Minesweeper! Yes, I am a man of simple tastes.

The Game of Life canvas I used for Life is very HTML5, so I decided not to do that again; instead, I chose to go low-tech and use straight bitmaps (Figure 7) within HTML and use jQuery to manipulate all the changes to the bits and pieces. I also went for a very minimalistic approach to keep things as clear as possible.

Figure 7: A set of 12 PNG images are all you need to set up a minesweeping board. From left to write and top to bottom: covered.png, 0_uncovered.png through 8_uncovered.png, explosion_uncovered.png, and mine_uncovered.png.

The first step in creating a new app is to click on the rectangle with the plus sign on the main screen. You will prompted to give your app a name and a color theme. Once you click Create, Coder sets up minimal skeletons for HTML, CSS, and JavaScript (you will not need Node.js for this project).

I designed the tiles in Inkscape, exported each one as a 20x20-pixel PNG image, and uploaded them to the project via the Media panel. In Figure 7 you can see all the tiles.From left to right and top to bottom, you can see covered.png, which represents a covered square in the minefield grid. Next, the files 0_uncovered.png through 8_uncovered.png represent uncovered squares and are used to show the number of neighboring mines in each square as the player uncovers them. Then, there's an explosion tile and, finally, a square with an uncovered mine, which is used when the whole minefield is shown at game's end.

The HTML file (Listing 1) is very barebones. The <head>...</head> section has not been modified in any way, but the lines

<link href="/static/apps/coderlib/css/index.css" media="screen" rel="stylesheet" type="text/css"/>

and

<script src="/static/apps/coderlib/js/index.js"></script>

are worth pointing out. These lines load in the CSS and JavaScript files that you are able to modify for your app from within Coder.

Listing 1

Mine Coder HTML

01 <!DOCTYPE html>
02 <html>
03 <head >
04     <title>Coder</title>
05     <meta charset="utf-8">
06     <!-- Standard Coder Includes -->
07     <script>
08         var appname = "{{app_name}}"; //app name (id) of this app
09         var appurl = "{{&app_url}}";
10         var staticurl = "{{&static_url}}"; //base path to your static files /static/apps/yourapp
11     </script>
12     <link href="/static/apps/coderlib/css/index.css" media="screen" rel="stylesheet" type="text/css"/>
13     <script src="/static/common/js/jquery.min.js"></script>
14     <script src="/static/common/ace-min/ace.js" type="text/JavaScript" charset="utf-8"></script>
15     <script src="/static/apps/coderlib/js/index.js"></script>
16     <script>
17         Coder.addBasicNav();
18     </script>
19     <!-- End Coder Includes -->
20
21     <!-- This app's includes -->
22     <link href="{{&static_url}}/css/index.css" media="screen" rel="stylesheet" type="text/css"/>
23     <script src="{{&static_url}}/js/index.js"></script>
24     <!-- End apps includes -->
25 </head>
26 <body class="">
27     <div class="pagecontent">
28         <div id="boardsection">
29             <div id="board">
30             </div>
31         </div>
32
33         <div id="splash">
34             <button id="start">Start</button>
35         </div>
36     </div>
37
38 </body>
39 </html>

The <body>...</body> section is split into two sections: <div id="board">...</div> will contain the board generated by the JavaScript, and <div id="splash">...</div> contains a button that starts a new game when clicked.

The CSS (Listing 2) contains the default layout for .pagecontent provided by Coder. I want to make sure the div #boardsection is hidden by default until I'm ready to show a board. To stack the tiles next to one another without any spaces between them, I use the float: left; attribute on the .cell class. (Quick explanatory detour: I haven't shown the HTML .cell yet because it is generated dynamically by the JavaScript, so I'll get to it a bit later. The same goes for rows … .)

Listing 2

Mine Coder CSS

01 .pagecontent {
02     padding: 24px;
03 }
04
05 #boardsection {
06     display: none;
07 }
08
09 .cell {
10    float: left;
11 }
12
13 .row {
14     clear: both;
15 }
16
17 #splash {
18     clear: both;
19 }

The exact opposite, however, goes for stacking rows: To stack each row of cells one on top of the other, I have to clear any float parameter, as well as the start button, which I will want to show below the grid when a game has finished.

Next up is the JavaScript (Listing 3), where most of the magic happens. Lines 1 to 15 are the main routine. For those unfamiliar with jQuery, using a $(document).ready(function() { ... }); function is a standard way of executing JavaScript code when – and only when  – the web page has completely loaded.

Listing 3

Mine Coder JavaScript

001 $(document).ready(function() {
002     var board_o = new board(10, 10, 15);
003
004     $("#start").click(function(){
005         $("#splash").hide();
006         $("#boardsection").show();
007
008         board_o.initiate();
009         $("#board").replaceWith(board_o.draw());
010
011         $(".cell").on("click", function(){
012             $(this).replaceWith(board_o.flip($(this).attr('id')));
013         });
014     });
015 });
016
017 var cell = function (x, y){
018     this.pos=[x, y];
019     this.state="covered";
020     this.mine=false;
021     this.neighbours=0;
022 };
023
024 var board = function (sizex, sizey, mines){
025     this.size=[sizex, sizey];
026     this.mines=mines;
027     this.cell_o=[];
028
029     this.initiate = function(){
030         for (i=0; i<this.size[0]; i++){
031             this.cell_o[i]=[];
032             for(j=0; j<this.size[1]; j++){
033                 this.cell_o[i][j]=new cell(i,j);
034             }
035         }
036         this.placeMines();
037         this.countNeighbours();
038         this.uncovered=0;
039     };
040
041     this.draw = function(){
042         var web_string="<div id='board'>";
043         for (j=0; j<this.size[1]; j++){
044             web_string = web_string + "<div class='row'>";
045             for (i=0; i<this.size[0]; i++){
046                 web_string = web_string + "<img class='cell' id='" + i + "_" + j + "' src='/static/apps/mine_coder/media/"+this.cell_o[i][j].state+".png'>";
047             }
048             web_string=web_string + "</div>";
049         }
050         return web_string + "</div>";
051     };
052
053     this.convertId = function(my_id){
054         return (my_id.split("_"));
055     };
056
057     this.flip = function(my_id){
058         var pos=my_id.split("_");
059         var x=parseInt(pos[0]); var y=parseInt(pos[1]);
060
061         if (this.cell_o[x][y].mine) {
062             this.cell_o[x][y].state="explosion_uncovered";
063             this.showBoard(x,y);
064         }
065
066         else {
067             this.cell_o[x][y].state=this.cell_o[x][y].neighbours + "_uncovered";
068             this.uncovered++;
069             if(this.uncovered==(this.size[0]*this.size[1])-this.mines){
070                   this.showBoard(this.size[0], this.size[1]);
071                   alert("You won!")
072             }
073         }
074         return ("<img class='cell' id='" + my_id + "'  src='/static/apps/mine_coder/media/      "+this.cell_o[x][y].state+".png'>");
075     };
076
077
078     this.showBoard = function(x,y){
079         for (i=0; i<this.size[0]; i++){
080             for (j=0; j<this.size[1]; j++){
081                 if(i!=x || j!=y){
082                     this.cell_o[i][j].state=this.cell_o[i][j].neighbours + "_uncovered";
083                     if (this.cell_o[i][j].mine){this.cell_o[i][j].state="mine_uncovered";}
084                 }
085             }
086         }
087         $("#board").replaceWith(this.draw());
088         $("#splash").show();
089     };
090
091     this.placeMines = function(){
092         for (i=0; i<this.mines; i++){
093             x=Math.ceil((Math.random()*this.size[0]-1));
094             y=Math.ceil((Math.random()*this.size[1]-1));
095             if (this.cell_o[x][y].mine===false) {this.cell_o[x][y].mine=true;}
096         }
097     };
098
099     // Count number of neighbouring mines
100     this.countNeighbours = function(){
101         for (i=0; i<this.size[0]; i++){
102           for (j=0; j<this.size[1]; j++){
103             if (this.cell_o[i][j].mine===false){
104               for(m=i-1; m<i+2; m++){
105                 for(n=j-1; n<j+2; n++){
106                   if (m>-1 && n>-1 && m<this.size[0] && n<this.size[1] && !(m==i && n==j)){
107                       if (this.cell_o[m][n].mine){this.cell_o[i][j].neighbours++;}
108                   }
109                 }
110               }
111             }
112           }
113         }
114     };
115 };

In this case, I create a board object, set its size (10x10 squares) and the number of mines it contains (15), then start running the game when the #start button is clicked. I hide the button, show the div that contains the board, create an instance, and initiate the board object. The board object (lines 24-115) is a bit of a sprawling mess, but, in my defense, I will say it contains a two-dimensional array of cell objects (lines 17-22), which is a rather complex thing to do in JavaScript.

First, to create a bi-dimensional array, you have to define a single-dimension array (line 27) and then loop through every element and jam a new array into each element of the original array (line 31). The effort is worth it, however, because you can then use the array of arrays to set up the playing field grid and jam a cell object into each item with its x, y coordinates. That's what the loops in lines 30 to 35 do, setting all squares as covered and empty (i.e., containing no mines).

Line 36 calls a method that randomly scatters mines throughout the playing field (lines 91-97). To save time later on during game play, the script then works out how many neighboring mines the empty squares have (lines 100-114) and stores that number in the cell's neighbours attribute. I also set the counter that keeps track of the uncovered square to 0 (line 38).

Back in the main routine, I use board's draw method and jQuery's replaceWith method to push the board to the app (line 9). The draw method (line 41) builds a long HTML string containing all the rows and the img elements (cells) by looking at the state attribute of each cell object in the grid.

At this stage in the game, draw returns a 10x10 grid of covered squares.

Back at the main routine, line 11 listens for a click event on each and every square (all belonging to the CSS .cell class I talked about earlier) and, when it comes along, it calls the flip method to decide what happens next (Figure 8). The flip method (lines 57-75) looks at the clicked square's state attribute and decides what to show. This step is quite easy to do, because each square is an HTML independent img element with its own generated id attribute (line 74) that includes its coordinates on the board. This allows me to change that image and only that image using, again, the jQuery replaceWith method (line 12). So clever.

Figure 8: Every time the player clicks on a square, the flip method is called and pushes the new "look" of the clicked cell to the web app.

There are two exceptions to the above process. When a player clicks on a square containing a mine, flip pushes an explosion_uncovered state to the cell, and then all the board is uncovered using the showboard method (lines 78-89). The game is then over (Figure  9).

Figure 9: Step on a mine, you die. Gaming doesn't get more exciting than this.

The second exception is when there are no more empty squares to uncover. The program keeps track of how many squares the player uncovers in line 68. When the player has uncovered all the empty squares (i.e., the total number of squares in the grid minus the number of mines), the player wins. Again, the complete board is shown, and the game ends (Figure 10).

Figure 10: Winner! Uncovering all the empty squares has this underwhelming effect.

The end result is not pretty, but it works, up to a point. If your board is wider than your browser window, it's going to look broken. Also, there is no autoclear function when you click on an empty square. I figured that I'd leave the pleasures of debugging recursive algorithms to the reader.

Buy this article as PDF

Express-Checkout as PDF

Pages: 7

Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Snapshot

    The remarkable Raspberry Pi has spawned a myriad of supporting projects – Android apps, program libraries, specialized Linux distributions, and an assortment of hardware accessories. The rapid changes within these projects is testament to the excitement and enthusiasm that developers around the world have given to the Raspberry Pi.

  • BlinkStick and Raspberry Pi

    Replace a simple LED with more powerful and flexible BlinkStick devices.

  • WiFi and the Raspberry Pi

    This SwitchDoc column looks at various uses for the inexpensive ESP8266 WiFi/processor combination.

  • Graphical displays with Python and Pygame

    As its name implies, Pygame is a set of Python modules designed to write games. However, many Pygame modules are useful for any number of projects. We introduce you to a few Pygame modules that you can use to create custom graphical displays for your project.

  • Build audio and proximity devices with the Touch Board and electric paint

    An Arduino-compatible board combines cool audio features, 12 touch sensors, and electric paint to make the most excellent (and enjoyable) educational board yet.