How to make a logical game on Flash. Part 1
This is the Chapter 11 from our book "The Flash 8 Game Developing Handbook", ISBN 1-931769-47-8. CD-ROM included.
You can buy this book from us for $30 only.
Chapter 11. Nim: Programming a Logical Game
This chapter will teach you how to skim through variants of moves when looking for the best move, how to limit the depth of this skimming, and how to implement heuristic algorithms.
11.1. A Description of Nim
A game where the players removed little stones from several groups, taking any number of stones from one group at a time, was known as long ago as in ancient China. I'll describe a variant of this game called Nim. There are three groups of three, four, and five pieces each. Two players take turns removing the pieces. A player can remove from one to all pieces from one group. The player who removed the last piece wins.
This game was popular in Europe and America about a hundred of years ago. Men played it in bars with coins laid out in three rows, and the looser paid for whisky or beer. However, at the beginning of 20th century, an English mathematician found a method to determine whether a particular position is winning and to find the best move if this is the case. I won't disclose the winning strategy to prevent you from being disappointed. Few people know it, and the value of Nim is that it allows me to demonstrate how you can create a function that skims through moves and finds the winning move if it exists. Since my site is called GameIntellect.com, I'm compelled to teach you how to write this game. The program will play fair: it will skim through variants like a human would do. When you learn how to skim through possible moves in your program, you'll be able to write similar programs playing other intellectual games. If you fail, you can ask me for advice.
Unlike Java, C, Delphi, and other authoring environments, Macromedia Flash doesn't offer you many tools for writing "thinking" game programs. Like JavaScript, Perl, and PHP, ActionScript is an interpreted language, and its code is executed tens or even hundreds times slower than a common program. Java applets are processed by browsers using JIT (Just in Time) compilers. They translate Java bytecode into processor code, and a Java applet works as quickly as a Windows application. However, ActionScript bytecode is executed by Flash player. If code attached to a frame or an object is executed longer than 15 seconds, Flash player will display the window shown in Fig. 11.1.

Fig. 11.1. Flash player's message
The message will appear every 15 seconds while the program computes without moving the playing head to another frame. This window indicates that the script hampers Flash player, and the player "suspects" that the script has entered an infinite loop. A click on the No button will continue the execution of the script, but will the user like to click on the button every 15 seconds? This is why your program should think over its move within 14 seconds. You'll avoid these problems if moves are thought over by a shell while the Flash movie just displays them. You already know how to write a shell. For on-line games, however, you'll have to optimize the thinking function so that it conforms to actual connection conditions.
11.2. Preparing Game Graphics
Start a new project and name it nim.fla. Open the Document Properties panel by double-clicking on the 12.0 fps panel located below the timeline and set the movie size to 385 375 pixels. Set the frame rate to 19 fps. I advise that you choose the background color after you finish the project. It would be best to agree the color with the color of your home page. Press the <Shift>+<F2> shortcut and rename the scene Game.
Select the third frame on the main timeline and press <F6>. Attach the following code to the second frame (which is also a key frame):
if (!_totalframes || _framesloaded != _totalframes) gotoAndPlay(1);
This code should be familiar to you. Attach the following code to the third frame:
#include "nim.as"
The main program will be contained in a separate file named nim.as.
11.2.1. A Game Board Square
Start creating graphics with a square of the game board. Let its side be 70 pixels long. However, create the square's shadow first. Create a new clip, name it square (<Ctrl>+<F8>), and export this name for ActionScript. Select the Rectangle tool and disable the outline. (To do this, select Stroke Color on the toolbar and click on the crossed square with the No Color hint). Select the #666666 fill color. While keeping the <Shift> key pressed, draw a square with a side of 70 pixels. To know the precise values, use the Info panel or this square's property panel. To use the latter, select the square and press the <Ctrl>+<F3> shortcut. Center the square using the <Ctrl>+<Alt>+<2> and <Ctrl>+<Alt>+<5> shortcuts and move it 5 pixels down-and-to-the-right. This can be done with the right and down arrow keys. Now draw the board square itself. For its outline, select the #3399FF color an the Solid line two pixels thick. Select the Radial fill. To do this, open the Color Mixer panel (using the <Shift>+<F9> shortcut), make the left marker white, and select the #878787 color for the right marker. Draw a square on an unused place and set its size to 70 70 pixels. Center the square in the same way as its shadow. (The square should overlap the shadow partly). Adjust the fill so that its center is from 8 pixels to 10 pixels above and to the left of the center of the square as shown in Fig. 11.2.

