-=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- (c) WidthPadding Industries 1987 0|646|0 -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=-
SoCoder -> Article Home -> Coding Basics


 
Jayenkai
Created : 10 May 2009
Edited : 10 May 2009
Language : D

MidletPascal : Cookie : Tic-Tac-Toe part two

Made for my Cookie : It's good enough for me

Note : These tutorials have been created for an "LG Cookie" centric forum, and as such are targetted at that phone.
They're also aimed at folk who may/may not be all that good at coding.
Only time will tell if folk are able to follow!!




Tic-Tac-tuTOErial-Two : Game Mechanics

Hopefully, by this point, you've got a clickable gameplay grid.
But we've only got one player clickable.
So, lets work on getting the player mechanics up and running, shall we?

First off, we need a variable to keep track of which player is currently playing.

var Player:integer;
^ Variable bit.

and in the Loady bit, we'll set it initially to 1. Note, this means player one always goes first when the game's loaded.
Hey, it's their phone, so why shouldn't they!!?

Player:=1;
^ Loady bit.

Next, head back into that great big zany IF section.
Just above mudown=1, we need to do two extra things.
First, switch Player from being 1, or 2, to being 2 or 1.
1 to 2 and 2 to 1 is easy to do.

Player:=3-Player;
^ Inside the big if, just above the mudown:=1 line..

That way, If player is 1, then 3-1 is 2.. If player is 2, then 3-2 is 1, and so on, in a loop.

Next, the line above that is used to set the Playground[] grid to 1. But now, instead, we set it to whatever Player is.
So change it appropriately to.
Playground[x,y]:=Player;

If you compile and run, now, you'll be able to tap for both players!




Your Turn!

Although it's obvious to yourself, it might not be so obvious to the player, whose turn it is.
So, below the grid, we'll stick an extra icon, to show that.

We'll use the same Ecksy and Ohsie icons we used earlier, but instead we'll draw it below the grid.
The ecksy will go on the left, the ohsie on the right.


if Player=1 then drawimage(ecksy,8,270);
if Player=2 then drawimage(ohsie,168,270);

^ under the for's/if's, but above the "Messy bottom bit"

Not exactly complex stuff! But then, it's just pictures! They have no function, they're just for show!

If you're interested to know the layout stuff..
Y = 270 = below the grid.. The grid's 3*80 pixels high, which is 240.. 270's just below, with a gap!

X = 8 for ecksy is where the leftmost grid icons appear. (1*80)-72
X = 168 is where the righthand ones are. (3*80)-72

Obvious placements, really, but it means we're still nice and lined up with everything else.

Good stuff!

Next, winning.
(uhoh!)




Checking

Rule #1 : If the player achieves a horizontal line of 3 items, they win.
Rule #2 : If the player achieves a vertical line of 3 items, they win.
Rule #3 : If the player achieves a diagonal line of 3 items, they win.

If programming terms, Rules 1 and 2 are actually the same thing, but with their x and y's swapped around, since we can check all in the same row at the same time.

The diagonal, though, follows a different check routine, because it's moving both x and y at the same time.
(huh!)

You'll see.

We'll start off with the top row, and build up as we go.

First off, add a "Winner" variable to our game.

var winner:integer;
^ Variable bit.

And initially set it to 0, to symbolise no winner.
winner:=0;
^ Loady bit.

Add yourself a nice "Check" section in the game, by using comments to help guide you later!

// Win Checking
^ shove that line below the two if's that you just added to draw the Player's Turn icons.

From here on, we'll think of everything between there, and the "Messy Bottom Bit" as the Win-Checking section.
Inside, we'll place our first check.

If 1,1 is the same as 2,1, and also the same as 3,1, then all three on the top row are the same, and that player should win.

If (Playground[1,1]=playground[2,1]) and (Playground[1,1]=Playground[3,1]) and (Playground[1,1]>0) then winner:=Playground[1,1];
^ Win check section.

Note, we also make sure that it's actually a player, too, and not all 0's.

That'll only check the first line, though.
There's two more lines to check, and we can check them either of two ways.

1) We could copy and paste that line, and change the numbers to suit.
2) We could get a for loop to do it for us.

Let's do #2!



Checking more!

Place the if inside a for loop. (or, rather, add a for loop around the outside of it.)

for y:=1 to 3 do begin
// Previous line ends up inside..
end;

Now, we fix the check line, to make it check each line.
Change each y co-ordinate from a 1 to a y.

