{{{{ JavaScript - Arrays }}}}

Single Array
Example - Sort
Two Dimensional Array
Example - Draughts
Start of website

Alphabetical index

Summary of colours in code: green is HTML useful for JavaScript, red is JavaScript, blue is a name and everything else is grey.



Single Array

We have been using variables for some time. You can produce quite complex code with simple variables. However, sometimes we need even more flexibility. Often we have a group of variables where we may want to treat them all the same, yet access them individually. This is done with arrays. (Some programming languages call these tables, but HTML has its own TABLEs, which are completely different, so we use the word "arrays" instead.) Unlike simple variables, we must define an array before we use it. In the example below, I define

var rand = new Array(maxr)

I've already defined "maxr" to be 10. This means that I have defined ten variables. The first one will be called rand [1], the next rand [2], and so on up to rand [10]. Note the square brackets! I could refer to them like this (in fact, I do refer to rand [1] further down the code), but usually we access the elements of an array one at a time via a loop, and use the loop counter to say which element we want. This is called the subscript. In "setrandom", I loop through all ten elements, setting each one equal to a random number. Since "i" is the loop counter, I can use "rand [i]" to mean the i'th element of "rand". (By the way, when I output the random numbers to the webpage using dynamic HTML, I've added a space between each one to stop them running into each other).

One button sets up the array. The other looks at each element of the array and finds the lowest. It does this by first assuming the first element is the lowest. Then it checks the second against this, and if that's lower, chooses that instead. Then it checks against the next, and so on. (Since there is only a single statement in the if statement, I've put it all on one line. I think it looks neater that way, but you may disagree!)

I've defined "rand" using the variable "maxr", which I set to be 10 beforehand. You can say

var rand = new Array(10)

However, for some reason, when you make an array, later you often find that you need to make it bigger. This means that you not only have to change the definition, you also have to go right through the code and change every reference to how big the array is, in all the for loops, for example. This is a right bore, and you're bound to miss one, which leads to the type of bug which is difficult to track down! If you use a variable in the definition, like I have, then you can make the table bigger or smaller just by changing that one variable. Much better style!




<HTML>
<HEAD>
<SCRIPT TYPE="TEXT/JAVASCRIPT">

// Global variables

var maxr = 10
var rand = new Array(maxr)

// set up array

function setrandom() {
var str = ""
  for (i = 1; i <= maxr; i++) {
    rand [i] = rnd(100)
    str = str + rand [i] + " "
   }
  document.getElementById('innum').innerHTML = str
  document.getElementById('outnum').innerHTML = ""
}

// Random number generator

function rnd(max) {
  var rndnum = max * Math.random()
  rndnum = Math.ceil (rndnum)
  return rndnum
}

// find least number

function findleast() {
  var least = rand [1]
  for (i = 1; i <= maxr; i++) {
    if (least > rand [i]) {least = rand [i]}
  }
  document.getElementById('outnum').innerHTML = least
}
</SCRIPT>

</HEAD>
<BODY>
<BR>
<INPUT TYPE=BUTTON VALUE="Generate numbers" ONCLICK="setrandom()">
<INPUT TYPE=BUTTON VALUE="Find least" ONCLICK="findleast()">
<BR><SPAN ID="innum"></SPAN>
<BR><SPAN ID="outnum"></SPAN>
</BODY>
</HTML>




Example - Sort

The code below is more complex, but uses similar ideas. It is an "insertion" sort, which sorts numbers into order. The insertion sort is not the most efficient sort for extremely large sets of numbers, but for a few numbers it is extremely good being reasonably efficient and easy to code.

First I generate some random numbers in an array again. The sort starts by looking at the first two numbers, and puts them in order if necessary. Then it takes the third number, and compares it to the previous until it finds its right place, shuffling numbers along as it does so. It continues for the rest of the numbers. It is efficient, as it doesn't compare every number to every other number At any one time, all the numbers to the left are in the right order within themselves, so it merely has to swap with the numbers that are greater than it.

You may notice j-- at one point in the code. Since i++ adds 1 to "i", I hope you'll agree that it's logical that j-- subtracts 1 from "j".


<HTML>
<HEAD>
<SCRIPT TYPE="TEXT/JAVASCRIPT">

// Global variables

var max = 12
var num = new Array(max)

// set up array

function setnum() {
  for (i = 1; i <= max; i++) {
    num [i] = rndm(100)
    document.write (num [i] + " ")
   }
}

// Random number generator

