Printris

 Learning Javascript using puzzles and games

 Making your own games

The aim of this document is to enable you to learn how the game works so you can make your own games. Don't worry; you don't need to know all the programming details to start off with.
 

This page describes the game PRINTRISPrintris

Printris

The game Printris is written in JavaScript and standard HTML commands.

The game is based on principle of Tetris.
The player’s task is to locate the same three printing machines vertically or horizontally into one line.
Control of the game is possible by mouse – click on the buttons at the bottom of the screen;or by using the arrows buttons and spacebar;or by using the numerals 4, 5, 6. The game speed is possible to increase or to decrease by the mouse click on the symbols "+" and"-"  or by the keyboard buttons"+" and"-"

The "Teachers Guide" button will show a brief description of the game and its purpose within the Ingot project. 
 

Game Download

The game can be copied and modified according to your own skills:

right clicking the mouse will bring up a menu. The "View Source" item on the menu must be selected (the text of the menu can differ slightly according to the browser used; the text "View Source" refers to the Internet Explorer browser and the "View Page Source" is used by the Mozilla Firefox browser).

Mark the text using standard Windows OS commands (e.g. CTRL+A) and copy it into the clipboard (e.g. CTRL+C). Open any text editor capable of processing plain text (e.g. Notepad, which is part of Windows OS) and paste the text into the editor from the clipboard (e.g. CTRL+V).

Save the text displayed in the word editor as a file of any name and use either "html" or "htm" extension, which is the standard for the files to be opened in any internet browser.


Images are another essential part of the game and the list of images used is as follows:

tisk1.gif, tisk2.gif, tisk3.gif, tisk4.gif    –  printing machines images

pozadi.gif, background.jpg  – game background and background of the playing area

The images can be downloaded via changing the address in the browser bar: „printris.htm“is replaced for example with „images/tisk1.gif“ as shown on the example below

 (for example:  www.ingot.org/javascript/printris/printris.htm to www.ingot.org/javascript/printris/images/printris.png )

After pressing "Enter" on the keyboard, a dialog box will prompt you to save a file. The file must be saved under the same name and extension and into the same directory containing the previous file.

 

The image must be saved in the subdirectory named "images", which must be created beforehand.

Correct function of all downloaded components of the game can be verified by launching the "printris.htm" file


Replacing Images

The game images can be replaced with your own ones. The game background can be modified under the following conditions:

  • the image files must have an identical name and extension(more experienced programmers can use a different type of the image file, provided they modify its source code accordingly as described below)
  • the game background is only a template, which consists of its repeated parts
  • the game background must be transparent (description of this feature is outside of the scope of this manual and can be found on the web)
  • the images must have an identical length and width measured in pixels (description of this feature is outside of the scope of this manual and can be found on the web)

Changes of the Directory Name, Using Different Image File Formats

If the different names must be used for image files or a subdirectory containing them, it is necessary to modify them properly by editing the "printris.htm" file. This action is designed for more experienced programmers.

 

  • Printing machines images and background image: in the file printris.htm, code line 79
    Pic[0] = new Image(); Pic[0].src = "images//pozadi.gif";
    Pic[1] = new Image(); Pic[1].src = "images//tisk1.gif";
    Pic[2] = new Image(); Pic[2].src = "images//tisk2.gif";  
    Pic[3] = new Image(); Pic[3].src = "images//tisk3.gif";  
    Pic[4] = new Image(); Pic[4].src = "images//tisk4.gif"; ) there is necessary to replace the folder images by the new one and the type gif by the new one type.
  • Image of the playing area: in the file printris.htm, code line 11
    body {background-image: url(images/background.png);}
    there is necessary to replace the folder images by the new one and the type png by the new one type.


Brief Description of the Game Functions in JavaScript Language

As mentioned earlier, the game is written using JavaScript and HTML commands. Brief help descriptions for functions and elements, and descriptions of variables are stated directly in the code (in the comment lines). In order to understand the function, basic knowledge of JavaScript and HTML programming is necessary.