You should now have..

for y:=1 to 3 do begin
If (Playground[1,y]=Playground[2,y]) and (Playground[1,y]=Playground[3,y]) and (Playground[1,y]>0) then winner:=Playground[1,y];
end;


Sorted.
That's all 3 lines being checked, horizontally.

To add vertical lines, we need only to duplicate the check line, and swap the co-ordinates.
(Click on the if line, then hit Ctrl-D to duplicate it, then swap the co-ords)

Now we should have..

for y:=1 to 3 do begin
If (Playground[1,y]=Playground[2,y]) and (Playground[1,y]=Playground[3,y]) and (Playground[1,y]>0) then winner:=Playground[1,y];
If (Playground[y,1]=Playground[y,2]) and (Playground[y,1]=Playground[y,3]) and (Playground[y,1]>0) then winner:=Playground[y,1];
end;


Note that we didn't literally change the y's to x's.. That's because X isn't going around in the for loop.. Only Y is.
It "looks" odd, having "y" in the x position, but it wouldn't work if we changed it to x, because x isn't changing!



Diagonal Wins
The diagonals won't work in our loop, so instead we do it manually, but that's ok, because there's only 2 of them that'll work. So we don't have too much work to do.

Copy and paste the two ifs so you have two new ones under the for loop
We then need to change them to the right grid placings.
[x][ ][x]
[ ][x][ ]
[x][ ][x]

Our two possible wins are..
1,1 2,2 3,3
or
3,1 2,2 1,3

So, go ahead and fill those in..

If (Playground[1,1]=Playground[2,2]) and (Playground[1,1]=Playground[3,3]) and (Playground[1,1]>0) then winner:=Playground[1,1];
If (Playground[1,3]=Playground[2,2]) and (Playground[1,3]=Playground[3,1]) and (Playground[1,3]>0) then winner:=Playground[1,3];

^ under the checker's for loop.

Your whole checker section should now look like so


Nice!
But if you run the game at this point, you can't tell we've just done all that!
That's because we've not added a !Winner! thing anywhere.




!!Winner!!

Let's draw one!
Open your painty program, draw a "WINNER!" sign for each player, and save them as EcksyWin and OhsieWin
The width of your screen is 240 pixels, so make use of the full width.
and we'll use the gap below the grid, so make it about 140 pixels high. (remembering that the screen is 400, the grid is 240, and there's that little bar at the top of the screen.)

Doodle away for each one, save them, and we're ready to pop them in.
Add them as resources with the big green + button.

Setup variables

var ecksywin,ohsiewin:image;
^ Variable bit

Load images
ecksywin:=loadimage('/EcksyWin.png');
ohsiewin:=loadimage('/OhsieWin.png');

^ Loady bit

And, in the main game, where we draw the player's turn, add the winner's drawing code.


if Winner=1 then drawimage(ecksywin,0,240);
if Winner=2 then drawimage(ohsiewin,0,240);


Now, once a player's won, we shouldn't do the following.
1. Allow playing.
2. Draw the player's turn.

So, turn the "if Player=1 then drawimage(ecksy,8,270);" to

if (Player=1) and (Winner=0) then drawimage(ecksy,8,270);

And do the same for Ohsie.

Then in "The big messy if", change the "if (mdown=1) and (mudown=0) then begin" line to

if (mdown=1) and (mudown=0) and (winner=0) then begin


Three simple changes, but they'll stop pretty much everything that we need 'em to.

Go ahead and try out the game..
But, be aware that the game will get stuck, once someone wins.. (or not, as the case may be!)



Reset

There's lots of reasons we should reset the game. Winning's one, Draws are another, and we should probably add a button to do it, too.
So, rather than duplicate things, over and over again, we'll make a little area to do it.

Below the "Win Checking" section, make yourself another "Reset" section.
We'll start it off with an if.

// Reset Section
if Reset=1 then begin

reset:=0;
end;

^ In the new Reset section.

Now, whenever we set Reset to 1, this'll happen, and it'll put Reset back to 0 afterwards. Nice and simple.
var Reset:integer;
^ Don't forget to add Reset as a variable, though!