function rndm(max) {
  var rndnum = max * Math.random()
  rndnum = Math.ceil (rndnum)
  return rndnum
}

// sort array

function sortarray() {
  var swap = 0
  for (i = 2; i <= max; i++) {
    j = i
    while (j > 1 && num [j] < num [j - 1]) {
      swap = num [j]
      num [j] = num [j - 1]
      num [j - 1] = swap
      j--
    }
  }
  var str = ""
  for (i = 1; i <= max; i++) {
    str = str + num [i] + " "
  }
  document.getElementById('sorted').innerHTML = str
}
</SCRIPT>

</HEAD>
<BODY>
<SCRIPT TYPE="TEXT/JAVASCRIPT">
setnum()
</SCRIPT>

<INPUT TYPE=BUTTON VALUE="Sort" ONCLICK="sortarray()">
<BR><SPAN ID="sorted"></SPAN>
</BODY>
</HTML>




Two Dimensional Array

It is possible to have a two dimensional table. That means, instead of a single row of variables, accessed by one subscript, you can have both rows and columns, which need two subscripts. Most programming languages can define a two dimensional array directly, but JavaScript needs to do it in rather an oblique way - see the example below. First I define a one dimensional array (a normal one) in the usual way. Then I code a loop, making each element of that array into an array itself. So we end up with an array of arrays, if you can understand that. Arrays start with the first element as "graph [0]". Often people ignore this (as I did in the example above), since it seems more natural to start from 1. However, since computers start counting from zero, that is where arrays really start, and that is what I've used in the example below. There are actually 100 x 20 or 2000 variables in the two dimensional array. It represents characters on a screen, with 100 characters (either a space or a dot) on each line, and there are 20 lines. The first line goes graph [0][0], graph [1][0], graph [2][0], graph [3][0], up to graph [100][1]. The next line is graph [0][1], graph [1][1], ..., graph [100][0]. And so on up to the last row, graph [0][20], board [1][20], ..., graph [100][20]. As far as the internal logic of the program goes, it doesn't really matter whether the array is 100 x 20 or 20 x 100 - I have chosen this way as I am making a graph, and traditionally you specify a point as (x,y). Once you have decided on which way round the array goes, you must stick to it, so choose something which makes sense to you. You can pick out any of these variables by specifying the two subscripts. Again, JavaScript has two subscripts in a different way to many programming languages. There are two lots of square brackets, with a single subscript in each one. Usually, of course, these will be variables, as in this program, and to look at the lot, you'd need to have one loop inside another. You need to be fairly confident with programming to cope with two dimensional arrays, as the code can get quite involved.