Heading of the file HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<META NAME="description" content="Printris- JavaScript game">
<META NAME="author" content="Jiri Mensik">
<META NAME="keywords" content="Javascript, Game">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<style type="text/css">
body {
    background-image: url(images/background.png);
}
</style>
<title>Printris</title></head>


 HTML code, score table and control

<BODY>
<form>
<DIV ALIGN=center>
<table noborder cellpadding=0 cellspacing=0>
<tr>
<td valign="top" bgcolor="#99CCCC"><strong>Speed:</strong>  <input type=button value="-" width=16 style="width:16;background-color:#FFFFFF" onClick="KeyDown(45);HideFocus()"></td>
<td><input size=1 name="Level" onFocus="HideFocus()"></td>
<td><input type=button value="+" width=16 style="width:16;background-color:#FFFFFF" onClick="KeyDown(43);HideFocus()"></td>
<td valign="middle" bgcolor="#99CCCC"><strong>Score:</strong>  <input size=4 name="Score" onFocus="HideFocus()"></td>
<td><input type=button value="Teacher's guide" name="Help" width=120 style="width:120;background-color:#FFFFFF" onClick="javascript:teachers_guide()"></td>
</tr></table>

Javascript code

Keyboard test

<script language="JavaScript1.2">
//browser test
var IsNetscape;
if(navigator.appName == "Netscape") IsNetscape = true;
else IsNetscape = false;
if (navigator.appName != "Microsoft Internet Explorer")
  document.captureEvents(Event.KEYDOWN)
document.onkeydown = NetscapeKeyDown;
function NetscapeKeyDown(key)
{ KeyDown(key.which);
}
</script>
<script for=document event="onkeydown()" language="JScript">
if (window.event) KeyDown(window.event.keyCode);
</script>

<script language="JavaScript">
var i, j, c, nc, dt, IsOver, MaxW=3, MaxH=12, w, h, Level, Score, TimerInterval, IsHideFocus=true;

document.open("text/plain");
//test keys
if (navigator.appName == "Konqueror")
{ document.write("<input width=0 height=0 style=\"width:0; height:0\" name=\"KeyCatch\" onBlur=\"KeyCatchFocus()\" onKeyUp=\"KeyCatchChange()\">");
  KeyCatchFocus();
  IsHideFocus=false;
}
function KeyCatchFocus()
{ setTimeout("document.forms[0].KeyCatch.focus()",100);
}
function KeyCatchChange()
{ var vv=""+document.forms[0].KeyCatch.value;
  if (vv=="") return;
  KeyDown(vv.charCodeAt(0));
  document.forms[0].KeyCatch.value="";
}


Background drawing

//drawing background
document.writeln("<table noborder cellpadding=0 cellspacing=0 bgcolor=#FFFFFF><tr><td>");
for (j=0; j < MaxH; j++)
{ for (i=0; i < MaxW; i++)
    document.write("<IMG src=\"images\pozadi.gif\" border=0>");
  document.writeln("<BR>");
}
document.writeln("</td></tr></table>");
document.close();


Initialization of variables

// initialization of variables
Level=4;
Fld = new Array(MaxW);
for (i=0; i < MaxW; i++)
{ Fld[i]=new Array(MaxH);
}
BFld = new Array(MaxW);
for (i=0; i < MaxW; i++)
{ BFld[i]=new Array(MaxH);
}
Pic= new Array(5);
Pic[0] = new Image(); Pic[0].src = "images//pozadi.gif";
Pic[1] = new Image(); Pic[1].src = "images//tisk1.gif";
Pic[2] = new Image(); Pic[2].src = "images//tisk2.gif";   
Pic[3] = new Image(); Pic[3].src = "images//tisk3.gif";   
Pic[4] = new Image(); Pic[4].src = "images//tisk4.gif"; 
 

Test pressing keys