Inside there, we first need to reset the entire grid to 0, then set Winner to 0, incase someone's won..
That's easy enough to do, since we already have that code up near the top, in the loader section.
You can copy+paste it down here. (don't remove it, just copy+paste!!)

Additionally, add an if that sets player to be the winner, so long as someone's won..

Now your reset should look like this.


Whenever we need to reset the game, we can now do it as easily as setting reset:=1;



Reset A : Win

When someone's won, if there's a click on the screen, reset..
if (winner>0) and (mudown=0) and (mdown=1) then begin mudown:=1; reset:=1; end;
^ under the "If winner=1" winner drawing things bit!

Note, we also set mudown to one, so that if the player's tapped the grid area, it won't instantly count as that player's turn.

Simple..



Reset B : Draw

Draws occur under the following conditions.
1. There's no grid spaces left.
2. Nobody's won.

So, first off, let's add a "GridLeft" variable.
var gridleft:integer;
^ Variables

Now, before our main big for-loop, set GridLeft to 0.
GridLeft:=0;
and inside the same loop, where we do the "if Playground[x,y]=1 then drawimage(ecksy,(x*80)-72,(y*80)-72);" bit, we need an additional line to check for any gridleft's.
if Playground[x,y]=0 then GridLeft:=1; // Will set to 1 if there's any grids left.

Got that working?
Good!

Next, draw yourself a "DRAW!" image, set up the variables, load it in.
You know this bit!
Big green button, Variable var Draw:image;, Loady bit Draw:=loadimage('/Draw.png');..

And down underneith our "Winner!" showing area, add a "Draw!" showing area.

If no winner, and no grids left, then draw the "Draw!" image, and if the screen's clicked, reset.

if (winner=0) and (Gridleft=0) then begin
drawimage(draw,0,240);
if (mudown=0) and (mdown=1) then begin mudown:=1; reset:=1; end;
end;


Woot!

If you run all that, it oughta work as expected.
[1][2][7]
[3][4][8]
[6][5][9] <-- click in that order to check for a draw!!



Reset C : Button Push

We'll work with buttons more closely, in a future tutorial.
For now we'll just do a simple check.
If any button's pushed, reset!
or, rather, if Not No Key is pushed, THEN reset!!

if GetKeyClicked <> KE_NONE then reset:=1;
^ Shove it below that if section that we just put in. somewhere above //Win Checking.

That line simply checks that a key that's pressed is not no_key!


On our cookie, the line responds to The Green Phone Connect button, The Middle App button (although it'll still bring up the App menu) and the Camera button.
It appears that, no matter what we do, those will only ever be the buttons we're allowed to use.
So, keep that in mind for future projects.

You're pretty much limited to two buttons, and one of those is the awkward to tap Camera one.
Dang!

To test on the emulator, since we're not aiming for any particular button, just hit any key on the keyboard.

You oughta be happy with all that, by this stage, so let's get it on the phone, shall we?



--> Phone!

Head into the /bin/ folder.
You've got a jad and a jar.
Ignore the jad, it's useless on the cookie.
Instead, open up the .jar file.
At this point, you're going to need something half decent on your system.
I use WinRar.
Others use WinImage.
There's lots of others.
Pick on, and open the .jar file as though it's an archive.

Inside, head to the meta-inf folder, and grab the Manifest.mf file.
Shove it somewhere you can edit it (back into the /bin/ folder is handy), open it into notepad, and add the following few lines to the bottom of the file.
(to open in notepad, double click it, "Choose a program" and select notepad. Make sure you "Always open with this program")


MIDlet-Touch-Support: True
UseNativeTextButtons: false
ReverseSoftkeys: true
UseNativeCommands: false
LGE-MIDlet-TargetLCD-Height: 400
LGE-MIDlet-TargetLCD-Width: 240

Then pop the new version back into the .jar archive.

All that gets rid of the nasty Touchkey dpad thing at the bottom of the screen.
*phew*

Note, every single time you compile, you're going to have to do that again.
It's annoying, I know, but I can't find a way to do that inside MidletPascal, so.. Them's the breaks I'm afraid..

Pop it in the "Others" directory on your microSD, pop that in the phone, find it, run it, install it, yada yada.

Then play!

Woot!

You got tic-tac-toe!!



Part Three!?!!!

In part three we'll attempt do the following.
1. Add Audio. Simple little midi files that play whenever you do something.
2. Add Vibrate. A little extra feedback whenever you click.
3. Add Artificial Intelligence. (uhoh!)

#3's a biggy!! So don't be expecting the next part to appear so quickly!

Meanwhile, play around with what you have.

If you need to cheat, here's the Sourcecode, so far.

 

Comments