This code draws a Sine curve. After defining the array as a global variable, I have to set every element of the array to a space (not a null string - that won't work!) If you don't do this, then the elements of the array are undefined, and when you try to find why your code isn't working, and put them in an alert box to find out what's happening, the computer tells you so two thousand times (and yes, I did make this mistake!)

Then the code actually works out the graph. I only need a single loop here, since I am running along every value of "x" and working out what the corresponding "y" is. If I just used the value of "x", which is 0, 1, 2, etc., I'm not going to get much of a graph. It would be much better to use "x" value of 0.1, 0.2, 0.3, etc. Easily done, divide "x" by ten. However, the "y" value I get out will have a value from -1 to +1, so that needs a little adjusting to get a value from 0 to 20. I also need to round, as array subscripts must be integers or whole numbers, and Sine is not noted for returning integers. (If you don't know what Sine is, don't worry. It's a mathematical function which varies from -1 to +1 and back again in a pretty curve, which is why I'm using it. And if you know what Sine is, but don't understand why I'm using "x" values of 0 to 10, JavaScript Sine function uses radians rather than degrees, so 0 to 10 covers over one cycle.)

Finally we need to output the graph to the HTML. JavaScript doesn't have any graphic capability, so you would have to be mad to draw a graph using JavaScript :-) but this is my attempt. Having constructed my block of variables, every one of which is a space, or a dot showing a point on the graph, I output them within <PRE> ... </PRE>. This is an HTML command which gives equal spacing to all characters, otherwise the spaces will take up less room than the dots, which will mess up the spacing. That was why you needed spaces rather than nulls, by the way - null strings take up no room at all. The double loops need some thinking about. I need to output it line by line, since that's what HTML does. This means that I need to cycle the "x" variable inside the "y" variable, otherwise I'll get the rows and columns the wrong way round, and the graph will be on its side. Also the "y" variable in a graph runs from the bottom of a page to the top, while the lines output will run from the top to the bottom, so if you're not careful your graph is upside down (yes, I got this one wrong as well!) The easiest way round this is to loop "y" from "maxy" to zero rather than the other way round, but that means you must remember to do "y--" rather than "y++" (no - I did get that one right!)

<HTML>
<HEAD>
<SCRIPT TYPE="TEXT/JAVASCRIPT">

// Global variables

var maxx = 100; var maxy = 20
var graph = new Array(maxx)
for (x = 0; x <= maxx; x++) {graph [x] = new Array(maxy)}

// set up graph

function draw() {

  for (x = 0; x <= maxx; x++) {
    for (y = 0; y <= maxy; y++) {
      graph [x] [y] = " "
    }
  }

  for (x = 0; x <= maxx; x++) {
      y = Math.sin (x / 10); y = Math.round ((y + 1) * 10)
      graph [x] [y] = "."
  }

  document.write ("<PRE>")
  for (y = maxy; y <= 0; y--) {
    for (x = 0; x <= maxx; x++) {
      document.write (graph [x] [y])
    }
    document.write ("<BR>")
  }
  document.write ("<" + "/PRE>")
}
</SCRIPT>

</HEAD>
<BODY>
<SCRIPT TYPE="TEXT/JAVASCRIPT">draw() </SCRIPT>
</BODY>
</HTML>


The graph is a little rough, but you can see the approximate curve. The example webpage gives you a choice of several curves, which makes a longer program, and a fair amount of jockeying to make sure that the interesting part of the curve is visible at the right scale. This code is deficient, of course, because it doesn't show an axis for "x" or "y", let alone any scale, which every graph ought to show! This just needs a little more code, putting perhaps "-" for an "x" axis in the right place, and "|" for the "y" axis. I'll leave that for you to extend the program, and work out where the right place should be!



Example - Draughts

The example below is the start of a Draughts program. It is not complete. White starts play. You click on a white to select it. Then you click where you need to go. You can take an opponent's piece by jumping over it.

As I said, the code starts to get complex at this level. Many of the values in variables are chosen by me to have an arbitrary value. I use 1 for represent the white player, and 2 to represent the red player. There needs to be a variable indicating the player's turn - "player". There also needs to be variables saving which row and column have the piece you've selected (since you select on one click and move on the next). I arbitrarily set these variables "selrow" and "selcol" to -1 to show that no piece has been selected yet. All these need to be global variables, of course, since they must be remembered between clicks.

When I set up the board, I need to have white squares and black ones. If it's white, then I just document.write a white square, without a NAME or an ONMOUSEDOWN, since it never needs to be clicked on, or changed. The black squares are more complicated! We need to work out if they have a piece on or not, and which colour. The picture file "player0.gif" is a simple black square, and "player1.gif" and "player2.gif" have pieces of different colours. We need a NAME which uniquely identifies the square, since we might need to change it to a simple black square, or one with a piece on it, in future. We also need an ONMOUSEDOWN to detect when you click on it, and that needs to identify the square row and column as well, so I make them parameters of the function "play". However, once we start playing, we need to know what is on what square, and the computer can't look at the screen to see! So we have a two dimensional array which mirrors whatever is on the screen. So whatever is on the square must be in the array as well.

To play, we need to identify errors, and output an error message (alert boxes are great for this), and then return which means "leave this function without doing any more code" - important after detecting an error! If no piece has been selected (such as at the start), then the first click must be on a piece, and a piece of the correct colour (you can't move your opponent's piece!) If correct, it's a good idea to show the player this so they don't get confused, and know the computer has recognised the click. I do this by changing the picture file to a grey piece for white, and a pink piece for red. I also save the position for later, and return out of the function. The code after this point deals with a click when the piece has been selected. Again, there are some errors, and I also need to work out whether this is a simple move (which needs the current square set to black, and the new square set to a piece on it), or a capture (which needs the opponent's piece removed). And I must remember to keep the array in step with whatever is on the screen (and yes, I did forget at first, which led to a certain amount of bug-hunting!) Since some of this code is repeated on more than one place, I've made it into a function. When the go is over, I have to change the "player" and reset the saved row and column position to show that the next player hasn't selected a piece yet. (Phew!)

<HTML>
<HEAD>
<SCRIPT TYPE="TEXT/JAVASCRIPT">

// Global variables

var board = new Array(7)
for (i = 0; i <= 7; i++) {board [i] = new Array(7)}
player = 1
selrow = -1; selcol = -1

// set up board

function setboard() {

  for (row = 0; row <= 7; row++) {
    for (col = 0; col <= 7; col++) {

      if (row <2) {typ = 2}
      else if (row > 5) {typ = 1}
      else {typ = 0}

      if ((row + col) % 2 == 0) {
        board [row] [col] = -1
        document.write ("<IMG SRC='white.gif' ALT=''>")
      }
      else {
        board [row] [col] = typ
        document.write ("<IMG SRC='player" + typ + ".gif' ")
        document.write ("ALT='' ")
        document.write ("NAME='row" + row + "col" + col + "' ")
        document.write ("ONMOUSEDOWN='play(" + row + ", " + col + ")'>")
      }
    }
    document.write ("<BR>")
  }
}

// play

function play(row, col) {

  if (selrow == -1 && board [row] [col] == 0) {alert ("Not a piece"); return}
  if (selrow == -1 && board [row] [col] != player) {alert ("Not your go"); return}

  if (selrow == -1) {
    selrow = row; selcol = col
    document.images["row" + row + "col" + col].src = "player" + player + "c.gif"
    return
  }

  if (board [row] [col] != 0) {alert ("Not empty"); return}

  if (Math.abs (row - selrow) == 1 || Math.abs (col - selcol) == 1 ) {move(row, col); return}

  if (Math.abs (row - selrow) != 2 && Math.abs (col - selcol) != 2 ) {alert ("Invalid move"); return}

  jumprow = (row + selrow) / 2; jumpcol = (col + selcol) / 2
  if (board [jumprow] [jumpcol] != (3 - player)) {alert ("Invalid jump"); return}
  document.images["row" + jumprow + "col" + jumpcol].src = "player0.gif"
  board [jumprow] [jumpcol] = 0
  move(row, col)
}
// move a piece

function move(row, col) {
  document.images["row" + selrow + "col" + selcol].src = "player0.gif"
  board [selrow] [selcol] = 0
  document.images["row" + row + "col" + col].src = "player" + player + ".gif"
  board [row] [col] = player
  selrow = -1; selcol = -1
  player = 3 - player
}
</SCRIPT>

</HEAD>
<BODY>
<SCRIPT TYPE="TEXT/JAVASCRIPT">
  setboard()
</SCRIPT>

</BODY>
</HTML>
Once you start more complex code, there are certain numeric tricks to make shorter code. You don't have to use them, but if you don't, you'll need to code more "if this then that else the other!" If you have just started programming, or aren't confident with numbers, it might be better to code things in an obvious way. Don't show off just for the sake of it, or you'll end up with a program where later you can't work out what on earth you meant! However, I've put these tricks in here to show they exist.

On the Draughts board, you need black and white squares which are offset for each row. A simple pattern but messy to code. You could test for "row equals 0 or 2 or 4 or 6" but you don't write it like that and it ends up a messy if statement. And you still need to work out what goes on within a row. However, try marking out a Draughts board with its row and column numbers, and add those together. The first square is 0+0=0 (white). The next is 0+1=1 (black). If you do the whole board, you'll find that the even sums are white, and the odd are black. (row + col) % 2 means the remainder when you divide by 2, and this will be 1 is the number is odd, and 0 if it's even. Much easier!

I need to test at one point if the new position is one place diagonally from the old one. If it is then the difference between the old row and the new one, and between the old column and the new one, will be be 1 or -1. Math.abs (..) makes this into a positive number, so I just have to test for 1.

When the go is over, I need to change the variable "player". If it was 2, it must become 1, and if it's 2, it should be 1. "player = 3 - player" does this. (Try it!)

This program is unfinished for lots of reasons. You can't change your mind after selecting a piece, which might mean that you select a piece that can't move, which effectively ends the entire game! Each piece moves diagonally, in the approved Draughts way, yet they can move backwards as well as forwards, which is illegal until after they have reached the end. What is worse, while you can take a single enemy piece (by jumping over it), you cannot take more than one piece. Also there is no count of taken pieces, and no realisation that someone has won, and not even any way to start a new game (other then reloading the whole page). Also you cannot "huff" a piece (this is a technical Draughts term!). The user (or two users) are expected to play both sides - the computer cannot move a piece itself. I leave any further enhancement of this code to the reader. (If you think it's worth it - frankly I'd get out a Draught board myself!)



Return to JavaScript index



Valid HTML 4.01!

© Jo Edkins 2005