//test pressing keys
function KeyDown(whichkey)
{ //alert(whichkey);
  if ((whichkey==43)||(whichkey==107)||(whichkey==65451))
  { Level++;
    if (Level>8) Level=8;
    else Init();
  }    
  if ((whichkey==45)||(whichkey==109)||(whichkey==65453))
  { Level--;
    if (Level<1) Level=1;
    else Init();
  }    
  if (whichkey == 37) AllLeft();
  if (whichkey == 39) AllRight();
  if (whichkey == 40) AllSpace();
  if (whichkey == 32) AllSpace();
  if (whichkey == 52) AllLeft();
  if (whichkey == 53) AllSpace();
  if (whichkey == 54) AllRight();
  if (whichkey == 12) AllSpace();
  if (whichkey == 65460) AllLeft();
  if (whichkey == 65461) AllMiddle();
  if (whichkey == 65462) AllRight();
}  


Timer

// timer
function Timer()
{ if (! IsOver)
  { if (nc)
    { dt=0;
      ThreeTest();
      if (dt>0) Erase();
      if (dt==0)
      { NewChip();
        nc=false;
      }
    }
    else ChipDown();
  }
  RefreshScreen();
}
// game initialization
function Init()
{ for (i=0; i<MaxW; i++)
  { for (j=0; j<MaxH; j++)
    { Fld[i][j]=0;
      BFld[i][j]=false;
    }
  }
  nc=true;
  IsOver=false;
  Score=0;
  RefreshScreen();  
  window.clearInterval(TimerInterval);
  TimerInterval=window.setInterval("Timer()",50*(8-Level)+Level);
}


Test positions (left, right, middle, space, random position)

// test position left
function AllLeft()
{ if ((IsOver)||(nc)) return;
  if (w>0)
  { if (Fld[w-1][h]==0)
    { Fld[w-1][h]=c;
      Fld[w][h]=0;
      w--;
    }
  }
  RefreshScreen();
}
// test position right
function AllRight()
{ if ((IsOver)||(nc)) return;
  if (w<MaxW-1)
  { if (Fld[w+1][h]==0)
    { Fld[w+1][h]=c;
      Fld[w][h]=0;
      w++;
    }
  }
  RefreshScreen();  
}
// test position middle
function AllMiddle()
{ if (w>1) AllLeft();
  if (w<1) AllRight();
}
// test position space
function AllSpace()
{ while ((!nc)&&(!IsOver)) ChipDown();
}
// random position new object
function NewChip()
{ w=Math.round(Math.random()*100) % MaxW;
  c=Math.round(Math.random()*100) % (MaxW+1) + 1;
  h=0;
  Fld[w][h]=c;
}


Test position (object is down, three objects)

//test - object is down
function ChipDown()
{ if (h<MaxH-1)
  { if (Fld[w][h+1]==0)
    { Fld[w][h+1]=c;
 
     Fld[w][h]=0;
      h++;
    }
    else
    { if (h==0)
      { IsOver=true;
        if (window.opener)
        { if (window.opener.SetHighscores)
            window.opener.SetHighscores("Threefit","",Score,1);
        }
        if (confirm("Game over ! Score: " + Score + ". Play again?")) Init();
      }
      else nc=true;
    }
  }
  else
  nc=true;
}
// test three objects
function ThreeTest()
{ dt=0;
  for (j=MaxH-1; j>=2; j--)
  { i=0;
    c=Fld[i][j];
    if (c!=0)
    { if ((Fld[i][j-1]==c)&&(Fld[i][j-2]==c))
      { dt++;
        BFld[i][j]=true;
        BFld[i][j-1]=true;
        BFld[i][j-2]=true;
      }
      if ((Fld[i+1][j-1]==c)&&(Fld[i+2][j-2]==c))
      { dt++;
        BFld[i][j]=true;
        BFld[i+1][j-1]=true;
        BFld[i+2][j-2]=true;
      }
    }
    i=1;
    c=Fld[i][j];
    if (c!=0)
    { if ((Fld[i][j-1]==c)&&(Fld[i][j-2]==c))
      { dt++;
        BFld[i][j]=true;
        BFld[i][j-1]=true;
        BFld[i][j-2]=true;
      }
      if ((Fld[i-1][j]==c)&&(Fld[i+1][j]==c))
      { dt++;
        BFld[i-1][j]=true;
        BFld[i][j]=true;
        BFld[i+1][j]=true;
      }
    }
    i=2;
    c=Fld[i][j];
    if (c!=0)
    { if ((Fld[i][j-1]==c)&&(Fld[i][j-2]==c))
      { dt++;
        BFld[i][j]=true;
        BFld[i][j-1]=true;
        BFld[i][j-2]=true;
      }
      if ((Fld[i-1][j-1]==c)&&(Fld[i-2][j-2]==c))
      { dt++;
        BFld[i][j]=true;
        BFld[i-1][j-1]=true;
        BFld[i-2][j-2]=true;
      }
    }
  }
}