Fig. 11.2. The square clip
Note: you could create the shadow on a separate layer under the square, and this would allow you to move it from behind the square so that it is seen a little. Then you would select the square and move it to the layer with the shadow using the Edit | Paste in Place menu command. However, a piece shouldn't have a shadow below it. This would spoil the impression from the piece's disappearance because the pieces in this game disappear by gradually increasing their transparency.
11.2.2. A Piece
Create a new clip, name it piece, and also export this name for ActionScript. First create a shadow with the same color than the square shadow. It should be a circle with a diameter of 55 pixels. Center it and move it four or five pixels down-and-to-the-right. Draw a circle without an outline on an unused place and center it in the same way as you have centered the square. Select the Radial fill. Set the left and right markers to the colors #66CCFF and #0066FF respectively. Shift the fill center in the same way as with the square. Select everything in the layer and press the Modify | Break Apart menu item to break the image apart. This is necessary for the Shape animation.
To create an animation in which the piece disappears after the gamer removes it from the board, select the fifth frame on the timeline and make it a key frame by pressing the <F6> key. In the sixth frame, select only the piece, so that its fill is displayed in the Color Mixer window, and set the Alpha parameter to 30% using the slider. Repeat this with the shadow. As a result, the piece and its shadow become more transparent, but keep their colors in the sixth frame. However, this isn't very important because the animation is short. Alternatively, you could set the piece color equal to the shadow color in the fifth frame or even move the shadow to another layer and animate it individually. However, as I mentioned earlier, only the visible portion of the shadow should be left.
The Shape animation type is selected in the drop-down list in the property panel of the selected object. Select all the frames and set animation for them. The animated frames on the timeline will acquire a green background, and an arrow from the first to the fifth frame will appear. It only remains for you to write some code. Select the first frame and attach the following code to it:
stop();
Attach the following code to the fifth frame:
this.removeMovieClip();
You should remember this code from Tet-a-Tetris.
11.2.3. Buttons
You should now create three buttons that differ only in labels. Create a new button with the btNewGame name without exporting for ActionScript. Create a shadow for this button. It should be a rectangle 61 pixels wide and 36 pixels high, with the #666666 color, and with a corner radius equal to four. Draw such a rectangle, center it, and move it 4 pixels down-and-to-the-right. As for the fill, it should be of the Linear type, and its left and right markers on the Color Mixer should have the #0066FF color, the central marker having the #61D7FE color. There should be no outline. Draw a rectangle of the same size as the shadow and center it. The New game text should take up two lines. Select the following settings for the text: the Static Text type, the Tahoma font, a font size of 12 pts, the bold typeface, the Center Justify alignment, the Use Device Fonts checkbox unchecked, and the #FF6600 color. Click the Format button and set all the values on the Format Options panel to zeroes. Type the text on the button, move to the Over frame, and press the <F6> to create a key frame. Select the text on the button and change its color to #FFFF00. Create two more buttons, btOK and btYou, in the same manner. The first should bear the OK text on it, and the second should have the Comp. begins text on two lines. For the OK text, set Character Spacing to three to move the letters apart (this input box is located immediately below the Font drop-down list).
My btNewGame button is shown in Fig. 11.3.

Fig. 11.3. The btNewGame button (magnified two times)
Drag these buttons from the library to the work area, more precisely, to the third frame. Set their coordinates as follows: X=12 for the btOK button, X=99 for the btYou button, X=183 for the btNewGame button, and Y=325 for all the buttons.
The purpose of these buttons is following: the btOK button is used for configuration of the gamer's move, the btYou button is used to let the computer make the first move, and the btNewGame button is used to start a new game at any moment. Attach the following code to the buttons:
on (release)
{ userMove();
}
to the btOK button,
on (release)
{ youBegin();
}
to the btYou button, and
on (release)
{ newGame();
}
to the btNewGame button.
These functions (and many others) will be written later.
11.2.4. An Empty Clip for Event Handling
Create another empty clip and name it gameact. You'll attach an event handler to it later. Don't export the clip name for ActionScript. In the third frame of the main timeline, drag this clip to an unused place of the movie work area or even outside this area. Set the Instance Name parameter to gameact. You should remember that this is done on the property panel of the selected object, and the panel is opened using the <Ctrl>+<F3> shortcut.
11.2.5. Clips for Messages
Create four identical clips to display messages.
- gameover - With the Game Over! text
- think - With the Thinking: text
- youlose - With the You lose text
- youwin - With the You win! text
Rectangles with these labels should have shadows, and you already know how to create them. You can draw shadows in a separate layer. This would allow you to adjust the clip size to a shorter or longer label. The rectangles should have rounded corners, no outlines, yellow (#FFFF99) fill color, and the #6666FF text color. The text font should be Tahoma, 24 pts, Static Text, bold, Center Justify. The registration points of all the clips should be in the upper left corner. The gameover clip's rectangle should be 170 pixels wide, and the other rectangles should have widths of 150 pixels. All the rectangles are 50 pixels high.
The gameover clip is shown in Fig. 11.4.

Fig. 11.4. The gameover clip
11.2.6. A Clip For Marking Pieces
What else do you need to allow players to make moves? They should be able to mark pieces they want to be removed from the board after a click on the btOK button. So create a clip for this purpose and name it mark. It should be a semi-transparent circle with a cross (Fig. 11.5).

Fig. 11.5. The mark clip (magnified four times)
To create this clip, press the <Ctrl>+<F8> shortcut, set the mark name, and check the Export for ActionScript checkbox. Select a line width of 3 pixels, the #FF6600 color, and Alpha equal to 50%. Using the Oval tool, draw a circle with a diameter of 25 pixels (be sure to keep the <Shift> button pressed). Align the circle with the center of the work area. Draw a cross with the same line width. If your cross juts out the circle, trim it using the <Del> key.
Next>>