Erase of objects

//erase
function Erase()
{ for (j=0; j<MaxH; j++)
  { for (i=0; i<MaxW; i++)
    { if (BFld[i][j])
      { BFld[i][j]=false;
        Fld[i][j]=0;
      }
    }
  }
  do
  { c=0;
    for (j=MaxH-1; j>=1; j--)
    { for (i=0; i<MaxW; i++)
      { if ((Fld[i][j]==0)&&(Fld[i][j-1]!=0))
        { Fld[i][j]=Fld[i][j-1];
          Fld[i][j-1]=0;
          c++;
        }
      }
    }
  }
  while (c>0);
  Score+=3*Level*dt;
  i=1;
  if ((Score>33)&&(Level<2)) i=2;
  if ((Score>99)&&(Level<3)) i=3;
  if ((Score>333)&&(Level<4)) i=4;
  if ((Score>666)&&(Level<5)) i=5;
  if ((Score>1111)&&(Level<6)) i=6;
  if ((Score>1919)&&(Level<7)) i=7;
  if ((Score>3333)&&(Level<8)) i=8;
  if (i>Level)
  { Level=i;
    window.clearInterval(TimerInterval);
    TimerInterval=window.setInterval("Timer()",50*(8-Level)+Level);
  }
}


Refresh of the screen

//refresh screen
function RefreshScreen()
{ for (i=0; i < MaxW; i++)
  { for (j=0; j < MaxH; j++)
      window.document.images[i+MaxW*j].src = Pic[Fld[i][j]].src;
  }
  window.document.forms[0].Level.value = Level;
  window.document.forms[0].Score.value = Score;
}
function HideFocus()
{ if (IsHideFocus)
  { window.document.forms[0].Help.focus();
    window.document.forms[0].Help.blur();
  }
}
Init();
HideFocus();


Link to the teachers guide

//teacher guide
function teachers_guide()
{  
 window.open('teachers_guide.htm','','scrollbars=yes,menubar=no,height=500,width=350,resizable=yes,toolbar=no,location=no,status=no');
}


Key test

if (navigator.appName != "Microsoft Internet Explorer") document.captureEvents(Event.KEYDOWN);
document.onkeydown = NetscapeKeyDown;
function NetscapeKeyDown(key)
{ KeyDown(key.which);
}  

</script>
<table noborder cellpadding=0 cellspacing=0>
<tr>
<td><input type=button value="<-" width=37 style="width:37;background-color:#FFFFFF" onClick="KeyDown(37);this.blur()"></td>
<td><input type=button value="\/" width=37 style="width:37;background-color:#FFFFFF" onClick="KeyDown(40);this.blur()"></td>
<td><input type=button value="->" width=37 style="width:37;background-color:#FFFFFF" onClick="KeyDown(39);this.blur()"></td>
</tr>
</table>
</DIV>
</form>
</BODY>