0% found this document useful (0 votes)
23 views847 pages

Programming Games With Microsoft Small Basic

Uploaded by

Nuno Gomes
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views847 pages

Programming Games With Microsoft Small Basic

Uploaded by

Nuno Gomes
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 847

Programming Games with

Microsoft® Small Basic

© PHILIP CONROD & LOU TYLEE, 2013

Kidware Software
PO Box 701
Maple Valley, WA 98038

http://www.computerscienceforkids.com
http://www.kidwaresoftware.com
Copyright © 2013 by Philip Conrod & Lou Tylee. All rights reserved

Kidware Software LLC


PO Box 701
Maple Valley, Washington 98038
1.425.413.1185
www.kidwaresoftware.com
www.computerscienceforkids.com
www.biblebytebooks.com

All Rights Reserved. No part of the contents of this book may be reproduced or transmitted in any
form or by any means without the written permission of the publisher.

Printed in the United States of America

ISBN-13: 978-1-937161-98-9 (Electronic Edition)

Previous edition published as “Programming Kid Games with Microsoft Small Basic”

Cover Design by Stephanie Conrod


Copy Edit by Jessica Conrod
Book Cover Illustration by Kevin Brockschmidt

This copy of the “Programming Games with Microsoft Small Basic” book and the associated
software is licensed to a single user. Copies of the course are not to be distributed or provided to any
other user. Multiple copy licenses are available for educational institutions. Please contact Kidware
Software for school site license information.

This guide was developed for the course, “Programming Games with Microsoft Small Basic,”
produced by Kidware Software, Maple Valley, Washington. It is not intended to be a complete
reference to the Small Basic language. Please consult the Microsoft website for detailed reference
information.
This guide refers to several software and hardware products by their trade names. These references
are for informational purposes only and all trademarks are the property of their respective companies
and owners. Microsoft, Visual Studio, Small Basic, Visual Basic, Visual J#, and Visual C#,
IntelliSense, Word, Excel, MSDN, and Windows are all trademark products of the Microsoft
Corporation. Java is a trademark product of the Oracle Corporation. JCreator is a trademark product
of XINOX Software

The example companies, organizations, products, domain names, e-mail addresses, logos, people,
places, and events depicted are fictitious. No association with any real company, organization,
product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred.

This book expresses the author’s views and opinions. The information in this book is distributed on
an "as is" basis, without and expresses, statutory, or implied warranties.

Neither the author(s) nor Kidware Software shall have any liability to any person or entity with
respect to any loss nor damage caused or alleged to be caused directly or indirectly by the
information contained in this book.
About The Authors Philip Conrod has authored, co-authored and
edited numerous computer programming books for kids, teens and adults.
Philip holds a BS in Computer Information Systems and a Master's
certificate in the Essentials of Business Development from Regis
University. Philip started programming computers in 1977 at 13 years of
age. Philip has also held various Information Technology leadership roles in
companies like Sundstrand Aerospace, Safeco Insurance Companies,
FamilyLife, Kenworth Truck Company, PACCAR and Darigold. Philip
serves as the President & Publisher of Kidware Software, LLC. He is the
proud father of three “techie” daughters. Philip and his family live in Maple
Valley, Washington.

Lou Tylee holds BS and MS degrees in Mechanical Engineering and a PhD


in Electrical Engineering. Lou has been programming computers since 1969
when he took his first Fortran course in college. He has written software to
control suspensions for high speed ground vehicles, monitor nuclear power
plants, lower noise levels in commercial jetliners, compute takeoff speeds
for jetliners, locate and identify air and ground traffic and to let kids count
bunnies, learn how to spell and do math problems. He has written several
online texts teaching Visual Basic, Visual C# and Java to thousands of
people. He taught a beginning Visual Basic course for over 15 years at a
major university. Currently, Lou works as an engineer at a major Seattle
aerospace firm. He is the proud father of five children and proud husband of
his special wife. Lou and his family live in Seattle, Washington.
Acknowledgements

I want to thank my three wonderful daughters - Stephanie, Jessica and


Chloe, who helped with various aspects of the book publishing process
including software testing, book editing, creative design and many other
more tedious tasks like finding errors and typos. I could not have
accomplished this without all your hard work, love and support.

I also want to thank my multi-talented co-author, Lou Tylee, for doing all
the real hard work necessary to develop, test, debug, and keep current all
the ‘kid-friendly’ applications, games and base tutorial text found in this
book. Lou has tirelessly poured his heart and soul into so many previous
versions of this tutorial and there are so many beginners who have benefited
from his work over the years. Lou is by far one of the best application
developers and tutorial writers I have ever worked with. Thank you Lou for
collaborating with me on this book project.
Contents

1. Writing Programs Using Small Basic


Preview

Introducing Kid Games With Small Basic

Requirements for Kid Games With Small Basic

Introducing Small Basic

Starting Small Basic

Running a Small Basic Program

Chapter Review

2. Overview of Small Basic Objects


Review and Preview

Objects, Properties, Methods and Events

TextWindow Object

GraphicsWindow Object

Controls Object

Program Object

Text Object
Mouse Object

ImageList Object

Shapes Object

File Object

Timer Object

Sound Object

Chapter Review

3. Overview of Small Basic Programming


Review and Preview

A Brief History of BASIC

Variables

Small Basic Data Types

Arrays

Intellisense Feature

Small Basic Statements and Expressions

Small Basic Arithmetic Operators

Comparison and Logical Operators

Concatenation Operator

Small Basic Methods

String Methods
Math Methods

Random Numbers

Graphics Methods

Shapes Objects

Small Basic Decisions - If Statements

Small Basic Looping

Small Basic Counting

Small Basic Subroutines

Chapter Review

4. Debugging a Small Basic Program


Review and Preview

Debugging a Small Basic Program

Syntax Errors

Run-Time Errors

Logic Errors

Chapter Review

5. Safecracker Program
Review and Preview

Safecracker Program Preview

Game Window Design


Safecracker Window Design

Window Design – Draw Safe

Window Design – Display Combination Digits

Window Design – Results Area

Code Design – Initializing Stopped State

Code Design – Stopped to Playing State

Code Design – Playing to Stopped State

Code Design – Generating Secret Combination

Code Design – Accepting Player Input

Code Design – Checking Player Input

Code Design – Adding Sounds

Safecracker Game Program Listing

Safecracker Game Program Review

Safecracker Game Program Enhancements

6. Tic Tac Toe Program


Review and Preview

Tic Tac Toe Program Preview

Tic Tac Toe Window Design

Window Design – Message Area

Window Design – Draw Grid


Window Design – Add Buttons

Code Design – Initializing Stopped State

Code Design – Stopped to Playing State

Code Design – Playing to Stopped State

Code Design – Marking Grid

Code Design – Checking for Win

Code Design – Random Computer Moves

Code Design – Smart Computer Moves

Code Design – Adding Sounds

Tic Tac Toe Game Program Listing

Tic Tac Toe Game Program Review

Tic Tac Toe Game Program Enhancements

7. Match Game Program


Review and Preview

Match Game Program Preview

Match Game Window Design

Window Design – Draw Picture Boxes

Window Design – Scores

Window Design – Message Area

Window Design – Add Buttons


Code Design – Initializing Stopped State

Code Design – Adding Photos

Code Design – Integer Shuffling

Code Design – Stopped to Playing to Stopped State

Code Design – Displaying Photos

Code Design – One Player, Solitaire Game

Code Design – Computer Moves

Code Design – Random Computer

Code Design – Smart Computer

Match Game Program Listing

Match Game Program Review

Match Game Program Improvements

8. Pizza Delivery Program


Review and Preview

Pizza Delivery Program Preview

Pizza Delivery Window Design

Window Design – Building Delivery Grid

Window Design – Clock and Sales Display

Window Design – Message Area

Window Design – Pizza Oven


Window Design – Pizza Loading Boxes

Window Design – Remaining Buttons

Code Design – Initializing Stopped State

Code Design – Clock

Code Design – Phone Orders

Code Design – Pizza Oven

Code Design – Load Car

Code Design – Move Car

Code Design – Deliveries

Window Design – Sales Results

Code Design – Sales Results

Pizza Delivery Program Listing

Pizza Delivery Game Program Review

Pizza Delivery Game Program Improvements

9. Moon Landing Program


Review and Preview

Moon Landing Program Preview

Moon Landing Window Design

Window Design – Lander Viewer

Window Design – Status Display


Window Design – Trajectory Display

Window Design – Add Buttons

Code Design – Initial Steps

Code Design – Starting, Clock Display

Code Design – Physics of Moon Landing

Remaining Work

Code Design – Landing Pad Distances

Code Design – Landing Detection

Code Design – Pilot Levels and Sounds

Code Design – Trajectory Display, Suggested Path

Code Design – Trajectory Display, Actual Path

Code Design – Lander Animation

Code Design – Adding Thrust

Code Design – Displaying Pad

Code Design – Autopilot

Moon Landing Game Program Listing

Moon Landing Game Program Review

Moon Landing Game Program Improvements

10. Leap Frog Program


Review and Preview
Leap Frog Program Preview

Game Design – Prelude to Window Design

Leap Frog Window Design

Window Design – Add Buttons

Code Design – Road Panel

Code Design – River Panel

Code Design – Grass Panel (Snake)

Code Design – Moving the Frog

Collision Detection

Code Design – Vehicle Collisions

Code Design – Snake Collisions

Code Design – Log Collisions

Code Design – Home Collisions

Code Design – Game Levels

Code Design – Scoring

Window Design – High Scores

Code Design – Displaying High Scores

Code Design – Saving High Scores

Code Design – Reading High Scores

Code Design – Adding to High Scores


A Possible Problem

Leap Frog Game Program Listing

Leap Frog Game Program Review

Leap Frog Game Program Enhancements

Appendix I. Small Basic Colors

Appendix II. Sharing a Small Basic Program

More Self-Study or Instructor-Led Computer


Programming Tutorials by Kidware Software
Introduction Microsoft Small Basic is a wonderful programming
environment for beginners. Small Basic is very easy and approachable for
both kids and adults. The aim of this book is to teach you the fundamentals
of programming with Microsoft Small Basic by using the free Microsoft
Small Basic Development Environment. You will learn the features of the
Small Basic language, and then use them to build applications running on
the Microsoft Windows operating system.

PROGRAMMING GAMES WITH MICROSOFT SMALL BASIC


teaches Small Basic programming concepts while providing detailed step-
by-step instructions for building many fun games. The tutorial is
appropriate for both kids and adults. The games built are non-violent and
teach logical thinking skills.

PROGRAMMING GAMES WITH MICROSOFT SMALL BASIC


explains (in simple, easy-to-follow terms) how to build a Small Basic game
program. Students learn about program design, Small Basic objects, many
elements of the Small Basic language, and how to debug and share finished
programs. Game skills learned include handling multiple players, scoring,
graphics, animation, and sounds. The game projects built include (in
increasing difficulty level). The product includes over 700 pages of self-
study notes, all Small Basic source code and all needed graphics and sound
files.

System Requirements You will need the following hardware and


software to complete the exercises in this book:

● Microsoft Windows XP with Service Pack 3

● Microsoft Small Basic v1.0

● 766 MHz Pentium or compatible processor (1.5 Ghz Pentium Recommended) ● 256 MB
RAM (512MB or more recommended) ● Video Monitor (1024 x768) with High Color 16
bit) ● CD-ROM or DVD-ROM Drive ● Microsoft Mouse or compatible pointing device
Course Prerequisites To grasp the concepts presented in
PROGRAMMING GAMES WITH MICROSOFT SMALL BASIC,
you should possess a working knowledge of the Windows operating system.
You should know how to locate, copy, move and delete files. You should be
familiar with the simple tasks of using menus, toolbars, resizing windows,
and moving windows around.

You should have had some exposure to Small Basic programming (or some
other programming language). We offer a beginning programming tutorial
BEGINNING MICROSOFT SMALL BASIC that would help you gain
this needed exposure.

You will also need the ability to view and print documents saved in the
Adobe Acrobat format.

Regarding software requirements, to use Small Basic, you (and your


potential users) must be using Windows 8, Windows 7, Windows XP, or
Windows Vista. These notes and all projects are developed using Windows
XP. And, of course, you need to have the Small Basic product installed on
your computer (Version 1.0 or higher). It is available for free download
from Microsoft. Follow this link for complete instructions for downloading
and installing Small Basic on your computer: http://www.smallbasic.com
Using Programming Kid Games With Microsoft
Small Basic If you purchased this book through a 3rd Party Book
Store, the source code solutions and multimedia files for this tutorial are
included in a downloadable compressed ZIP file that is available for
download directly from our webpage at:
http://www.computerscienceforkids.com/PKGSB-Registration.aspx

Please complete the online registration web form at the webpage above with
your name, shipping address, email address, date of purchase, online or
physical store name, and your order confirmation number from that store.
After we receive all this information from you we will email you a
download link for the Program Solution and Multimedia Files associated
with this book.

WARNING: If you purchased this book “used” or “second hand” you are
NOT licensed or entitled to download the Program Solution Files. However,
you can purchase the Download Only version of this book as an E-Book at
a discounted price which allows you access to the program solutions and
multimedia files required for completing this tutorial.

The course notes and code for PROGRAMMING GAMES WITH


MICROSOFT SMALL BASIC are included in one or more ZIP file(s).
Use your favorite ‘unzipping’ application to write all files to your computer.
The course is included in the folder entitled KidGamesSB. There’s a
chance when you copy the files to your computer, they will be written as
‘Read-Only.’ To correct this (in Windows Explorer or My Computer),
right-click the KidGamesSB folder and remove the check next to Read
only. Make sure to choose the option to apply this change to all sub-folders
and files.

The KidGamesSB Programs folder includes all programs developed


during the course.
1. Writing Programs Using Small Basic
Preview

In this first chapter, we will do an overview of how to write a


program using Small Basic. You’ll get a brief history of Small Basic
and look into use of the Small Basic development environment.
Introducing Programming Games With Microsoft Small Basic
In these notes, we will use Small Basic to build many fun game programs.
The games are non-violent and teach logical thinking skills. They are
appropriate for kids of all ages (even adults). The programs you will build
are (in increasing complexity):

➢ Safecracker – Decipher a secret combination using clues from the


computer.
➢ Tic Tac Toe – The classic game – one of the first programmed by
Bill Gates!
➢ Match Game – Find matching pairs of hidden photos – you use your
own photos!
➢ Pizza Delivery – A business simulation where you manage a small
pizza shop for a night.
➢ Moon Landing – Land a module on the surface of the moon.
➢ Leap Frog – A fun arcade game where you need to get a frog
through traffic and across a raging river.

These programs will teach many of the skills needed to be a successful


game programmer. You will learn about timing, multi-player games,
scoring, simulation techniques and animation.

Each program will be addressed in a single chapter. Complete step-by-step


instructions covering every program detail will be provided. Before
beginning the programs, however, we will review Small Basic and its
development environment in the remainder of this chapter. Then, we
provide an overview of the objects used in Small Basic (Chapter 2), a
review of the Small Basic programming language (Chapter 3) ), and
instructions on using the Small Basic debugging (Chapter 4). The programs
will begin with Chapter 5.
Requirements for Programming Games With Microsoft Small
Basic Before starting, let’s examine what you need to successfully build
the programs included with Programming Games With Microsoft Small
Basic. As far as computer skills, you should be comfortable working within
the Windows environment. You should know how to run programs, find and
create folders, and move and resize windows.

As far as programming skills, we assume you have had some exposure to


computer programming using some language. If that language is Small
Basic, great!! We offer two tutorials Microsoft Small Basic for Kids and
Beginning Microsoft Small Basic, that could help you gain that exposure
(see our website for details). But, if you’ve ever programmed in any
language (Visual Basic, C, C++, C#, Java, J#, Ada, even FORTRAN), you
should be able to follow what’s going on. Even if you are a veteran
programmer, we suggest you go through the first three chapters before
attacking the programs. This review will give you some idea of the
terminology we use in referring to different parts of a Small Basic program.

Regarding software requirements, to use Small Basic, you must be using


Windows 8, Windows 7, Windows XP, or Windows Vista. These notes and
all programs are developed using Windows Vista and Version 1.0 of Small
Basic. And, of course, you need to have the Small Basic product installed
on your computer. It is available for free download from Microsoft. Follow
this link for complete instructions for downloading and installing Small
Basic on your computer: http://www.smallbasic.com/
Introducing Small Basic In the late 1970’s and early 1980’s, it seems
there were computers everywhere with names like Commodore 64, Texas
Instruments 99/4A, Atari 400, Coleco Adam, Timex Sinclair and the IBM
PC-Jr. Stores like Sears, JC Penneys and even K Mart sold computers.

One thing these machines had in common was that they were all
programmed in some version of Microsoft’s BASIC. Each computer had its
own fans and own magazines. Users would wait each month for the next
issue of a magazine with BASIC programs you could type into your
computer and try at home.

This was a fun and exciting time for the beginning programmer, but the fun
times ended with the introduction of the IBM-PC in the early 1980’s.
Bigger and faster computers brought forth bigger languages and bigger
development environments. These new languages were expensive to
acquire and difficult for the beginning programmer to grasp.

Which brings us to Small Basic, which I would call a relative of the early,
original BASIC language. The development of Small Basic is an attempt to
rekindle the exciting days when just about anyone could sit down at a
computer and write a simple program using the BASIC language.

Those of you who wrote programs on those old “toy” computers will
recognize the simplicity of the Small Basic language and the ease of its use.
And, you will also notice Small Basic is a great environment for writing
and testing code, something missing in the early 1980’s. For those of you
new to programming, I hope you can feel the excitement we old timers once
had. For the old timers, I hope you rekindle your programming skills with
this new product.

Small Basic possesses many features of more powerful (and more


expensive) programming languages:

➢ Easy-to-use, Integrated Development Environment (IDE) ➢


Response to mouse and keyboard actions ➢ Full array of
mathematical, string handling, and graphics functions ➢ Can easily
work with arrays ➢ Sequential file support
Starting Small Basic ● We assume you have Small Basic installed and
operational on your computer. Once installed, to start Small Basic:

➢ Click on the Start button on the Windows task bar ➢ Select


Programs, then Small Basic ➢ Click on Microsoft Small Basic

(Some of the headings given here may differ slightly on your computer, but
you should have no trouble finding the correct ones.) The Small Basic
program should start. If you are using Windows 8, search for the Small
Basic tile on the menu page.

After installation and trying to start, you may see an error message that
announces Small Basic cannot be started. If this occurs, try downloading
and installing the latest version of the Microsoft .NET framework at:
http://msdn.microsoft.com/en-us/netframework/aa569263.aspx

This contains some files that Small Basic needs to operate and such files
may not be on your computer.
Upon starting, my screen shows:

This window displays the Small Basic Development Environment. There


are many areas of interest on the screen. At the top of the window is the
Title Bar. The title bar gives us information about what program we’re
using and what Small Basic program we are working with.

Below the title bar is a Toolbar. Here, little buttons with pictures allow us
to control Small Basic.

In the middle of the screen is the Editor. This is where we will write our
Small Basic programs. To the right is a Help area. Small Basic has great
help features when writing programs. This area will display hints and tips
while we write code.
Running a Small Basic Program Let’s write our first Small Basic
program. When you start, a new editor window appears. You can also get a
new editor window by clicking the New toolbar button. Type these two
lines in the editor window: TextWindow.Title = "Hello Program"

TextWindow.WriteLine("This is the first line of the program.") The editor


window should look like this:

Notice as you started typing the first line, this popped-up:

Small Basic has “intellisense” and uses this to make typing suggestions.
You can just keep typing or accept its suggestion by scrolling through the
pop-up list and pressing the Enter key.
Also, notice this appeared in the help area:

Once you typed TextWindow, the help feature displayed all it knows about
the TextWindow to help you in your programming.

The TextWindow is a Small Basic object. It displays text output. The


object has properties, methods and events. There are many objects in
Small Basic. They will be reviewed in Chapter 2.

Let’s run the program. Simply click the Run button on the toolbar to see:

This is the text window displaying the program output. I have resized the
window a bit. To stop the program, click the X in the upper right corner of
the window.

That’s all there is to writing a Small Basic program. Type the code in the
editor window. Click the Run button to run the code. We will learn a lot of
Small Basic code as we build the games in this course. Chapter 3 reviews
most elements of the Small Basic language.

Other useful toolbar buttons are: Open – Open a previously saved Small
Basic program Save – Save a Small Basic program Save As – Save a Small
Basic program with a different name We suggest saving each Small Basic
program in its own folder.

There are also the Cut, Copy, Paste, Undo, and Redo buttons for common
editing tasks. Learn to use these – they will save you lots of time typing
code.
Chapter Review

This completes our overview of the Small Basic environment and a brief
demonstration of how to write a Small Basic program. If you’ve used Small
Basic before, this material should be familiar. If you’ve programmed with
other languages, you should have a fairly clear understanding of what’s
going on.

After completing this chapter, you should understand:

➢ A little of the history of Small Basic.


➢ The various parts of the Small Basic integrated development
environment.
➢ The utility of “intellisense” and the Small Basic help panel.
➢ How to write code using the code editor.
➢ How to run a Small Basic program.

Before starting the game programs in Chapter 5, we need to review the


objects used to build programs (Chapter 2), the language of Small Basic
(Chapter 3), and Small Basic debugging (Chapter 4).
2. Small Basic Objects
Review and Preview In this chapter, we provide an overview of
Small Basic objects used to build the game programs. While
building the programs, you can refer back to this chapter for
information regarding objects.
Objects, Properties, Methods and Events Objects are used by the
Small Basic language to help build programs. An object can have
properties, methods and/or events.

A property describes something about the object. In Chapter 1, we had this


simple line of code: TextWindow.Title = "Hello Program"

Here TextWindow is the object, Title is the property (the information that
appears in the window title bar) and “Hello Program” is the value of the
property. So, in general, to set the Property of an Object, you use this “dot-
notation”: Object.Property = Value A method does something to an object.
Again, in Chapter 1, we had this line: TextWindow.WriteLine("This is the
first line of the program.") Here, WriteLine is the method (it writes
information in the text window) and the item in the parentheses is called the
method argument. The argument (or sometimes arguments) provides
information needed by the method to do its job. To apply a Method to an
Object, use: Object.Method(Arguments) Sometimes, the method may
compute and return a value. In this case, that Value is found using: Value =
Object.Method(Arguments) Lastly, an event is something that happens to
an object. Example events are pressing a mouse button or pressing a key on
the keyboard. To respond to an event, the event must be assigned a
subroutine (a self-contained segment of program code) that is called if the
event occurs. To assign the subroutine EventSub to the Event for Object,
use: Object.Event = EventSub In the rest of this chapter, we look at objects
we will use in the course to build our games. For each object, we review
some of the properties, methods and events (if any).
TextWindow Object

The TextWindow is an object where we can receive text input and write
text output. In the game programs written in this course, we will use the text
window to set game options. We saw the text window in the little example
in Chapter 1.

TextWindow Properties:

BackgroundColor Gets or sets the background color of the text to


be output in the text window.
CursorLeft Gets or sets the cursor's column position in the
text window.
CursorTop Gets or sets the cursor's row position in the
text window.
ForegroundColor Gets or sets the foreground color of the text to
be output in the text window.
Title Gets or sets the title for the text window.

TextWindow Methods: Clear()


Clears the text window.

Hide()
Hides the text window.

Pause()
Waits for user input before returning.

Read()
Reads a line of text from the text window. This method will not return
until the user presses Enter. Returns entered text.

ReadNumber()
Reads a number from the text window. This method will not return until
the user presses Enter. Returns entered number.

Show()
Shows the text window.

Write(data)
Writes text or number (data) to the text window. Unlike WriteLine, this
will not append a new line character, which means, anything written to
the text window after this call will be on the same line.

WriteLine(data) Writes text or number (data) to the text window. A new


line character will be appended to the output, so that the next time
something is written to the text window, it will go in a new line.

TextWindow Example: This code shows the text window, asks for an
input and writes that input back to the text window: TextWindow.Show()
TextWindow.Write("Enter a number ") A = TextWindow.ReadNumber()
TextWindow.WriteLine(A)
GraphicsWindow Object The GraphicsWindow object is the
cornerstone of our game building. In the graphics window, we can draw
lines, shapes, and text in many colors. We can receive mouse and keyboard
input from a user. The coordinate system used by the graphics window is:

The window is Width pixels wide and Height pixels high. We use two
values (coordinates) to identify a single pixel in the window. The x
(horizontal) coordinate increases from left to right, starting at 0. The y
(vertical) coordinate increases from top to bottom, also starting at 0. Points
in the region are referred to by the two coordinates enclosed in parentheses,
or (x, y).

Each game program will be developed within the graphics window. This
window has many properties, methods and events. As you build the games,
you will become familiar with the use of most of these.

GraphicsWindow Properties:
BackgroundColor Gets or sets the background color of the
graphics window.
BrushColor Gets or sets the brush color to be used to fill
shapes drawn on the graphics window.
FontBold Gets or sets whether or not the font to be used
when drawing text on the graphics window, is
bold.
FontSize Gets or sets the font size to be used when
drawing text on the graphics window.
Height Gets or sets the height of the graphics window.
LastKey Gets the last key that was pressed or released.
MouseX Gets the x-position of the mouse relative to the
graphics window.
MouseY Gets the y-position of the mouse relative to the
graphics window.
PenColor Gets or sets the color of the pen used to draw
shapes on the graphics window.
PenWidth Gets or sets the width of the pen used to draw
shapes on the graphics window.
Title Gets or sets the title for the graphics window.
Width Gets or sets the width of the graphics window.

GraphicsWindow Methods: Clear()


Clears the window.

DrawEllipse(x, y, w, h) Draws an ellipse (width w, height h) at (x, y) on


the screen using the selected pen.

DrawImage(image, x, y) Draws the specified image from memory on to


the screen at (x, y).

DrawLine(x1, y1, x2, y2) Draws a line from one point (x1, y1) to
another (x2, y2).
DrawRectangle(x, y, w, h) Draws a rectangle (width w, height h) on the
screen at (x, y) using the selected pen.

DrawResizedImage(image, x, y, w, h) Draws the specified image from


memory on to the screen at (x, y), in the specified size (width w, height
h).

DrawText(x, y, text) Draws a line of text on the screen at the specified


location (x, y).

DrawTriangle(x1, y1, x2, y2, x3, y3) Draws a triangle connecting the
three input points on the screen using the selected pen.

FillEllipse(x, y, w, h) Fills an ellipse (width w, height h) on the screen at


(x, y) using the selected brush.

FillRectangle(x, y, w, h) Fills a rectangle (width w, height h) on the


screen at (x, y) using the selected brush.

FillTriangle(x1, y1, x2, y2, x3, y3) Fills a triangle connecting the three
input points on the screen using the selected brush.

GetColorFromRGB(red, green, blue) Constructs a color give the red,


green, blue values (0-255). Returns the color.

GetRandomColor() Gets a valid random color. Returns the color.

Hide()
Hides the graphics window.

Show()
Shows the graphics window to enable interactions with it.

ShowMessage(text, title) Displays a message box (with message text


and title) to the user.
GraphicsWindow Events:

KeyDown Raises an event when a key is pressed down on the


keyboard.
KeyUp Raises an event when a key is released on the
keyboard.
MouseDown Raises an event when the mouse button is clicked
down.
MouseMove Raises an event when the mouse is moved around.
MouseUp Raises an event when the mouse button is released.

GraphicsWindow Example: This code displays a graphics window 400


pixels wide by 150 pixels high with a yellow background. It draws
“Graphics Window” in black near the center in a large font:
GraphicsWindow.Show() GraphicsWindow.Width = 400
GraphicsWindow.Height = 150
GraphicsWindow.BackgroundColor = "Yellow"
GraphicsWindow.FontSize = 36
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.DrawText(20, 40, "Graphics Window")

Many more examples of graphics methods are given in Chapter 3.


Controls Object

The Controls object allows you to use three controls in your Small Basic
programs – a Button, a TextBox and a MultiLineTextBox. In these notes,
we will only use the button control. The Button control is used to begin,
interrupt, or end a particular process.

Controls Properties:

LastClickedButton Gets the last button that was clicked on the


graphics window.

Controls Methods: AddButton(caption, x, y) Adds a button with caption


to the graphics window at (x, y). Returns the added button.

GetButtonCaption(button) Gets the current caption of the specified


button. Returns the caption.

HideControl(control) Hides an already added control.

Move(control, x, y) Moves the control with the specified name to a new


position (x, y).

Remove(control) Removes a control from the graphics window.

SetButtonCaption(button, caption) Sets the caption of the specified


button.

SetSize(control, w, h) Sets the size (width w, height h) of the control.

ShowControl(control) Shows a previously hidden control.

Controls Events:

ButtonClicked Raises an event when any button control is clicked.


Some features of the Button control:

➢ The background is gray in color.


➢ The text color is the value of GraphicsWindow.BrushColor when
the button is created.
➢ The text font assumes the values of GraphicsWindow.FontSize and
GraphicsWindow.FontBold when the button is created.

Button Control Example: This code creates a button (caption This Button,
size 100 pixels by 40 pixels) in the graphics window:
GraphicsWindow.Show() GraphicsWindow.Width = 400
GraphicsWindow.Height = 150
GraphicsWindow.BrushColor = "Black"
ThisButton = Controls.AddButton("This Button", 10, 10)
Controls.SetSize(ThisButton, 100, 40)
Program Object

The Program object (or more properly class) helps with program
execution.

Program Properties:

Directory Gets the executing program's directory.

Program Methods: Delay(milliseconds) Delays program execution by the


specified amount of milliseconds.

End()
Ends the program.
Text Object

The Text object provides helpful operations when working with strings of
text.

Text Methods: Append(text1, text2) Appends two text inputs (text1,


text2) and returns the result as another text. This operation is particularly
useful when dealing with unknown text in variables which could
accidentally be treated as numbers and get added, instead of getting
appended.

ConvertToLowerCase(text) Converts the given text to lower case.


Returns the converted text.

ConvertToUpperCase(text) Converts the given text to upper case.


Returns the converted text.

GetLength(text) Gets the length of the given text. Returns the length
(number of characters).

GetSubText(text, start, length) Gets a subtext from the given text.


Returns the text starting at start and length characters long. Returns the
subtext.

GetSubTextToEnd(text, start) Gets a subtext from the given text from a


specified position (start) to the end. Returns the subtext.

IsSubText(text, subtext) Gets whether or not a given subtext is a subset


of the larger text. Returns “true” if subtext is found in text.
Mouse Object

The Mouse object (or more properly class) helps decide if mouse is being
used.

Mouse Properties:

IsLeftButtonDown Gets whether or not the left button is pressed.


IsRightButtonDown Gets whether or not the right button is
pressed.
ImageList Object

The ImageList object (or more properly class) helps to load and store
images in variables.

ImageList Methods: ClipImage(image, x, y, w, h) Clips a portion of a


given image and returns a new image. The clipping rectangle is at (x, y) in
the image and width w, height h. Returns the clipped image.

GetHeightOfImage(image) Gets the height of the stored image. Returns


the height.

GetWidthOfImage(image) Gets the width of the stored image. Returns


the width.

LoadImage(filename) Loads an image from a file or the internet into


memory (filename can be a local file or a URL). Returns the name of the
image that was loaded.
Shapes Object

The Shapes object allows you to add, move and rotate shapes to the
graphics window. Shapes are drawn and filled with the current pen and
brush settings.

Shapes Methods: AddEllipse(w, h) Adds an ellipse shape with the


specified width w and height h. Returns the ellipse.

AddImage(image) Adds an image as a shape that can be moved,


animated or rotated. Returns the image.

AddLine(x1, y1, x2, y2) Adds a line between the specified points (x1,
y1) and (x2, y2). Returns the line.

AddRectangle(w, h) Adds a rectangle shape with the specified width w


and height h. Returns the rectangle.

AddText(text)
Adds text as a shape that can be moved, animated or rotated. Returns the
text shape.

AddTriangle(x1, y1, x2, y2, x3, y3) Adds a triangle shape represented by
the specified points. Returns the triangle.

Animate(shape, x, y, duration) Animates a shape with the specified


name to a new position (x, y). The animation lasts duration milliseconds.

GetLeft(shape) Gets the left coordinate of the specified shape. Returns


the left coordinate.

GetTop(shape)
Gets the top coordinate of the specified shape. Returns the top
coordinate.
Move(shape, x, y) Moves the shape with the specified name to a new
position (x, y).

Remove(shape)
Removes a shape from the graphics window.

Rotate(shape, angle) Rotates the shape with the specified name to the
specified angle (in degrees).

SetText(shape, text) Sets text of already added shape.

Shapes Example: This code draws a red rectangle with a blue border and
rotates it 30 degrees: GraphicsWindow.Show() GraphicsWindow.Width =
400
GraphicsWindow.Height = 150
GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 5
GraphicsWindow.BrushColor = "Red"
MyShape = Shapes.AddRectangle(70, 100) Shapes.Move(MyShape, 100,
20) Shapes.Rotate(MyShape, 30)
File Object

The File object provides methods to access, read and write information
from and to a file on disk. You provide the complete filepath to the file.

File Methods: AppendContents(file, contents) Opens the specified file


and appends the contents to the end of the file. Returns “SUCCESS” if
successful, otherwise returns “FAILED”.

InsertLine(file, line number, contents) Opens the specified file and


inserts the contents at the specified line number. This operation will not
overwrite any existing content at the specified line. Returns “SUCCESS”
if successful, otherwise returns “FAILED”.

ReadContents(file) Opens a file and reads the entire file's contents.


Returns the contents of the file.

ReadLine(file, line number) Opens the specified file and reads the
contents at the specified line number. Returns the text at the specified
line.

WriteContents(file, contents) Opens a file and writes the specified


contents into it, replacing the original contents with the new content.
Returns “SUCCESS” if successful, otherwise returns “FAILED”.

WriteLine(file, line number, contents) Opens the specified file and


write the contents at the specified line number. This operation will
overwrite any existing content at the specified line. Returns “SUCCESS”
if successful, otherwise returns “FAILED”.
Timer Object

The Timer object provides an easy way for doing something repeatedly
with a constant interval between.

Timer Properties:

Interval Gets or sets the interval (in milliseconds) specifying


how often the timer should raise the Tick event.

Timer Methods: Pause()


Pauses the timer. Tick events will not be raised.

Resume()
Resumes the timer from a paused state. Tick events will now be raised.

Timer Events:

Tick Raises an event when the timer ticks.


Sound Object

The Sound object provides operations that allow the playback of sounds.
Some sample sounds are provided along with the library.

Sound Methods: Pause(file)


Pauses playback of an audio file. If the file was not already playing, this
operation will not do anything.

Play(file)
Plays an audio file. If the file was already paused, this operation will
resume from the position where the playback was paused.

PlayAndWait(file) Plays an audio file and waits until it is finished


playing. If the file was already paused, this operation will resume from
the position where the playback was paused.

PlayBellRing() Plays the bell ring sound.

PlayBellRingAndWait() Plays the bell ring sound and waits for it to


finish.

PlayChime()
Plays the chime sound.

PlayChimeAndWait() Plays the chime sound and waits for it to finish.

PlayChimes()
Plays the chimes sound.

PlayChimesAndWait() Plays the chimes sound and waits for it to finish.

PlayClick()
Plays the click sound.
PlayClickAndWait() Plays the click sound and waits for it to finish.

Stop(file)
Stops playback of an audio file. If the file was not already playing, this
operation will not do anything.
Chapter Review

After completing this chapter, you should understand:

➢ Use of the TextWindow.


➢ Use of the GraphicsWindow.
➢ Use of other objects.
➢ How to play sounds using the Sound object.

We have completed our overview of the Small Basic objects. Use this
chapter as a reference when building the game programs. Next we look at
the language used to write program code.
3. Overview of Small Basic Programming
Review and Preview

In this chapter, we are concerned with writing code for our programs.
We will provide an overview of many of the elements of the language
used in Small Basic. This chapter is essentially a self-contained guide
to the Small Basic language. This will give us the foundation needed
to begin building some kid games.
A Brief History of BASIC

The BASIC language was developed in the early 1960's at Dartmouth


College as a device for teaching programming to “ordinary” people. There
is a reason it’s called BASIC: B (eginner's) A (All-Purpose) S (Symbolic) I
(Instruction) C (Code) When timesharing systems were introduced in the
1960’s, BASIC was the language of choice. Many of the first computer
simulation games (Star Trek, for example) were written in timeshare
BASIC.

In the mid-1970's, two college students decided that the new Altair
microcomputer needed a BASIC language interpreter. They sold their
product on cassette tape for a cost of $350. You may have heard of these
entrepreneurs: Bill Gates and Paul Allen!

Every BASIC written since then has been based on that early version.
Examples include: GW-Basic, QBasic, QuickBasic, Visual Basic. All the
toy computers of the early 80’s (anyone remember TI99/4A, Commodore
64, Timex, Atari 400?) used BASIC for programming.

Small Basic continues the tradition of BASIC programming. It uses the


simple concepts of the early BASIC language with a modern development
environment.

This chapter provides an overview of the BASIC language used in the


Small Basic environment. If you’ve ever used another programming
language (or some version of BASIC), you will see equivalent structures in
the language of Small Basic.
Variables

Variables are used by Small Basic to hold information needed by an


application. Variables must be properly named. Rules used in naming
variables:

➢ No more than 40 characters ➢ They may include letters, numbers,


and underscore (_) ➢ The first character must be a letter ➢ You
cannot use a reserved word (keywords used by Small Basic)

Use meaningful variable names that help you (or other programmers)
understand the purpose of the information stored by the variable.

Examples of acceptable variable names:

StartingTime Interest_Value Letter05


JohnsAge Number_of_Days TimeOfDay
Small Basic Data Types

Each variable is used to store information of a particular type. Small Basic


uses three types of data: numeric, string (or text) and Boolean variables.
You must always know the type of information stored in a particular
variable.

Numeric variables can store integer or decimal numbers. They can be


positive or negative.

A string variable is just that – one that stores a string (list) of various
characters. A string can be a name, a string of numbers, a sentence, a
paragraph, any characters at all. And, many times, a string will contain no
characters at all (an empty string). We will use lots of strings in Small
Basic, so it’s something you should become familiar with. Strings are
always enclosed in quotes (“). Examples of strings:

“I am a Small Basic programmer” “012345” “Title Author”

Boolean variables can have one of two different string values: “true” or
“false”. The quotes are need to indicate these are string values. Boolean
variables are helpful in making decisions.

With all the different variable types, we need to be careful not to improperly
mix types. We can only do mathematical operations on numbers (integer
and decimal types). String types must only work with other string types.
Boolean types are used for decisions.

Small Basic has no requirements (or capabilities) for declaring variables


before they are used. They are essentially declared the first time they are
used.
Arrays

Small Basic has facilities for handling arrays, which provide a way to store
a large number of variables under the same name. Each variable, called an
element, in an array must have the same data type, and they are
distinguished from each other by an array index which is enclosed in
brackets [].

Arrays are used in a manner identical to that of regular variables. For


example, the ninth element of an array named Item is: Item[9]

The index on an array variable begins at 0 and ends at the highest value
used. Hence, the Item array in the above example actually has ten
elements, ranging from Item[0] to Item[9]. This is different than other
languages. You use array variables just like any other variable - just
remember to include its name and its index. Many times, the 0 index is
ignored and we just start with item 1. But sometimes the 0th element cannot
be ignored. You will see examples of both 0-based and 1-based arrays in the
course examples.

You can have multi-dimensional arrays. A two-dimensional array element is


written as: AnotherArray[2][7]

This refers to the element in the 2nd row and 7th column of the array
AnotherArray.
Intellisense Feature

Working within the code editor window is easy. You will see that typing
code is just like using any word processor. The usual navigation and editing
features are all there.

One feature that you will become comfortable with and amazed with is
called Intellisense. As you type code, the Intellisense feature will, at times,
provide assistance in completing lines of code. For example, once you type
an object name and a dot (.), a drop-down list of possible properties and
methods will appear. When we use methods and events, suggested values
for arguments will be provided in the Small Basic help panel.

Intellisense is a very useful part of Small Basic. You should become


acquainted with its use and how to select suggested values. We tell you
about now so you won’t be surprised when little boxes start popping up as
you type code.
Small Basic Statements and Expressions

The simplest (and most common) statement in Small Basic is the


assignment statement. It consists of a variable name, followed by the
assignment operator (=), followed by some sort of expression. The
expression on the right hand side is evaluated, then the variable (or
property) on the left hand side of the assignment operator is replaced by
that value of the expression.

Examples: StartTime = Now ExplorerName = "Captain Spaulding"


TextWindow.Title = "My Program"
BitCount = ByteCount * 8
Energy = Mass * LightSpeed * LightSpeed NetWorth = Assets ‐
Liabilities The assignment statement stores information.

Comment statements begin with a single quote ('). For example: ' This is a
comment
x = 2 * y ' another way to write a comment You, as a programmer, should
decide how much to comment your code. Consider such factors as reuse,
your audience, and the legacy of your code. In our notes and examples,
we try to insert comment statements when necessary to explain some
detail.
Small Basic Arithmetic Operators

Operators modify values of variables. The simplest operators carry out


arithmetic operations. There are four arithmetic operators in Small Basic.

Addition is done using the plus (+) sign and subtraction is done using the
minus (-) sign. Simple examples are:

Operation Example Result


Addition 7+2 9
Addition 3.4 + 8.1 11.5
Subtraction 6-4 2
Subtraction 11.1 – 7.6 3.5

Multiplication is done using the asterisk (*) and division is done using the
slash (/). Simple examples are:

Operation Example Result


Multiplication 8*4 32
Multiplication 2.3 * 12.2 28.06
Division 12 / 2 6
Division 45.26 / 6.2 7.3

The mathematical operators have the following precedence indicating the


order they are evaluated without specific groupings: 1. Multiplication (*)
and division (/) 2. Addition (+) and subtraction (-) If multiplications and
divisions or additions and subtractions are in the same expression, they are
performed in left-to-right order. Parentheses around expressions are used to
force some desired precedence.
Comparison and Logical Operators

There are six comparison operators in Small Basic used to compare the
value of two expressions (the expressions must be of the same data type).
These are the basis for making decisions:

Operator Comparison
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
= Equal to
<> Not equal to

It should be obvious that the result of a comparison operation is a Boolean


value (“true” or “false”). Examples: A = 9.6, B = 8.1, A > B returns “true”
A = 14, B = 14, A < B returns “false”
A = 14, B = 14, A >= B returns “true”
A = 7, B = 11, A <= B returns “true”
A = “Small”, B=”Small”, A = B returns “true”
A = “Basic”, B = “Basic”, A <> B returns “false”

Logical operators operate on Boolean data types, providing a Boolean


result. They are also used in decision making. We will use two logical
operators

Operator Operation
And Logical And
Or Logical Or

The And operator checks to see if two different Boolean data types are both
“true”. If both are “true”, the operator returns a “true”. Otherwise, it returns
a “false” value. Examples: A = “true”, B = “true”, then A And B = “true”
A = “true”, B = “false”, then A And B = “false”
A = “false”, B = “true”, then A And B = “false”
A = “false”, B = “false”, then A And B = “false”

The Or operator checks to see if either of two Boolean data types is “true”.
If either is “true”, the operator returns a “true”. Otherwise, it returns a
“false” value. Examples: A = “true”, B = “true”, then A Or B = “true”
A = “true”, B = “false”, then A Or B = “true”
A = “false”, B = “true”, then A Or B = “true”
A = “false”, B = “false”, then A Or B = “false”

Logical operators follow arithmetic operators in precedence. Use of these


operators will become obvious as we delve further into coding.
Concatenation Operator

To concatentate two string data types (tie them together), use the + symbol,
the string concatenation operators: CurrentTime = "The current time is" +
Clock.Time SampleText = "Hook this " + "to this"
Small Basic Methods

Small Basic offers a rich assortment of built-in methods that compute or


provide various quantities. The general form of a method is: ReturnedValue
= ObjectName.MethodName(Arguments) where Arguments represents a
comma-delimited list of information needed by MethodName to perform
its computation. Once the arguments are supplied to the method it returns a
value (ReturnedValue) for use in an application.

Some methods do not return a value, but only perform a task. To use these
methods, just type: ObjectName.MethodName(Arguments)
String Methods

Small Basic offers a powerful set of methods to work with string type
variables, which are very important in Small Basic. These methods are
associated with the Text object.

To determine the number of characters in (or length of) a string variable, we


use the GetLength method. Using MyString as example: MyString =
"Small Basic is fun!"
LenString = Text.GetLength(MyString) LenString will have a value of
19. Characters in the string variable start at index 1 and end at 19.

You can extract substrings of characters. The GetSubText method is used


for this task. You specify the string, the starting position and the number of
characters to extract. This example starts at character 2 and extracts 6
characters: MyString = "Small Basic is fun!"
SubString = Text.GetSubText(MyString, 2, 6) The SubString variable is
equal to “mall B” Notice you can use this to extract from 1 to as many
characters as you wish.

Perhaps, you just want a far left portion of a string. Use the GetSubText
method with a starting position of 1. This example extracts the 3 left-most
characters from a string: MyString = "Small Basic is fun!"
LeftString = Text.GetSubText(MyString, 1, 3) The LeftString variable is
equal to “Sma”

To get the far right portion of a string, use the GetSubTextToEnd method.
Specify the character to start with and the right portion of the string is
returned. To get 6 characters at the end of our example, you would use:
MyString = "Small Basic is fun!"
RightString = Text.GetSubTextToEnd(MyString, 13) The RightString
variable is equal to “s fun!”
Many times, you want to convert letters to upper case or vice versa. Small
Basic provides two methods for this purpose: ConvertToUpperCase and
ConvertToLowerCase. The ConvertToUpperCase method will convert all
letters in a string variable to upper case, while the ConvertToLowerCase
method will convert all letters to lower case. Any non-alphabetic characters
are ignored in the conversion. And, if a letter is already in the desired case,
it is left unmodified. For our example (modified a bit): MyString = "Read
About Small Basic in 2010!”
A = Text.ConvertToUpperCase(MyString) B =
Text.ConvertToLowerCase(MyString) The first conversion using
ConvertToUpperCase will result in: A = “READ ABOUT SMALL
BASIC IN 2010!”

And the second conversion using ConvertToLowerCase will yield: B =


“read about small basic in 2010!”
Math Methods

Another set of methods we need are mathematical methods (yes,


programming involves math!) Small Basic provides a set of methods that
perform tasks such as square roots, trigonometric relationships, and
exponential functions.

Each of the Small Basic math functions comes from the Math class. All this
means is that each method name must be preceded by Math. (say Math-dot)
to work properly. The methods and the returned values are:

Math Method Value Returned


Math.Abs Returns the absolute value of a specified
number.
Math.Ceiling Gets an integer that is greater than or equal to
the specified decimal number. For example,
32.233 will return 33.
Math.Cos Returns a value containing the cosine of the
specified angle in radians.
Math.Floor Gets an integer that is less than or equal to the
specified decimal number. For example,
32.233 will return 32.
Math.GetDegrees Converts a given angle in radians to degrees.
Math.GetRadians Converts a given angle in degrees to radians.
Math.Log Gets the logarithm (base 10) value of the given
number.
Math.Max Returns the larger of two numbers.
Math.Min Returns the smaller of two numbers.
Math.NaturalLog Gets the natural logarithm value of the given
number.
Math.Pi A constant that specifies the ratio of the
circumference of a circle to its diameter
(3.14159265359…).
Math.Power Raises a number to a specified power.
Math.Remainder Divides the first number by the second and
returns the remainder.
Math.Round Returns the number nearest the specified
value.
Math.Sin Returns a value containing the sine of the
specified angle in radians.
Math.SquareRoot Returns a value specifying the square root of a
number.
Math.Tan Returns a value containing the tangent of an
angle in radians.

Examples: Math.Abs(‐5.4) returns the absolute value of –5.4 (returns 5.4)


Math.Cos(2.3) returns the cosine of an angle of 2.3 radians Math.Max(7,
10) returns the larger of the two numbers (returns 10) Math.Power(2, 4)
returns 2 raised to the fourth power (16) Math.SquareRoot(4.5) returns the
square root of 4.5
Random Numbers

We single out one math method for its importance. In writing games and
learning software, we use a random number generator to introduce
unpredictability. The Math.GetRandomNumber method is used in Small
Basic for random numbers.

Whenever you need a random whole number (integer) value, use this
method: Math.GetRandomNumber(Limit) This statement generates a
random value that is between 1 and Limit. For example, the method:
Math.GetRandomNumber(5) will generate random numbers from 1 to 5.
The possible values will be 1, 2, 3, 4 and 5.

A roll of a die can produce a number from 1 to 6. To use


GetRandomNumber to roll a die, we would write: DieNumber =
Math.GetRandomNumber(6) For a deck of cards, the random integers
would range from 1 to 52 since there are 52 cards in a standard playing
deck. Code to do this: CardNumber = Math.GetRandomNumber(52) If we
want a number between -100 and 100, we would use: YourNumber = 101
‐Math.GetRandomNumber(201) Check the examples above to make sure
you see how the random number generator produces the desired range of
integers.
Graphics Methods

All of our games will be “hosted” by the Small Basic graphics window. To
put anything in the graphics window, it must be “drawn” there using one of
the many Small Basic graphics methods. Even text has to be drawn! Let’s
take a look at these methods.

The coordinate system used by the graphics window is:

The window is Width pixels wide and Height pixels high. We use two
values (coordinates) to identify a single pixel in the window. The x
(horizontal) coordinate increases from left to right, starting at 0. The y
(vertical) coordinate increases from top to bottom, also starting at 0. Points
in the region are referred to by the two coordinates enclosed in parentheses,
or (x, y).

To draw lines and shapes, we use a pen. You can choose color and width.
Lines of code that accomplish this task are: GraphicsWindow.PenColor =
Color GraphicsWindow.PenWidth = Width where Color is the color your
pen will draw in and Width is the integer width (a value of 1 by default) of
the line (in pixels) drawn. This pen will draw a solid line. To specify a
color, you use a color name like “Red”, “White” or “Blue”. Appendix I lists
the multitude of colors available with Small Basic.

The Small Basic DrawLine method is used to connect two points with a
straight-line segment. If we wish to connect the point (x1, y1) with (x2, y2),
the statement is: GraphicsWindow.DrawLine(x1, y1, x2, y2) The line will
draw in the current pen Color and Width. Example that draws a blue line
of width 1: GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 1
GraphicsWindowGraphicsWindow.DrawLine(20, 50, 380, 280) The
Small Basic DrawRectangle method is used to draw a rectangle. To
draw a rectangle, we specify the upper left hand corner’s coordinate (x,
y) and the width and height of the rectangle. To draw such a rectangle in
the graphics window: GraphicsWindow.DrawRectangle(x, y, width,
height) The rectangle will draw with the current pen. To draw a blue
rectangle (pen width 2) with the upper left corner at (20, 50), width 150
and height 100, use this code: GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawRectangle(20, 50, 150, 100) The Small Basic
DrawEllipse method is used to draw an ellipse. To draw an ellipse, we
specify the upper left hand corner’s coordinate (x, y) and the width and
height of the ellipse. To draw such an ellipse in the graphics window:
GraphicsWindow.DrawEllipse(x, y, width, height) The ellipse will draw
with the current pen. To draw a green ellipse (pen width 3) with the upper
left corner at (20, 50), width 150 and height 100, use this code:
GraphicsWindow.PenColor = "Green"
GraphicsWindow.PenWidth = 3
GraphicsWindow.DrawEllipse(20, 50, 150, 100) A brush is like a “wide”
pen. It is used to fill areas with a color. It has a single property (Color).
To set the brush color, use: GraphicsWindow.BrushColor = Color A brush
is ‘solid’ – filling areas completely with the specified color To fill
rectangles and ellipses with the current brush color, use the FillRectangle
and FillEllipse methods. They have the same arguments as
DrawRectangle and DrawEllipse, respectively.

To add text information to the graphics window, we use the Small Basic
DrawText method – yes, text is “drawn” to the window. The DrawText
method is: GraphicsWindow.DrawText(x, y, text) In this statement, text
represents the string to print in the window and the point (x, y) is where the
string will be located. The string will draw in the graphics window using the
current brush color using the default font. Note this method uses the brush
color, not the pen color – text is truly drawn like other graphics objects.

Here’s an example using DrawText: GraphicsWindow.BrushColor = "Blue"


GraphicsWindow.DrawText(40, 100, "Isn't Small Basic fun?") This puts
the line “Isn’t Small Basic fun?” at (40, 100) in the graphics window. The
text will be blue in color. By setting the (x, y) point, you can left or right
justify the text, or center it horizontally and/or vertically by knowing the
window dimensions. The font size can be changed by setting the
FontSize property and FontBold determines if the font is bold or not.
Shapes Objects

Related to graphics methods are Shapes objects. A Shapes object is a


rectangular region we can add, move and remove within the graphics
window. Such an object makes animation (moving objects) very simple. We
can have shapes that are rectangles, ellipses and even images! Let’s look at
each.

To create a rectangular shape (MyRectangle) that is W pixels wide and H


pixels high, use the AddRectangle method: MyRectangle =
Shapes.AddRectangle(W, H) This will create a ‘bordered’ rectangle. The
current pen color and pen width establishes the rectangle’s border color,
while the current brush color establishes the fill color. By default, it will be
put in the upper left corner of the graphics window.

Analogously, to create an elliptical shape (MyEllipse) that is W pixels wide


and H pixels high, use the AddEllipse method: MyEllipse =
Shapes.AddEllipse(W, H) This will create a ‘bordered’ ellipse. The current
pen color and pen width establishes the ellipse border color, while the
current brush color establishes the fill color. By default, it will be put in the
upper left corner of the graphics window.

To create a shape with an image, we need two steps. First, we must load the
image, then create the shape. Assume you have jpg image file (a digital
photo) named MyImage.jpg. (You can use other image files types too). The
file with this image must be in the same folder as your Small Basic
program. The image is loaded using the LoadImage method of the
ImageList object: MyImage = ImageList.LoadImage(Program.Directory +
"\MyImage.jpg") Then the image shape (MyImageShape) is created using:
MyImageShape = Shapes.AddImage(MyImage) The shape will be placed in
the upper left corner of the graphics window.

Moving Shapes objects in a graphics window is easy to do. It is a simple


two step process: use some rule to determine a new position, then redraw it
in this new position using the Shapes object Move method. If you have a
shape object named MyShape and you want to move it to (NewX, NewY),
the code is: Shapes.Move(MyShape, NewX, NewY) This code will ‘erase’
MyShape at its current position, then ‘redraw’ it at the newly specified
position. Successive transfers (or moves) gives the impression of motion, or
animation.

We will see many examples of using Shapes objects in the game programs
we build. We will provide the image files for any Shapes requiring images.
Small Basic Decisions - If Statements

The concept of an If statement for making a decision is very simple. We


check to see if a particular condition is “true”. If so, we take a certain
action. If not, we do something else. If statements are also called
branching statements. Branching statements are used to cause certain
actions within a program if a certain condition is met.

The simplest branching statement is:

If (Condition) Then [process this code]


EndIf

Here, if Condition is “true”, the code bounded by the If/EndIf is executed.


If Condition is “false”, nothing happens and code execution continues after
the EndIf statement.

Example: If (Balance ‐ Check < 0) Then Trouble = "true"


GraphicsWindow.BackgroundColor = "Red"
EndIf

In this case, if Balance - Check is less than zero, two lines of information
are processed: Trouble is set to “true” and the window turns red. Notice the
indentation of the code between the If and EndIf lines. The Small Basic
Intellisense feature will automatically do this indentation. It makes
understanding (and debugging) your code much easier.

What if you want to do one thing if a condition is “true” and another if it is


“false”? Use an If/Then/Else/EndIf block: If (Condition) Then [process
this code]
Else
[process this code]
EndIf
In this block, if Condition is “true”, the code between the If and Else lines is
executed. If Condition is “false”, the code between the Else and EndIf
statements is processed.

Example: If (Balance ‐ Check < 0) Then Trouble = "true"


GraphicsWindow.BackgroundColor = "Red"
Else
Trouble = "false"
GraphicsWindow.BackgroundColor = "Black"
EndIf

Here, the same two lines are executed if you are overdrawn (Balance -
Check < 0), but if you are not overdrawn (Else), the Trouble flag is turned
off and your window is black.

Finally, we can test multiple conditions by adding the ElseIf statement: If


(Condition1) Then [process this code]
ElseIf (Condition2) Then [process this code]
ElseIf (Condition3) Then [process this code]
Else
[process this code]
EndIf

In this block, if Condition1 is “true”, the code between the If and first ElseIf
line is executed. If Condition1 is “false”, Condition2 is checked. If
Condition2 is “true”, the indicated code is executed. If Condition2 is not
true, Condition3 is checked. Each subsequent condition in the structure is
checked until a “true” condition is found, a Else statement is reached or the
EndIf is reached.

Example: If (Balance ‐ Check < 0) Then Trouble = "true"


GraphicsWindow.BackgroundColor = "Red"
ElseIf (Balance – Check = 0) Then Trouble = "false"
GraphicsWindow.BackgroundColor = "Yellow"
Else
Trouble = "false"
GraphicsWindow.BackgroundColor = "Black"
EndIf

Now, one more condition is added. If your Balance equals the Check
amount (ElseIf Balance - Check = 0), you’re still not in trouble and the
screen is yellow.

In using branching statements, make sure you consider all viable


possibilities in the If/Else/EndIf structure. Also, be aware that each If and
ElseIf in a block is tested sequentially. The first time an If test is met, the
code associated with that condition is executed and the If block is exited. If
a later condition is also “true”, it will never be considered.
Small Basic Looping

Many applications require repetition of certain code segments. For example,


you may want to roll a die (simulated die of course) until it shows a six. Or,
you might generate financial results until a certain sum of returns has been
achieved. This idea of repeating code is called iteration or looping.

In Small Basic, one way of looping is with the While loop: While
(Condition) ' Small Basic code block to repeat while Condition is true
EndWhile

In this structure, all code between While and EndWhile is repeated while
the given logical Condition is “true”.

Note a While loop structure will not execute even once if Condition is
“false” the first time through. If we do enter the loop (Condition is “true”),
it is assumed at some point Condition will become false to allow exiting.
Once this happens, code execution continues at the statement following the
EndWhile statement. This brings up a very important point about loops – if
you get in one, make sure you get out at some point. In the While loop, if
Condition is always “true”, you will loop forever – something called an
infinite loop.

Here is an example:

Counter = 1
While (Counter <= 1000) Counter = Counter + 1
EndWhile

This loop repeats as long as (While) the variable Counter is less than or
equal to 1000.

Another example:

Rolls = 0
Counter = 0
While (Counter < 10) ' Roll a simulated die
Roll = Roll + 1
If (Math.GetRandomNumber(6) = 6) Then Counter = Counter + 1
EndIf
EndWhile

This loop repeats while the Counter variable remains less than 10. The
counter variable is incremented (increased by one) each time a simulated
die rolls a 6. The Roll variable tells you how many rolls of the die were
needed to roll 10 sixes. Theoretically, it should take 60 rolls since there is a
1 in 6 chance of rolling a six.

As mentioned, if the logical condition used by a While loop is “false” the


first time the loop is encountered, the code block in the While loop will not
be executed. This may be acceptable behavior – it may not be.

We can build a loop that will always be executed at least once. To do this
we need to introduce the Small Basic Goto statement. A Goto allows you to
transfer code execution to anywhere in your code. A Goto requires a label.
A label is like a bookmark – it can be named anything you want. A label
name is always followed by a colon. An example is: MyLabel: Anytime we
want to transfer program execution to this label statement, we use a Goto:
Goto MyLabel You do not write the colon in the Goto statement.

Using these new concepts in a loop, we have what we’ll call a Goto loop:
MyLabel: ' Small Basic code block to process
If (Condition) Then Goto MyLabel EndIf

The code block repeats as long as Condition is “true”. Unlike the While
loop, this loop is always executed at least once. Somewhere in the loop,
Condition should be changed to “false” to allow exiting.

Let’s look at examples of the Goto loop. What if we want to keep adding
three to a Sum until the value exceeds 50. This loop will do it: Sum = 0
SumLoop: Sum = Sum + 3
If (Sum <= 50) Then Goto SumLoop EndIf

Or, another dice example:

Sum = 0
Roll = 0
SumLoop: ' Roll a simulated die
Die = Math.GetRandomNumber(6) Sum = Sum + Die Roll = Roll + 1
If (Sum <= 30) Then Goto SumLoop EndIf

This loop rolls a simulated die (Die) while the Sum of the rolls does not
exceed 30. It also keeps track of the number of rolls (Roll) needed to
achieve this sum.

You need to decide which of the loop structures (While, Goto) fits your
program. Recall the major difference is that a Goto loop is always executed
at least once; a While loop may never be executed.

And, make sure you can always get out of a loop. In both looping
structures, this means that, at some point, the checking logical condition
must become “false” to allow exiting the loop. When you exit a While loop,
processing continues at the next Small Basic statement after the EndWhile.
In a Goto loop, processing continues at the Small Basic statement after the
If structure checking whether the loop should repeat.

If, at some point in the code block of a loop, you decide you need to
immediately leave the loop or move to another point in the code, a Goto
statement can also do this. You just need a label statement at the appropriate
place. When the Goto statement is encountered, processing is immediately
transferred to the labeled statement.
Small Basic Counting

With While loop structures, we usually didn’t know, ahead of time, how
many times we execute a loop or iterate. If you know how many times you
need to iterate on some code, you want to use Small Basic counting.
Counting is useful for adding items to a list or perhaps summing a known
number of values to find an average.

Small Basic counting is accomplished using the For loop: For Variable =
Start To End Step Increment ' Small Basic code to execute goes here]
EndFor

In this loop, Variable is the counter (doesn’t necessarily need to be a whole


number). The first time through the loop, Variable is initialized at Start.
Each time the corresponding EndFor statement is reached, Variable is
incremented by an amount Increment. If the Step value is omitted, a
default increment value of one is used. Negative increments are also
possible. The counting repeats until Variable equals or exceeds the final
value End.

Example:

For Degrees = 0 To 360 Step 10


'convert to radians
R = Degrees * Math.PI / 180
A = Math.Sin(R) B = Math.Cos(R) C = Math.Tan(R) EndFor

In this example, we compute trigonometric functions for angles from 0 to


360 degrees in increments (steps) of 10 degrees.

Another Example:

For Countdown = 10 To 0 Step ‐1


TextWindow.WriteLine(Countdown + " Seconds") EndFor
NASA called and asked us to countdown from 10 to 0. The loop above
accomplishes the task.

And, Another Example:

Sum = 0
For I = 1 to 100
Sum = Sum + MyValues[I]
EndFor
Average = Sum / 100

This code finds the average value of 100 numbers stored in the array
MyValues. It first sums each of the values in a For loop. That sum is then
divided by the number of terms (100) to yield the average.

You may exit a For loop early using an Goto statement. This will transfer
program control to the corresponding labeled statement, usually the line
after the EndFor.
Small Basic Subroutines

In the looping discussion, we saw how code in one particular block could
be repeated until some desired condition was met. Many times in Small
Basic programs, we might have a need to repeat a certain block of code at
several different points in the program. Why would you want to do this?

Say we had a game that requires us to roll 5 dice and add up their individual
values to yield a sum. What if we needed to do this at 10 different places in
our program? We could write the code, then copy and paste it to the 10
different places. I think you can see problems already. What if you need to
change the code? You would need to change it in 10 different places. What
if you needed to put the code in another place in your program? You would
need to do another ‘copy and paste’ operation. There’s a better way. And
that way is to use a Small Basic subroutine.

A subroutine allows you to write the code to perform certain tasks just once.
Then, whenever you need to access the code in your program, you can “call
it.,” providing any information it might need to do its tasks. Subroutines are
the building blocks of a Small Basic program. Using subroutines in your
Small Basic programs can help divide a complex application into more
manageable units of code. Just think of a subroutine as a code block you
can access from anywhere in a Small Basic program. When you call the
subroutine, program control goes to that subroutine, performs the assigned
tasks and returns to the calling program. It’s that easy.

Subroutines are also an important part of object events. When an event


occurs, program control transfers to the subroutine assigned to that event.

Let’s see how to create and call a subroutine. Subroutines go at the end of
your ‘main’ program code. A subroutine named MySubroutine would have
the form (starts with a Sub keyword and ends with EndSub): Sub
MySubroutine ' Code to be executed in the subroutine EndSub
You execute, or call, this subroutine using: MySubroutine() The parentheses
are needed to tell the computer you are executing a subroutine. When the
subroutine is called, the corresponding code is executed until the EndSub
line is reached. At this point, program execution returns to the ‘main’ code
after the line calling the subroutine.

A subroutine can access and use any variable you use in your program.
Likewise, your program can use any variables defined in your subroutines.
In computer talk, we say the variables in a Small Basic program have
global scope.

Let’s try to make this clearer by looking at a subroutine example. We’ll do


the dice example of rolling five dice and computing their sum. The
subroutine that accomplishes this task is: Sub RollDice Die1 =
Math.GetRandomNumber(6) Die2 = Math.GetRandomNumber(6) Die3 =
Math.GetRandomNumber(6) Die4 = Math.GetRandomNumber(6) Die5 =
Math.GetRandomNumber(6) SumDice = Die1 + Die2 + Die3 + Die4 +
Die5
EndSub

This subroutine is named RollDice and the variable SumDice has the
resulting sum.

Using this subroutine, any time you need the sum of five dice in your
program, you would use: RollDice() A = SumDice After this code is
executed, the variable A will have sum of five dice.

As you progress in your Small Basic programming education, you will


become more comfortable with using subroutines and see how useful they
are. In the remainder of this course, we will use subroutines for all of the
code. Study each example to help learn how to build and use subroutines.
Chapter Review

After completing this chapter, you should understand:

➢ How to properly use variables.


➢ Small Basic statements.
➢ The assignment operator, mathematics operators, comparison and
logic operators and concatenation operators.
➢ The wide variety of built-in Small Basic methods, especially string
methods and mathematics methods.
➢ How to use graphics methods to draw in the graphics window.
➢ The If/Then/ElseIf/Else/EndIf structure used for branching and
decisions.
➢ How the While loop and Goto loop work.
➢ How the For loop is used for counting.
➢ The importance of subroutines in Small Basic programs.

We now have the foundation needed to write code for our programs. We
will begin our first program in Chapter 5, once we have a brief discussion
of debugging Small Basic programs (Chapter 4).
4. Debugging a Small Basic Program
Review and Preview As you begin building projects using
Programming Games With Microsoft Small Basic, you will
undoubtedly encounter errors in your code. In this chapter, we look
at handling errors in projects. After this, we begin building projects
(at last).
Debugging a Small Basic Program No matter how well you plan your
program and no matter how careful you are in implementing your ideas in
Small Basic code, you will make mistakes. Errors, or what computer
programmers call bugs, do creep into your program. You may have already
encountered a few in the programs we’ve built so far. Perhaps you spelled a
keyword wrong, forgot a punctuation mark or misspelled a variable name.
These are all examples of program bugs. You, as a programmer, need to
have a strategy for finding and eliminating those bugs. The process of
eliminating bugs in a program is called debugging. Unfortunately, there are
not a lot of hard, fast rules for finding bugs in a program. Each programmer
has his or her own way of attacking bugs. You will develop your ways. We
can come up with some general strategies, though, and that’s what we’ll
give you here.

Program errors, or bugs, can be divided into three types:

● Syntax errors ● Run-time errors ● Logic errors

Syntax errors occur when you make an error typing a line of Small Basic
code. Something is misspelled or something is left out that needs to be
there. Your program won’t run if there are any syntax errors. Run-time
errors occur when you try to run your program. It will stop abruptly
because something has happened beyond its control. Logic errors are the
toughest to find. Your program will run okay, but the results it gives are not
what you expected. Let’s examine each error type and address possible
debugging methods.
Syntax Errors Syntax errors are the easiest to identify and eliminate. The
Small Basic development environment is a big help in finding syntax errors.
Syntax errors will occur as you’re writing Small Basic code.

Start Small Basic. We’ll type in a few snippets of code to see how different
bugs are identified. Let’s look at some typical errors. In the editor, type
these two lines of code: MyNumber = 7
TextWindow.WriteLine(MyNmber) We’ve misspelled the assigned
variable name (MyNumber) in the WriteLine statement.

Try running this and below the editor you will see the message:

The 2,22 implies there is an error in Line 2, Column 22. It tells you it
does not recognize the variable MyNmber and asks if you misspelled it.
We did. Small Basic is pretty smart!

Correct that error, but misspell WriteLine as WriteLne: MyNumber = 7


TextWindow.WriteLne(MyNumber) Try running and Small Basic will

tell you the problem:

Correct your error. But, change the first line as shown (leave out the
assignment operator): MyNumber 7
TextWindow.WriteLine(MyNumber) Try running and you’ll get this error

message:

You are being told this (line 1 again) is not a recognized statement and the
problem is somewhere around Column 11. You should immediately see the
problem and be able to fix it. Fix the error.
Let’s try one other example. Change the second line by adding an additional
parenthesis at the end of the WriteLine method: MyNumber = 7
TextWindow.WriteLine(MyNumber)) Try running and you receive this

message:

The problem is clear – you have one too many right parentheses.

So when you try to run with syntax errors, the Small Basic environment
will kindly point out your errors to you so you can fix them. Note that
syntax errors usually result because of incorrect typing, either misspellings,
additions or omissions - another great reason to improve your typing skills,
if they need it.
Run-Time Errors Once you have written your code and eliminated all
identified syntax errors, obtaining a successful compilation, you try to run
your program. If the program runs, great! But, many times, your program
may stop and tell you it found an error - this is a run-time error. You need to
figure out why it stopped and fix the problem. At this writing, the Small
Basic environment does not give you much useful information when a run-
time error occurs. Many times, the program will just stop.

Let’s look at a couple of examples. Type these lines in the editor:


MyNumber = 7
MyOtherNumber = 0
TextWindow.WriteLine(MyNumber / MyOtherNumber) Yes, I know
we’ll get a divide by zero (a classic run-time error), but that’s the point
here – to illustrate potential errors. The program should not run, giving
you some indication you are dividing by zero. If you run the program, it
runs without error, printing a zero as the division result:

This error needs to be corrected by Microsoft in future Small Basic


versions.

Another common run-time error occurs when using one of Small Basic’s
built-in functions. Errors result if you use the wrong type or value as one of
the arguments. Try these two lines of code: MyNumber = ‐7
TextWindow.WriteLine(Math.SquareRoot(MyNumber)) We attempt to
take the square root of a negative number (not allowed). When we run the
program, we get some indication that something is wrong, but it is not
very explicit:

Click OK and the program just stops:

We’ve seen just a couple of possible run-time errors. There are others and
you’ll see them as you start building programs. And, unfortunately, the
current Small Basic program is not very helpful in pointing out where errors
are. Hopefully, this situation will change with future versions. One last
thing about run-time errors. Small Basic will not find all errors at once. It
will stop at the first run-time error it encounters. After you fix that error,
there may be more. You have to fix run-time errors one at a time.
Logic Errors Logic errors are the most difficult to find and eliminate.
These are errors that don’t keep your program from running, but cause
incorrect or unexpected results. The only thing you can do at this point, if
you suspect logic errors exist, is to dive into your program and make sure
everything is coded exactly as you want it. Finding logic errors is a time-
consuming art, not a science. There are no general rules for finding logic
errors. Each programmer has his or her own particular way of searching for
logic errors.

With the example we have been using, a logic error would be setting a
variable to an incorrect value. Or, perhaps you add two numbers together
when you should have subtracted. Logic errors are mistakes you have
inadvertently introduced into your Small Basic code. And, unfortunately,
these errors are not pointed out to you. Hence, eliminating logic errors is
not always easy.

Advanced programming languages use something called a debugger that


helps in the identification of logic errors. Using a debugger lets you
examine variable values, stop your code wherever and whenever you want,
and run your program line-by-line. Small Basic does not offer a debugger.
So, for now, you need to learn to eliminate logic errors by paying close
attention to your code. And, the best approach is to be so careful that you
don’t have any logic errors to worry about.
Chapter Review After completing this chapter, you should understand:
➢ The different types of errors.
➢ Ways to track errors.

We can now start building some projects.


5. Safecracker Program
Review and Preview

We’ve completed our review of the Small Basic development


environment, and the objects and language used to program using
Small Basic. We can finally start building some kid games. For each
program built, we provide step-by-step instructions in designing the
game graphic windows and detailed explanations of the code behind
the programs.

The first program we build is a Safecracker that asks you to guess a secret
combination of numbers using clues from the computer.
Safecracker Program Preview

In this chapter, we will build a Safecracker game. A bank safe is locked


and can only be opened if you enter the proper combination. The
combination can be 2 to 4 non-repeating digits (digits range from 1 to 9).
After each guess, you are told how many digits are correct and how many
are in the correct location. Based on this information, you make another
guess. You continue guessing until you get the correct combination or stop
the game.

The finished program is saved as Safecracker in the


KidGamesSB\KidGamesSB Programs\Safecracker folder. Start Small
Basic and open the finished program. Run the program (click the Run
toolbar button or press <F5>). The game will appear in its ‘stopped’ state.
The bank safe is disabled – no combination can be entered. At this point,
you can click the Start Game button to start the game, click Change
Options to change program options (program options are displayed in the
title bar area) or click Exit to exit the program.
Click Change Options to change options. A text window will appear:

The only option you can change is the number of digits in the combination.
I selected 3, then pressed Enter. The graphics window reappears with the
game still in the ‘stopped’ state:

Notice the title bar area now reflects 3 digits in the combination and that
number of digits is shown in the bank safe.
Click Start Game to start playing. Two of the buttons disappear and a
Results area appears on the right of the window. We call this the ‘playing’

state:

In this state, you make a guess at the three digit combination using the
number keys on the keyboard. After each guess, the results of your guess
are displayed in the Results area. You keep guessing until correct or until
you click Stop Game.
Enter a guess; I entered 123:

As a guess is entered, notice several things. Once a key is pressed, the


corresponding digit appears in the proper location. Once three buttons are
pressed (numbers cannot repeat), the results are shown. You are shown your
guess and two numbers separated by a colon (:). The number to the left of
the colon tells you how many digits in your guess were correct and the
number on the right tells you how many were in the correct position. If
incorrect, you will hear an ‘uh-oh’ sound. Obviously, my guess was not
very good!

When I try 456, I see:


Much better. Now, I know that the combination has either a 4 and a 5, a 4
and a 6, or a 5 and a 6. I also know none of the digits are in their proper
position.
What if I try 745 (I assumed the 4 and 5 should stay and shifted them over)

Since only 1 digit is now correct, I know the 6 is definitely in the


combination. I think you’re starting to see how the game works.
I continued playing until finally, after entering 648:

The correct combination was entered! A little celebratory sound is heard


and a message is shown. The game returns to its stopped state to allow
another game, change options or to exit the program.

Continue playing the game to understand its operation. Click Exit when
you’re done to stop the game. Look over the code in the editor if you like.

You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program. This is the approach we will take on
all programs in these notes.

We address window design. This involves deciding just what we need to


display in the graphics window to play the game. And, we address code
design. We discuss how to form the secret combination, how to gather user
input and how to check an entered combination.
Game Window Design

Since this is our first program, let’s look briefly at the idea of game window
design. This is a first step in building a Small Basic game program (or any
program) where you decide what you want to display to the user in the
graphics window. In this window design phase, you need to know what
inputs you need from the user and how you want to show them outputs.

Make initial sketches of where you want certain game elements to appear.
Always have an area to provide messages to the user – messages like how
to start/stop the game and messages on how they are progressing in the
game. Use button controls to perform specific tasks (start, stop, change
options) in your program. In your design, since you are using the graphics
window, make sure you incorporate graphics elements of colors and shapes.
Make the window pleasant to look at and easy to understand. Finalize your
sketch on graph paper to help with positioning parts of the final layout.
Make notes for dimensions and locations of different components.

Translate your sketch to actual Small Basic code to draw the window
elements. With Small Basic, you can make quick changes and see the
results of these changes immediately. The window design process is
iterative – meaning you will always be tweaking certain items until you are
satisfied with your window design. For the games in these notes, we present
our ideas for windows. Feel free to modify them in anyway you choose.
Safecracker Window Design

Here is the sketch for the window layout of the Safecracker game:

We draw a safe on the left side of the window using lines and rectangles.
The combination digits will be displayed in bordered rectangles. A little
‘money bag’ graphic is added. The right side of the window is a blank area
where we will provide information to the user at the appropriate times.
Three button controls will be used: one to start and stop the game, one to
change options and one to exit the program.

We now begin writing code for the Safecracker game program. We will
write the code in several steps. As a first step, we will write the code that
draws the game window and establishes the ‘stopped’ state. We write code
to set game options in a text window. Then, we look at how to go to
‘playing’ state following clicking of the Start Game button. During the
code development process, recognize you may modify a particular
procedure several times before arriving at the finished product.
Before starting, make sure you have established a folder on your computer
for building Small Basic programs. Always save your programs in this
folder. Do not save them in the folder used in these notes
(KidGamesSB\KidGamesSB Programs). Leave this folder intact so you
can always reference the finished programs, if needed.

Start a new program in Small Basic. Once started, we suggest you


immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Draw Safe

We see in the sketch that the safe used in the Safecracker game is made up
of rectangles, lines, a heading (BANK) and a little money bag graphic. In
the KidGamesSB\KidGamesSB Programs\Safecracker folder is a file
money.jpg. This is the graphic we will display. It is loaded by the program.
Copy this file to your program’s folder.

Now, add this code to the editor.

'Safecracker
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 650
GraphicsWindow.Height = 400
'Draw bank safe
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(0, 0, 310, 400)
GraphicsWindow.BrushColor = "LightGray"
GraphicsWindow.FillRectangle(25, 25, 260, 350)
GraphicsWindow.BrushColor = "Gray"
GraphicsWindow.FillRectangle(50, 50, 210, 300)
GraphicsWindow.PenWidth = 2
GraphicsWindow.PenColor = "Black"
GraphicsWindow.DrawRectangle(25, 25, 260, 350)
GraphicsWindow.DrawRectangle(50, 50, 210, 300)
GraphicsWindow.DrawLine(25, 25, 50, 50)
GraphicsWindow.DrawLine(285, 25, 260, 50)
GraphicsWindow.DrawLine(285, 375, 260, 350)
GraphicsWindow.DrawLine(25, 375, 50, 350)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 48
GraphicsWindow.DrawText(95, 50, "BANK") MoneyImage =
ImageList.LoadImage(Program.Directory + "\money.jpg")
GraphicsWindow.DrawImage(MoneyImage, 80, 200) EndSub

This code is just a translation of our window sketch into actual code. The
first line of code calls a subroutine InitializeProgram where we will put all
code needed to set up the program for use. All remaining code here goes in
that subroutine. Notice the graphics file (money.jpg) is loaded from the
Program.Directory folder – this is your program’s folder. That’s why we
asked you to copy the file to this particular folder. Notice the line loading
the file is displayed on two lines in these notes due to margin restrictions.
Make sure this is typed on one line in the code editor. Look for similar
occurrences throughout the notes for this course.

Save and Run (click Run in the toolbar) the program. The safe will appear:

If the money bag does not show up, double-check you copied the file into
the same folder holding your program code.
Window Design – Display Combination Digits The combination
entered by the user will be displayed in bordered rectangles on the safe. To
draw these rectangles, we need to know how many digits will be entered.
The variable NumberDigits will be used for this purpose – we give it a
default (beginning value) of 2. This can be changed by the user later when
setting program options.

Add this code at the end of the current code in InitializeProgram: 'Default
Options
NumberDigits = 2
GraphicsWindow.Title = "Safecracker ‐ " + NumberDigits + " Digits in
Combination"
ClearDigits() A value is set for NumberDigits and used in the graphics
window Title to reflect that value.

The subroutine ClearDigits draws the blank bordered digits. We use a


subroutine because it will be used often in the game when the digits need to
be cleared. Add this subroutine to your code: Sub ClearDigits For I = 1 To
NumberDigits GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(60 + (I ‐ 1) * 50, 120, 40, 60)
GraphicsWindow.PenWidth = 1
GraphicsWindow.PenColor = "Black"
GraphicsWindow.DrawRectangle(60 + (I ‐ 1) * 50, 120, 40, 60)
EndFor
EndSub

Save and Run the program. You should now see two blank boxes ready for
digits in the safe. Also, notice the information shown in the title bar area:
Window Design – Results Area

The final item we need in the window is the results area. It is simply a blank
area with a header (Results:) and three button controls used to start/stop the
game, change options and exit the program.

Add this code at the end of InitializeProgram: 'results area


GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontSize = 20
GraphicsWindow.DrawText(330, 10, "Results:") 'define buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
StartStopButton = Controls.AddButton("Start Game", 320, 360)
OptionsButton = Controls.AddButton("Change Options", 420, 360)
ExitButton = Controls.AddButton("Exit", 550, 360) Save and Run the
program. The finished window is displayed:
We establish three buttons (StartStopButton, OptionsButton,
ExitButton).
Code Design – Initializing Stopped State At this point, our game is
in what we call ‘stopped’ state, waiting for the user to make a selection. We
will use a variable (GameStatus) to let us know what state the game is in.
It will help us decide what steps to take when certain actions occur. Add this
single line at the end of InitializeProgram: GameStatus = "Stopped"

We have three choices at this point – either click Start Game to start, click
Change Options to change options, or click Exit to exit the program. We
will write code for each of these options in reverse order.

First, we need to be able to detect button clicks so next add this line at the
end of InitializeProgram: Controls.ButtonClicked = ButtonClickedSub
With this, each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.

The code for exiting is simple. It is placed in the ButtonClickedSub


subroutine: Sub ButtonClickedSub B = Controls.LastClickedButton If
(GameStatus = "Stopped") Then If (B = ExitButton) Then Program.End()
EndIf
EndIf
EndSub

This simply says whenever the ExitButton button is clicked, the program
ends. Note, we only want to detect clicking Exit when the game is stopped,
hence it is place within an If structure. Run the program. Click Exit to
make sure the game stops.

If the user clicks Change Options, we want to provide the ability to change
program options (NumberDigits in this game). In all games in these notes,
we will use the Small Basic text window to establish game options. Add the
shaded code to the ButtonClickedSub subroutine: Sub ButtonClickedSub
B = Controls.LastClickedButton If (GameStatus = "Stopped") Then If (B =
ExitButton) Then Program.End()
ElseIf (B = OptionsButton) Then SetOptions()
EndIf
EndIf
EndSub

The options are set in the SetOptions subroutine – add this routine: Sub
SetOptions GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title
= "Safecracker"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("SAFECRACKER OPTIONS")
TextWindow.WriteLine("") GetInput: TextWindow.CursorLeft = 3
TextWindow.WriteLine("The safe combination can have 2, 3, or 4
digits.") TextWindow.CursorLeft = 3
TextWindow.Write("How many digits do you want?") NumberDigits
= TextWindow.ReadNumber() If (NumberDigits < 2 Or
NumberDigits > 4) Then Goto GetInput EndIf
GraphicsWindow.Title = "Safecracker ‐ " + NumberDigits + " Digits
in Combination"
ClearDigits() TextWindow.Hide() GraphicsWindow.Show() EndSub

This routine hides the graphics window, displays a text window and asks
the user how many digits. Once entered, the program returns to the game in
‘stopped’ state, displaying the entered number of digits.

Save and Run the program. Click the Change Options button to change
options:
Make a choice and press Enter. The Safecracker game window will again
appear.

Here’s what I got when I chose 4 digits:

Notice, as expected, there are now 4 digits in the safe.


The code for clicking the Start Game button is much more complicated.
We will build it in several steps. First, we look at switching the game from
stopped to playing state.
Code Design – Stopped to Playing State When the user presses the S
key in ‘stopped’ state, several things must happen to switch the
Safecracker game to ‘playing’ state:

➢ Change GameStatus to “Playing”


➢ Change the caption of StartStopButton to Stop Game.
➢ Hide OptionsButton and ExitButton.
➢ Clear any previous results.
➢ Allow user to input combination.
➢ Check to see if input combination matches secret combination –
provide results.

Right now, we will just implement the first step (setting up the results area).
The other steps, those establishing the secret combination and accepting and
checking user input, will be addressed separately.

Add the shaded code to the ButtonClickedSub subroutine: Sub


ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =
"Stopped") Then If (B = ExitButton) Then Program.End() ElseIf (B =
OptionsButton) Then SetOptions()
ElseIf (B = StartStopButton) Then StartGame()
EndIf
EndIf
EndSub

Clicking Start Game calls the StartGame subroutine: Sub StartGame


GameStatus = "Playing"
'clear results area and change buttons GraphicsWindow.BrushColor
= "White"
GraphicsWindow.FillRectangle(320, 30, 330, 370)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton)
Controls.HideControl(ExitButton) ClearDigits() EndSub

Save and Run the program. Change options if you want. Click Start Game
and the game should switch to ‘playing’ state (assumes 2 digits in
combination):

Make sure the number of boxes displayed in the bank area match the
number of digits selected. Notice the single button –Stop Game. Also,
notice clicking this button does nothing. Let’s fix that. Stop the program by
clicking the X in the upper right corner of the window.
Code Design – Playing to Stopped State When the user clicks the
Stop Game button in ‘playing’ state, we want to switch the Safecracker
game back to ‘stopped’ state. The steps are:

➢ Change GameStatus to “Stopped”


➢ Change the caption of StartStopButton to Start Game.
➢ Show OptionsButton and ExitButton.

The button now marked Stop Game is the StartStopButton control. We


have already added some code to its ButtonClick event. It is common
practice to have one button control have multiple purposes - we just need to
have some way to distinguish which “mode” the button is in when it is
clicked. In this program, we use the value of GameStatus. The code that
does this is (modifications to the current ButtonClickSub subroutine code
are shaded): Sub ButtonClickedSub B = Controls.LastClickedButton If
(GameStatus = "Stopped") Then If (B = ExitButton) Then Program.End()
ElseIf (B = OptionsButton) Then SetOptions() ElseIf (B =
StartStopButton) Then StartGame() EndIf
ElseIf (GameStatus = "Playing") Then If (B = StartStopButton)
Then 'stop program
StopGame() EndIf
EndIf
EndSub

We now look for button clicks while playing the game. Clicking Stop
Game calls the StopGame subroutine: Sub StopGame 'restore buttons
GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton) EndSub
Later, we will add code to this routine to report game results.

Save and Run the program. You should be able to now move from
‘stopped’ to ‘playing’ state and back. Make sure you can display 2, 3 or 4
digits in the combination (changing options). Try the Exit button. We can
now look at the three missing steps in the program: generating a secret
combination and accepting and checking user input.
Code Design – Generating Secret Combination A critical step in
the Safecracker program is to generate the secret combination the game
player is trying to guess. Using the options selected, we know the
combination can be from 2 to 4 digits. We have also specified none of the
digits can repeat.

Since repeated digits are not allowed, for each digit in the combination, we
generate a random number from 1 to 9, but only add it to the combination if
it has not been used before. The code snippet that accomplishes this for our
game is: 'Get combination
SecretCombo = ""
For I = 1 To NumberDigits 'select unique digit
UniqueDigit = "false"
While (UniqueDigit = "false") J = Math.GetRandomNumber(9)
UniqueDigit = "true"
If I <> 1 Then For K = 1 To I ‐ 1
If (Text.GetSubText(SecretCombo, K, 1) = J) Then
UniqueDigit = "false"
EndIf
EndFor
EndIf
EndWhile
SecretCombo = Text.Append(SecretCombo, J) EndFor

We’ll step you through this code to see what’s going on. A string variable
(SecretCombo) is used to store the combination. It is initially blank. One
digit at a time (a total of NumberDigits) is added to SecretCombo using
string concatenation.

A random digit J (from 1 to 9) is generated. We then look at the current


digits in the code to see if this newly generated digit is unique. If so, it is
added to SecretCombo. If not unique, a new random digit is generated. All
of this logic is implemented in a While loop. Study how the GetSubText
method is used to look at the individual digits in SecretCombo. Let’s try
this new code.

Add the given snippet to the StartGame subroutine as shown in the shaded
code below: Sub StartGame GameStatus = "Playing"
'clear results area and change buttons GraphicsWindow.BrushColor
= "White"
GraphicsWindow.FillRectangle(320, 30, 330, 370)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton)
Controls.HideControl(ExitButton) ClearDigits()
'Get combination
SecretCombo = ""
For I = 1 To NumberDigits 'select unique digit
UniqueDigit = "false"
While (UniqueDigit = "false") J = Math.GetRandomNumber(9)
UniqueDigit = "true"
If I <> 1 Then For K = 1 To I ‐ 1
If (Text.GetSubText(SecretCombo, K, 1) = J) Then
UniqueDigit = "false"
EndIf
EndFor
EndIf
EndWhile
SecretCombo = Text.Append(SecretCombo, J) EndFor
EndSub

We can now generate a secret combination, but have no way of seeing what
it is. Let’s change that. Many times while developing a program, you want
to check results before the program is complete. This means adding
temporary code just for debugging purposes. Place this line after the
EndFor line in the code generating the combination:
GraphicsWindow.ShowMessage("Combo: " + SecretCombo, "") This will
write the generated combination in a message box allowing you to see if the
combination meets the requirements (proper number of digits and proper
repeating/non-repeating of digits.

Save and Run the program. Click Start Game to start the game. View the
message box to see the generated combination. Make sure it meets the
selected options requirement. Click Stop Game to stop game. Repeat this
process for various combinations (and different numbers of digits) to make
sure the combination is being generated correctly. When done, delete the
debug line from the code.

We’re now ready to accept the player’s guess at the secret combination.
Code Design – Accepting Player Input Once the secret combination
has been generated, the next step is to allow the user to enter his or her
guess at the combination. This is done using the number keys on the
keyboard (or numeric keypad). The steps followed are:

➢ Press a key to enter a digit.


➢ If this is the first number in the combination, clear out any previous
guess.
➢ Determine which key was pressed.
➢ Make sure the key has not been pressed yet.
➢ Add the new number to the user’s input combination.
➢ Display the number in the proper location on the safe.
➢ If all digits have been entered, compare the user’s input to the actual
combination, else repeat these steps.

First add these lines at the end of the StartGame subroutine:


EnteredCombo = ""
DigitsEntered = 0
Tries = 0
ComboX = 330
ComboY = 40

These variables are used to store the combination entered by the user
(EnteredCombo), the number of digits entered (DigitsEntered), the
number of tries to guess the combination (Tries), and the location to print
the results of a guess (ComboX, ComboY).

And, we need to be able to detect key presses so add this line at the end of
the InitializeProgram subroutine: GraphicsWindow.KeyDown =
KeyDownSub With this, each time a KeyDown event occurs, the
subroutine named KeyDownSub is called.
Now, add this code (there is a lot of it) to the KeyDownSub subroutine:
Sub KeyDownSub K = GraphicsWindow.LastKey If (GameStatus =
"Playing") Then N = 0
If (K = "D1" Or K = "NumPad1") Then N = 1
ElseIf (K = "D2" Or K = "NumPad2") Then N = 2
ElseIf (K = "D3" Or K = "NumPad3") Then N = 3
ElseIf (K = "D4" Or K = "NumPad4") Then N = 4
ElseIf (K = "D5" Or K = "NumPad5") Then N = 5
ElseIf (K = "D6" Or K = "NumPad6") Then N = 6
ElseIf (K = "D7" Or K = "NumPad7") Then N = 7
ElseIf (K = "D8" Or K = "NumPad8") Then N = 8
ElseIf (K = "D9" Or K = "NumPad9") Then N = 9
EndIf
If (N = 0) Then Goto LeaveSub EndIf
'if first number in combo, clear out digits boxes If DigitsEntered
= 0 Then ClearDigits() EndIf
'for second digit on, make sure not in code already If
(NumberDigits >= 1) Then For I = 1 To NumberDigits If (N =
Text.GetSubText(EnteredCombo, I, 1)) Then Goto LeaveSub
EndIf
EndFor
EndIf
EnteredCombo = Text.Append(EnteredCombo, N) DigitsEntered
= DigitsEntered + 1
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 48
GraphicsWindow.DrawText(67 + (DigitsEntered ‐ 1) * 50, 120,
N) 'if all digits entered, check combo If (DigitsEntered =
NumberDigits) Then GraphicsWindow.ShowMessage("Combo: "
+ EnteredCombo, "") EndIf
EndIf
LeaveSub: EndSub
Notice we allow the user to press a number on the keyboard or on the
numeric keypad. The pressed digit is the variable N. We have temporarily
display the entered combination in a message box for debug purposes.

Save and Run the program. Make sure the entered combination looks
correct (has the proper number of digits, in the correct order and following
repeatability rules). Let’s complete the game by comparing the player’s
input to the actual combination and displaying the results.
Code Design – Checking Player Input We now have the capability to
generate a secret combination and obtain the player’s guess at that
combination. We need the code that compares the two string variables and
displays the results. If it’s a match, great! If not, we tell the player how
many digits are correct and how many are in the correct position. This is
some of the trickier code.

Once the user has complete their input, we follow these steps:

➢ Display the user’s guess (EnteredCombo) in the results area.


➢ If user’s guess (EnteredCombo) equals the actual combination
(SecretCombo), return the game to stopped state and let the user
know they guessed the combination.
➢ If incorrect guess, determine number of correct digits and number in
correct positions. Display this information in the results area.
➢ Clear user’s guess to allow another try.

All of the code to perform these steps is placed in the KeyDownSub


subroutine.

We have a specific format for the displaying the results to the user. For each
guess, we display three pieces of information: EnteredCode NumberRight
: PositionCorrect EnteredCode is what the user entered. NumberRight is
the number of correct digits in the guess, PositionCorrect is the number of
digits in the correct position. There is room for three sets of results on each
line in the results area.

Place the shaded code in the KeyDownSub subroutine to implement these


steps (we deleted the line displaying the entered code in the message box):
Sub KeyDownSub K = GraphicsWindow.LastKey If (GameStatus =
"Playing") Then N = 0
If (K = "D1" Or K = "NumPad1") Then N = 1
ElseIf (K = "D2" Or K = "NumPad2") Then N = 2
ElseIf (K = "D3" Or K = "NumPad3") Then N = 3
ElseIf (K = "D4" Or K = "NumPad4") Then N = 4
ElseIf (K = "D5" Or K = "NumPad5") Then N = 5
ElseIf (K = "D6" Or K = "NumPad6") Then N = 6
ElseIf (K = "D7" Or K = "NumPad7") Then N = 7
ElseIf (K = "D8" Or K = "NumPad8") Then N = 8
ElseIf (K = "D9" Or K = "NumPad9") Then N = 9
EndIf
If (N = 0) Then Goto LeaveSub EndIf
'if first number in combo, clear out digits boxes If DigitsEntered
= 0 Then ClearDigits() EndIf
'for second digit on, make sure not in code already If
(NumberDigits >= 1) Then For I = 1 To NumberDigits If (N =
Text.GetSubText(EnteredCombo, I, 1)) Then Goto LeaveSub
EndIf
EndFor
EndIf
EnteredCombo = Text.Append(EnteredCombo, N) DigitsEntered
= DigitsEntered + 1
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 48
GraphicsWindow.DrawText(67 + (DigitsEntered ‐ 1) * 50, 120,
N) 'if all digits entered, check combo If (DigitsEntered =
NumberDigits) Then
Tries = Tries + 1
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.FontSize = 16
GraphicsWindow.DrawText(ComboX, ComboY,
EnteredCombo) If (EnteredCombo = SecretCombo) Then
StopGame() Else
NumberRight = 0
For I = 1 To NumberDigits N =
Text.GetSubText(EnteredCombo, I, 1) For J = 1 To
NumberDigits If (N = Text.GetSubText(SecretCombo, J,
1)) Then NumberRight = NumberRight + 1
EndIf
EndFor
EndFor
'how many in correct position PositionRight = 0
For I = 1 To NumberDigits If
(Text.GetSubText(SecretCombo, I, 1) =
Text.GetSubText(EnteredCombo, I, 1)) Then
PositionRight = PositionRight + 1
EndIf
EndFor
GraphicsWindow.DrawText(ComboX + 50, ComboY,
NumberRight + ":" + PositionRight) 'clear combo to try
again
EnteredCombo = ""
DigitsEntered = 0
ComboX = ComboX + 100
If (ComboX > 530) Then ComboX = 330
ComboY = ComboY + 20
EndIf
EndIf
EndIf
EndIf
LeaveSub: EndSub

You should be able to follow the above code. It first counts the number of
correct digits in the user’s input. The code to see if digits are in correct
position just compares each digit (using the GetSubText method) in
EnteredCombo and SecretCombo. All the results are displayed in the
results area. Check how we use ComboX and ComboY to establish the
location for each set of results.
If the entered combination is correct, we just go to the StopGame
subroutine. We need to modify the subroutine a bit to distinguish whether
we called it because the correct combination was guessed or because S was
pressed to stop the game. Add these shaded lines to that routine: Sub
StopGame 'restore buttons
GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton)
'write message
ComboX = 330
ComboY = ComboY + 20
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontSize = 16
If (EnteredCombo = SecretCombo) Then
GraphicsWindow.DrawText(ComboX, ComboY, "That's it!! It took
you " + Tries + " tries.") Else
GraphicsWindow.DrawText(ComboX, ComboY, "Game Stopped.
Combination: " + SecretCombo) EndIf
EndSub

Here, if the combination is correct, you are told so. Else, if the game was
stopped by clicking Stop Game, we display the combination to the user.

Save and Run the program. The game is now fully functional. Try playing
it a few times to make sure things are working okay. It still needs just one
more thing.
Code Design – Adding Sounds

The text feedback of the Safecracker game is a bit boring. Let’s snazz it up
a bit by adding sounds. In the KidGamesSB\KidGamesSB
Programs\Safecracker folder are two wav files that can be used for sound.
The file uhoh.wav is an ‘uhoh’ sound we’ll use for incorrect guesses. The
tada.wav file is a celebratory sound we’ll use for correct guesses. These
files will be loaded when the program starts. Copy the two sound files to
your program’s folder.

Play the two sounds at the appropriate (shaded) locations in the


KeyDownSub subroutine: Sub KeyDownSub K =
GraphicsWindow.LastKey If (GameStatus = "Playing") Then N = 0
If (K = "D1" Or K = "NumPad1") Then N = 1
ElseIf (K = "D2" Or K = "NumPad2") Then N = 2
ElseIf (K = "D3" Or K = "NumPad3") Then N = 3
ElseIf (K = "D4" Or K = "NumPad4") Then N = 4
ElseIf (K = "D5" Or K = "NumPad5") Then N = 5
ElseIf (K = "D6" Or K = "NumPad6") Then N = 6
ElseIf (K = "D7" Or K = "NumPad7") Then N = 7
ElseIf (K = "D8" Or K = "NumPad8") Then N = 8
ElseIf (K = "D9" Or K = "NumPad9") Then N = 9
EndIf
If (N = 0) Then Goto LeaveSub EndIf
'if first number in combo, clear out digits boxes If DigitsEntered
= 0 Then ClearDigits() EndIf
'for second digit on, make sure not in code already If
(NumberDigits >= 1) Then For I = 1 To NumberDigits If (N =
Text.GetSubText(EnteredCombo, I, 1)) Then Goto LeaveSub
EndIf
EndFor
EndIf
EnteredCombo = Text.Append(EnteredCombo, N) DigitsEntered
= DigitsEntered + 1
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 48
GraphicsWindow.DrawText(67 + (DigitsEntered ‐ 1) * 50, 120,
N) 'if all digits entered, check combo If (DigitsEntered =
NumberDigits) Then Tries = Tries + 1
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.FontSize = 16
GraphicsWindow.DrawText(ComboX, ComboY,
EnteredCombo) If (EnteredCombo = SecretCombo) Then
Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
StopGame() Else
NumberRight = 0
For I = 1 To NumberDigits N =
Text.GetSubText(EnteredCombo, I, 1) For J = 1 To
NumberDigits If (N = Text.GetSubText(SecretCombo, J,
1)) Then NumberRight = NumberRight + 1
EndIf
EndFor
EndFor
'how many in correct position PositionRight = 0
For I = 1 To NumberDigits If
(Text.GetSubText(SecretCombo, I, 1) =
Text.GetSubText(EnteredCombo, I, 1)) Then
PositionRight = PositionRight + 1
EndIf
EndFor
GraphicsWindow.DrawText(ComboX + 50, ComboY,
NumberRight + ":" + PositionRight)
Sound.Stop(Program.Directory + "\uhoh.wav")
Sound.Play(Program.Directory + "\uhoh.wav")
'clear combo to try again
EnteredCombo = ""
DigitsEntered = 0
ComboX = ComboX + 100
If (ComboX > 530) Then ComboX = 330
ComboY = ComboY + 20
EndIf
EndIf
EndIf
EndIf
LeaveSub: EndSub

Like the earlier graphics file, the sound files are loaded from the
Program.Directory folder. Also notice you should always Stop a sound
before you Play it – just in case it’s already playing.

Save and Run the program. You should now have a complete, running
version of the Safecracker game. Have fun playing it! See if you can come
up with some kind of winning strategy. Here’s a game I played using 3 non-
repeating digits. First, I tried 123 (obviously not a good guess) and heard
‘uh-oh’:

Next try was 456:


Much better – two digits are correct. I have some valuable information.

Next, I tried 745, digressing a bit:

After a few more tries, I entered 648:


The correct combination was entered! A little celebratory sound was heard
and a message appears. The game returned to its stopped state.
Safecracker Game Program Listing Here is the complete listing of
the Safecracker Small Basic program: 'Safecracker

InitializeProgram() Sub InitializeProgram 'graphics window


GraphicsWindow.Width = 650
GraphicsWindow.Height = 400
'Draw bank safe
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(0, 0, 310, 400)
GraphicsWindow.BrushColor = "LightGray"
GraphicsWindow.FillRectangle(25, 25, 260, 350)
GraphicsWindow.BrushColor = "Gray"
GraphicsWindow.FillRectangle(50, 50, 210, 300)
GraphicsWindow.PenWidth = 2
GraphicsWindow.PenColor = "Black"
GraphicsWindow.DrawRectangle(25, 25, 260, 350)
GraphicsWindow.DrawRectangle(50, 50, 210, 300)
GraphicsWindow.DrawLine(25, 25, 50, 50)
GraphicsWindow.DrawLine(285, 25, 260, 50)
GraphicsWindow.DrawLine(285, 375, 260, 350)
GraphicsWindow.DrawLine(25, 375, 50, 350)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 48
GraphicsWindow.DrawText(95, 50, "BANK") MoneyImage =
ImageList.LoadImage(Program.Directory + "\money.jpg")
GraphicsWindow.DrawImage(MoneyImage, 80, 200) 'Default Options
NumberDigits = 2
GraphicsWindow.Title = "Safecracker ‐ " + NumberDigits + " Digits in
Combination"
ClearDigits() 'results area
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontSize = 20
GraphicsWindow.DrawText(330, 10, "Results:") 'define buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
StartStopButton = Controls.AddButton("Start Game", 320, 360)
OptionsButton = Controls.AddButton("Change Options", 420, 360)
ExitButton = Controls.AddButton("Exit", 550, 360) GameStatus =
"Stopped"
Controls.ButtonClicked = ButtonClickedSub
GraphicsWindow.KeyDown = KeyDownSub EndSub

Sub ClearDigits For I = 1 To NumberDigits GraphicsWindow.BrushColor


= "White"
GraphicsWindow.FillRectangle(60 + (I ‐ 1) * 50, 120, 40, 60)
GraphicsWindow.PenWidth = 1
GraphicsWindow.PenColor = "Black"
GraphicsWindow.DrawRectangle(60 + (I ‐ 1) * 50, 120, 40, 60)
EndFor
EndSub

Sub ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =


"Stopped") Then If (B = ExitButton) Then Program.End() ElseIf (B =
OptionsButton) Then SetOptions() ElseIf (B = StartStopButton) Then
StartGame() EndIf
ElseIf (GameStatus = "Playing") Then If (B = StartStopButton) Then
'stop program
StopGame() EndIf
EndIf
EndSub

Sub SetOptions GraphicsWindow.Hide() TextWindow.Show()


TextWindow.Title = "Safecracker"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("SAFECRACKER OPTIONS")
TextWindow.WriteLine("") GetInput: TextWindow.CursorLeft = 3
TextWindow.WriteLine("The safe combination can have 2, 3, or 4
digits.") TextWindow.CursorLeft = 3
TextWindow.Write("How many digits do you want?") NumberDigits =
TextWindow.ReadNumber() If (NumberDigits < 2 Or NumberDigits > 4)
Then Goto GetInput EndIf
GraphicsWindow.Title = "Safecracker ‐ " + NumberDigits + " Digits in
Combination"
ClearDigits() TextWindow.Hide() GraphicsWindow.Show() EndSub

Sub StartGame GameStatus = "Playing"


'clear results area and change buttons GraphicsWindow.BrushColor =
"White"
GraphicsWindow.FillRectangle(320, 30, 330, 370)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton) Controls.HideControl(ExitButton)
ClearDigits() 'Get combination
SecretCombo = ""
For I = 1 To NumberDigits 'select unique digit
UniqueDigit = "false"
While (UniqueDigit = "false") J = Math.GetRandomNumber(9)
UniqueDigit = "true"
If I <> 1 Then For K = 1 To I ‐ 1
If (Text.GetSubText(SecretCombo, K, 1) = J) Then
UniqueDigit = "false"
EndIf
EndFor
EndIf
EndWhile
SecretCombo = Text.Append(SecretCombo, J) EndFor
EnteredCombo = ""
DigitsEntered = 0
Tries = 0
ComboX = 330
ComboY = 40
EndSub

Sub StopGame 'restore buttons


GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton) 'write message
ComboX = 330
ComboY = ComboY + 20
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontSize = 16
If (EnteredCombo = SecretCombo) Then
GraphicsWindow.DrawText(ComboX, ComboY, "That's it!! It took you "
+ Tries + " tries.") Else
GraphicsWindow.DrawText(ComboX, ComboY, "Game Stopped.
Combination: " + SecretCombo) EndIf
EndSub

Sub KeyDownSub K = GraphicsWindow.LastKey If (GameStatus =


"Playing") Then N = 0
If (K = "D1" Or K = "NumPad1") Then N = 1
ElseIf (K = "D2" Or K = "NumPad2") Then N = 2
ElseIf (K = "D3" Or K = "NumPad3") Then N = 3
ElseIf (K = "D4" Or K = "NumPad4") Then N = 4
ElseIf (K = "D5" Or K = "NumPad5") Then N = 5
ElseIf (K = "D6" Or K = "NumPad6") Then N = 6
ElseIf (K = "D7" Or K = "NumPad7") Then N = 7
ElseIf (K = "D8" Or K = "NumPad8") Then N = 8
ElseIf (K = "D9" Or K = "NumPad9") Then N = 9
EndIf
If (N = 0) Then Goto LeaveSub EndIf
'if first number in combo, clear out digits boxes If DigitsEntered = 0
Then ClearDigits() EndIf
'for second digit on, make sure not in code already If (NumberDigits
>= 1) Then For I = 1 To NumberDigits If (N =
Text.GetSubText(EnteredCombo, I, 1)) Then Goto LeaveSub EndIf
EndFor
EndIf
EnteredCombo = Text.Append(EnteredCombo, N) DigitsEntered =
DigitsEntered + 1
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 48
GraphicsWindow.DrawText(67 + (DigitsEntered ‐ 1) * 50, 120, N) 'if
all digits entered, check combo If (DigitsEntered = NumberDigits)
Then Tries = Tries + 1
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.FontSize = 16
GraphicsWindow.DrawText(ComboX, ComboY, EnteredCombo)
If (EnteredCombo = SecretCombo) Then
Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav") StopGame() Else
NumberRight = 0
For I = 1 To NumberDigits N =
Text.GetSubText(EnteredCombo, I, 1) For J = 1 To
NumberDigits If (N = Text.GetSubText(SecretCombo, J, 1))
Then NumberRight = NumberRight + 1
EndIf
EndFor
EndFor
'how many in correct position PositionRight = 0
For I = 1 To NumberDigits If
(Text.GetSubText(SecretCombo, I, 1) =
Text.GetSubText(EnteredCombo, I, 1)) Then PositionRight =
PositionRight + 1
EndIf
EndFor
GraphicsWindow.DrawText(ComboX + 50, ComboY,
NumberRight + ":" + PositionRight)
Sound.Stop(Program.Directory + "\uhoh.wav")
Sound.Play(Program.Directory + "\uhoh.wav") 'clear combo
to try again
EnteredCombo = ""
DigitsEntered = 0
ComboX = ComboX + 100
If (ComboX > 530) Then ComboX = 330
ComboY = ComboY + 20
EndIf
EndIf
EndIf
EndIf
LeaveSub: EndSub
Safecracker Game Program Review

The Safecracker game program is now complete. Save and Run the
program and make sure it works as promised. Check that all options work
correctly.

If there are errors in your implementation, go back over the steps of


window and code design. Go over the developed code – make sure you
understand how different parts of the program were coded. As mentioned in
the beginning of this chapter, the completed program is saved as
Safecracker in the KidGamesSB\KidGamesSB Programs\Safecracker
folder.

While completing this program, new concepts and skills you should have
gained include:

➢ Proper steps in program design.


➢ Capabilities and use of many Small Basic features.
➢ Using button controls.
➢ Detecting key presses.
➢ Using random numbers and sounds.
Safecracker Game Program Enhancements There are always
things you can do to improve a program. At the end of each chapter, we will
give you some ideas for the current program. For the Safecracker game,
some possibilities are:

➢ Add an option so the digits in the combination can repeat. You will
need to modify the code that generates and checks the combination.
You will need to allow the user to enter repeated digits. Do you see
how such an option makes the game easier to play?
➢ To make the game simpler for smaller children, you might like to
have combinations that use fewer than the 9 digits. For example, a
three digit code that only uses the numbers from 1 to 4 would be
much easier to guess. You would need logic to decide which keys to
allow.
➢ After each guess, you might like to provide a hint on how to proceed.
➢ After a correct combination, maybe have more dramatic results.
Perhaps, have the bank graphic disappear and a pile of treasure
appear.
6. Tic Tac Toe Program
Review and Preview

The next program we build is the classic Tic Tac Toe game, where
you try to line up 3 X’s or 3 O’s in a 3 by 3 grid. We’ll develop a two
player version and one where you can play against the computer.
Tic Tac Toe Program Preview

In this chapter, we will build a Tic Tac Toe game. This is purportedly the
first game ever programmed on a computer and one of the first ever
programmed by Bill Gates when he was a teenager. The object of the game
is line up 3 X markers or 3 O markers in a 3 by 3 grid. The markers can run
horizontally, vertically or diagonally. Turns alternate between players. The
version we build here allows two players to compete against each other or
to have a single player compete against a pretty smart computer.

The finished program is saved as TicTacToe in the


KidGamesSB\KidGamesSB Programs\TicTacToe folder. Start Small
Basic and open the finished program. Run the program (click the Run
toolbar button or press <F5>). The game will appear in its ‘stopped’ state.
At this point, you can click the Start Game button to start the game, click
Change Options to change program options or click Exit to exit the
program.
Click Change Options to change options. A text window will appear:

You are given a few questions to choose game options (one or two players
and, if one player, who goes first and how smart you want the computer to
be). Make your choices (pressing Enter after each). For this example, I
selected a one player game, where I go first (giving me X’s) and a smart
computer:

The graphics window reappears with the game still in the ‘stopped’ state.
Notice the title bar area reflects a single player game.

Click the Start Game button to start playing. The button choices change.
The message at the top of the grid says X’s Turn. X always goes first in this
game (whether it’s you, the human player, or the computer). This is the

game’s ‘playing’ state:

In this state, you make a mark in the grid by clicking on the desired square.
The computer will then place its mark, making it your turn again. After each
mark, the board is examined for a win or a draw. You keep alternating turns
until there is a win, the grid is full or until you click Stop Game. The game
works the same way for two players, with the two players alternating turns
marking the grid.

Enter a mark; I chose the center square and the computer immediately
placed its mark (an O) in the upper left corner:
I try the lower left corner and the computer blocks me from winning:
I block the computer’s possible win by putting an X in the middle box of
the top row. Then, the computer blocks me with a move to the middle of the

bottom row:

Looks like no one is going to win here.

I continued playing (moving to the right of the middle row and, following
the computer’s block, a move to the right of the bottom row) until finally
we ended in a draw:

Looks like the computer is pretty smart! We’ll see how this intelligence is
programmed later. Notice the game returns to its ‘stopped’ state to allow
another game, changing options or to stop the program.

Continue playing the game to understand its operation. Try using the
Random Computer option (the computer just makes random moves
making it easier to beat). Click the Exit button when you’re done to exit the
game. Look over the code in the editor if you like.

You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.

We address window design. And, we address code design. We discuss how


to mark the grid, handle multiple players, check for a win and decide how
to make computer-generated moves.
Tic Tac Toe Window Design

Here is a sketch for the window layout of the Tic Tac Toe game:

A message area is at the top. The game grid (drawn with skinny rectangles)
is below. Identifying numbers are given to the nine boxes in the grid. Three
button controls will be used: one to start and stop the game, one to change
options and one to exit the program.

We now begin writing code for the Tic Tac Toe game. We will write the
code in several steps. As a first step, we will write the code that draws the
window, then starts the game and establishes its ‘stopped’ state. We write
code to set game options in a text window. Then, we look at how to go to
‘playing’ state following clicking of the Start Game button. During the
code development process, recognize you may modify a particular
procedure several times before arriving at the finished product.
Start a new program in Small Basic. Once started, we suggest you
immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Message Area

The first element of the Tic Tac Toe window is the bordered message area
at the top of the window. It is used to inform the user of whose turn it is and
who wins (if there is a win).

Add this code to your blank editor: 'Tic Tac Toe


InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 340
GraphicsWindow.Height = 460
'Draw message area
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FillRectangle(10, 10, 320, 50)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawRectangle(10, 10, 320, 50)
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 30
Message = "Game Stopped"
MessageX = 70
MessageArea = Shapes.AddText(Message) DisplayMessage()
EndSub

The first line of code calls a subroutine InitializeProgram where we will


put all code needed to set up the program for use. All remaining code here
goes in that subroutine. The code establishes the window size and draws a
filled, bordered rectangle to surround the message area. The message to
display is Message and its horizontal location is MessageX. A Shapes
object (MessageArea) is created to display the message.

The subroutine DisplayMessage writes the message. Add this to your code:
Sub DisplayMessage Shapes.Move(MessageArea, MessageX, 15)
Shapes.SetText(MessageArea, Message) EndSub

This is similar to code we will use often in building game programs. To


display information that changes often, the Shapes object that displays text
is invaluable. To update the display, we simply change the text using
SetText (and in this case Move the text to make it appear centered in
MessageArea). An immediate, flicker-free update is seen.

Save and Run the program. You should see the initial ‘Game Stopped’

message:
Window Design – Draw Grid

The next element of the game window is the Tic Tac Toe grid. It is drawn
with ‘skinny’ rectangles. Add these lines of code at the end of the
InitializeProgram subroutine: 'draw grid
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(10, 170, 320, 10)
GraphicsWindow.FillRectangle(10, 280, 320, 10)
GraphicsWindow.FillRectangle(110, 70, 10, 320)
GraphicsWindow.FillRectangle(220, 70, 10, 320) Save and Run the

program to see the grid:


Window Design – Add Buttons

The final item we need are three button controls used to start/stop the game,
change options and exit the program.

Add this code at the end of InitializeProgram: 'define buttons


GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
StartStopButton = Controls.AddButton("Start Game", 10, 420)
OptionsButton = Controls.AddButton("Change Options", 110, 420)
ExitButton = Controls.AddButton("Exit", 240, 420) Save and Run the
program. The finished window is displayed:

We establish three buttons (StartStopButton, OptionsButton,


ExitButton).
Code Design – Initializing Stopped State Any time we start a
program, there are certain initializations that must take place. Let’s look at
the initializations needed in the Tic Tac Toe game. All initializations are
done in the main program.

We want to initialize the number of players in the game (NumberPlayers),


whether you go first (YouGoFirst) and whether the computer is smart
(SmartComputer). We will use this information to update the graphics
window title. We also want to know the location of the nine areas (boxes)
within the Tic Tac Toe grid. This will help us place marks there later.

Add this code at the end of InitializeProgram: 'Default Options


NumberPlayers = 2
YouGoFirst = "true"
SmartComputer = "true"
SetTitle() 'initialize box locations and marks x = 20
y = 80
For I = 1 to 9
BoxX[I] = x BoxY[I] = y x = x + 110
If (x > 240) Then x = 20
y = y + 110
EndIf
EndFor
GameStatus = "Stopped"

This code initializes the options variables. Next, the (x, y) location of the
nine boxes in the grid is established. Lastly, the GameStatus is set to
“Stopped”.

The subroutine SetTitle is also needed: Sub SetTitle If (NumberPlayers =


1) Then GraphicsWindow.Title = "Tic Tac Toe ‐ 1 Player"
Else
GraphicsWindow.Title = "Tic Tac Toe ‐ 2 Players"
EndIf
EndSub

This sets the window title based on selected options.

Once again, Save and Run. You’ll see the game in the ‘stopped’ state (using

default properties):

As desired, the game initializes in Two Players mode.

We have three choices at this point – either click Start Game to start, click
Change Options to change options, or click Exit to exit the program. We
will write code for each of these options in reverse order.

First, we need to be able to detect button clicks so add this line at the end of
InitializeProgram: Controls.ButtonClicked = ButtonClickedSub With this,
each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.
The code for exiting is simple. It is placed in the ButtonClickedSub
subroutine: Sub ButtonClickedSub B = Controls.LastClickedButton If
(GameStatus = "Stopped") Then If (B = ExitButton) Then Program.End()
EndIf
EndIf
EndSub

This simply says whenever Exit is clicked, the program ends. Run the
program. Click Exit to make sure the game stops.

If the user clicks Change Options, we want to provide the ability to change
program options. We will use the Small Basic text window to establish
game options. Add the shaded code to the ButtonClickedSub subroutine:
Sub ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =
"Stopped") Then If (B = ExitButton) Then Program.End()
ElseIf (B = OptionsButton) Then SetOptions()
EndIf
EndIf
EndSub

The options are set in the SetOptions subroutine – add this routine: Sub
SetOptions GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title
= "Tic Tac Toe"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("TIC TAC TOE OPTIONS")
TextWindow.WriteLine("") GetPlayers: TextWindow.CursorLeft = 3
TextWindow.WriteLine("With one player, you play against the
computer.") TextWindow.CursorLeft = 3
TextWindow.WriteLine("With two players, you play against a
friend.") TextWindow.CursorLeft = 3
TextWindow.Write("How many players do you want (1 or 2)?")
NumberPlayers = TextWindow.ReadNumber() If (NumberPlayers < 1
Or NumberPlayers > 2) Then Goto GetPlayers EndIf
If (NumberPlayers = 1) Then GetWhoFirst:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can go first or the computer can go
first.") TextWindow.CursorLeft = 3
TextWindow.Write("Who goes first (1‐You, 2‐Computer)?") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto
GetWhoFirst EndIf
If (T = 1) Then YouGoFirst = "true"
Else
YouGoFirst = "false"
EndIf
GetSmart: TextWindow.WriteLine("") TextWindow.CursorLeft =
3
TextWindow.WriteLine("Computer can make random moves or
smart moves.") TextWindow.CursorLeft = 3
TextWindow.Write("What do you want (1‐Random, 2‐Smart)?") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto GetSmart
EndIf
If (T = 2) Then SmartComputer = "true"
Else
SmartComputer = "false"
EndIf
EndIf
SetTitle() TextWindow.Hide() GraphicsWindow.Show() EndSub

This routine hides the graphics window, displays a text window and asks
the user questions necessary to establish the three options
(NumberPlayers, YouGoFirst, SmartComputer). Note, if two players are
selected, there is no need to ask who goes first or how smart the computer
should be. Once the questions are answered, the program returns to the
game in ‘stopped’ state with a new window title.

Save and Run the program. Click the Change Options button the change
options:
Make your choices and press Enter after each. The Tic Tac Toe game
window will again appear.

Here’s what I got for a single player (the only difference is in the title bar):
The code for clicking the Start Game button (to start the game) is much
more complicated. We will build it in several steps. First, we look at
switching the game from stopped to playing state.
Code Design – Stopped to Playing State When the user clicks the
Start Game button in the ‘stopped’ state, several things must happen to
switch the Tic Tac Toe game to ‘playing’ state:

➢ Change GameStatus to “Playing”


➢ Change the caption of StartStopButton to Stop Game.
➢ Hide OptionsButton and ExitButton.
➢ Establish this as X’s turn (since X always goes first).
➢ Blank out grid boxes displaying marks.
➢ Allow player to input a mark on the grid.

We use two variables to help keep track of where we are in the game. If
XTurn is “true”, it is X’s turn, otherwise it is O’s turn. NumberClicks
keeps track of how many of the grid boxes have been clicked on (9
maximum).

Add the shaded code to the ButtonClickSub subroutine: Sub


ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =
"Stopped") Then If (B = ExitButton) Then Program.End() ElseIf (B =
OptionsButton) Then SetOptions()
ElseIf (B = StartStopButton) Then StartGame()
EndIf
EndIf
EndSub

Clicking Start Game calls the StartGame subroutine: Sub StartGame


GameStatus = "Playing"
XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() 'clear boxes
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
For I = 1 To 9
BoxMark[I] = ""
GraphicsWindow.FillRectangle(BoxX[I] ‐ 5, BoxY[I] ‐ 5, 90, 90)
EndFor
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton)
Controls.HideControl(ExitButton) NumberClicks = 0
EndSub

Can you see how the needed steps are implemented in code?

Save and Run the program. Click Start Game and the game should switch

to two player ‘playing’ state:

The game is waiting for the first player to click one of the grid locations
(we’ll write code for that soon). Notice clicking Stop Game does nothing at
the moment. Let’s fix that. Stop the program.
Code Design – Playing to Stopped State When the user clicks the
Stop Game button in the two player ‘playing’ state, we want the Tic Tac
Toe game to change to ‘stopped’ state. The steps for this are:

➢ Change GameStatus to “Stopped”


➢ Change the caption of StartStopButton to Start Game.
➢ Show OptionsButton and ExitButton.

Add the shaded code to the ButtonClickedSub subroutine: Sub


ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =
"Stopped") Then If (B = ExitButton) Then Program.End() ElseIf (B =
OptionsButton) Then SetOptions() ElseIf (B = StartStopButton) Then
StartGame() EndIf
ElseIf (GameStatus = "Playing") Then If (B = StartStopButton)
Then 'stop program
Message = "Game Stopped"
MessageX = 70
StopGame() EndIf
EndIf
EndSub

Clicking Stop Game establishes a message to display and calls the


StopGame subroutine.

Add the StopGame subroutine: Sub StopGame 'restore buttons


GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton) DisplayMessage() EndSub
Save and Run the program. You should be able to now move from
‘stopped’ to ‘playing’ state and back. Try the Exit button. Let’s write the
code for the two player game (the default value for NumberPlayers), first
looking at how to mark the grid.
Code Design – Marking Grid

In the Tic Tac Toe two player game, when a player clicks a box in the grid,
we want the proper mark (X or O) to appear. After each mark, we then need
to see if anyone won. If there is no win, and there are still empty locations,
we switch to the next player. Recall, for reference purposes, the nine areas

of the grid are numbered as follows:

So, when a box in the game grid is clicked, we follow these steps:

➢ Make sure there is not a mark there already.


➢ Increment NumberClicks.
➢ Place proper mark in corresponding location (X if XTurn is “true”,
otherwise O).
➢ Switch to next player (not needed if there is a win or draw).
➢ Check for win. If there is a win, declare the winner and stop the
game.
➢ Check if NumberClicks = 9 (board is full with no win). If so, declare
the game a draw and stop.

To detect mouse clicks, we need this line at the end of the


InitializeProgram subroutine: GraphicsWindow.KeyDown =
KeyDownSub With this, each time a KeyDown event occurs, the
subroutine named KeyDownSub is called. The code to perform the steps
above will be in this subroutine.

Add this subroutine (MouseDownSub) to your program. This implements


the needed steps to accept the player’s marking of the grid: Sub
MouseDownSub If (GameStatus = "Playing") Then 'find which box was
clicked x = GraphicsWindow.MouseX
y = GraphicsWindow.MouseY
ClickedBox = 0
For I = 1 To 9
If (x > BoxX[I] And x < BoxX[I] + 80) Then If (y > BoxY[I]
And y < BoxY[I] + 80) Then ClickedBox = I Goto GotIt
EndIf
EndIf
EndFor
GotIt: If (ClickedBox <> 0) Then 'if already clicked then exit If
(BoxMark[ClickedBox] <> "") Then Goto LeaveSub EndIf
MarkAndCheck() EndIf
EndIf
LeaveSub: EndSub

Let’s look at this code. Clicking the graphics window with the mouse will
call this subroutine. The first part of the code determines which grid box
area (if any) was clicked (the variable ClickedBox). If there is already a
mark there (not blank), the subroutine is exited. If blank, another subroutine
(MarkAndCheck) is called to do the actual marking and check for a win.
We use a subroutine for this step because later we will want a way for the
computer to mark the grid when it is the opponent.

Add the subroutine MarkAndCheck to your code (we are not checking for
a win yet): Sub MarkAndCheck NumberClicks = NumberClicks + 1
If (XTurn) Then BoxMark[ClickedBox] = "X"
DrawX() XTurn = "false"
Message = "O's Turn"
MessageX = 115
DisplayMessage() Else
BoxMark[ClickedBox] = "O"
DrawO() XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() EndIf
'check for win ‐ will establish a value for WhoWon CheckForWin() If
(WhoWon <> "") Then Message = WhoWon + " Wins!"
MessageX = 115
StopGame() ElseIf (NumberClicks = 9) Then 'draw
Message = "It's a Draw!"
MessageX = 95
StopGame() EndIf
EndSub

Here, the proper mark is placed in BoxMark[ClickedBox]. After this, we


check for a win in the subroutine CheckForWin. If the variable WhoWon
is not blank (will be established by the check win logic), we declare the
winner. Otherwise, we keep accepting clicks until the grid is full, declaring
a draw.

The above subroutine requires these subroutines to draw an X or O. Add


them to your program: Sub DrawX
'draw blue X at ClickedBox GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 10
GraphicsWindow.DrawLine(BoxX[ClickedBox], BoxY[ClickedBox],
BoxX[ClickedBox] + 80, BoxY[ClickedBox] + 80)
GraphicsWindow.DrawLine(BoxX[ClickedBox], BoxY[ClickedBox]
+ 80, BoxX[ClickedBox] + 80, BoxY[ClickedBox]) EndSub

Sub DrawO
'draw blue O at Clicked Box GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 10
GraphicsWindow.DrawEllipse(BoxX[ClickedBox],
BoxY[ClickedBox], 80, 80) EndSub

These routines use thick lines for the X and a thick ellipse for the O.

We also need the CheckForWin subroutine. For now, just use this which
returns a blank for the WhoWon variable: Sub CheckForWin WhoWon =
""
EndSub

We will write code for this subroutine next.

Save and Run the program. You should be able to click on each of the grid
locations, placing X’s and O’s there in alternate turns. Once you have filled
all the grid locations, the game will be returned to stopped state. Wins will
not be recognized. Here’s what I got when I tried it:

As expected, the computer completely missed the fact that O (Player 2) got
a Tic Tac Toe!! Let’s fix that. We will modify the CheckForWin
subroutine to determine a value for the WhoWon variable used in the code.
Code Design – Checking For Win The CheckForWin subroutine
examines the playing grid and determines if there is a winner. If so, the win
will be identified and the subroutine will establish a value for WhoWon – it
will hold the marker (X or O) for the winner or a blank if there is no
winner. Let’s establish a strategy for doing this.

There are eight possible ways to win (3 horizontal, 3 vertical, 2 diagonal).


Notice the indices for the BoxMark array used in the playing grid are laid

out in this manner:

If we have a string array named PossibleWins, its 8 elements would be:


'possible wins
PossibleWins[1] = "123"
PossibleWins[2] = "456"
PossibleWins[3] = "789"
PossibleWins[4] = "147"
PossibleWins[5] = "258"
PossibleWins[6] = "369"
PossibleWins[7] = "159"
PossibleWins[8] = "357"

Add the above lines to the InitializeProgram subroutine to establish values


for the PossibleWins array.

So our win logic would be to go through each possible win and see if the
corresponding elements of BoxMark all contain the same mark (X or O,
but not blank). If so, a winner is declared.

Put the modified CheckForWin subroutine in your program (new lines are
shaded): Sub CheckForWin WhoWon = ""
'check all possible for win For I = 1 To 8
For J = 1 To 3
BoxNumber[J] = Text.GetSubText(PossibleWins[I], J, 1)
Mark[J] = BoxMark[BoxNumber[J]]
EndFor
If (Mark[1] = Mark[2] And Mark[1] = Mark[3] And Mark[2] =
Mark[3] And Mark[1] <> "") Then 'we have a winner
WhoWon = Mark[1]
For J = 1 To 3
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.FillRectangle(BoxX[BoxNumber[J]] ‐
5, BoxY[BoxNumber[J]] ‐ 5, 90, 90) ClickedBox =
BoxNumber[J]
If (WhoWon = "X") Then DrawX() Else
DrawO() EndIf
EndFor
EndIf
EndFor
EndSub

This code goes through all the possible wins. If all the marks in a particular
horizontal, vertical or diagonal line match, the marks in that line are
redrawn in a red rectangle and the corresponding winner returned. Study the
code to see how it works. The BoxNumber array holds the indices of the
BoxMark array for each possible win.

Save and Run the program. You and a friend should be able to compete
with wins and draws properly determined. Here is a replay of the game I
tried before (notice the win by O is now declared):

The two player game is now complete. Let’s start looking at how to
implement a one player game versus a computer opponent. We’ll start easy,
just having the computer make random moves (no brains!). This will help
us establish the logic of switching players when the computer is one of
them.
Code Design – Random Computer Moves A big part of allowing the
computer to play against a human (you, the player) is to decide what
“thought processes” to give the computer. We’re allowing two choices: a
random computer and a smart computer. We’ll start by coding up the
random computer. This will get all the logic of implementing computer
moves along with human moves working properly. Then, we’ll move on to
a smart computer, developing a formidable opponent.

All of the logic behind a computer move will be implemented in a


subroutine named ComputerTurn. For random moves, it will simply
choose (at random) one of the empty boxes in the grid and place a marker in
that box (X if computer goes first, O if human goes first.

Place this subroutine ComputerTurn in your program: Sub ComputerTurn


If (SmartComputer <> "true") Then 'random logic
'put mark in Nth available square N =
Math.GetRandomNumber(9 ‐ NumberClicks) I = 0
For ClickedBox = 1 To 9
If (BoxMark[ClickedBox] = "") Then I = I + 1
If I = N Then Goto GotMark EndIf
EndIf
EndFor
GotMark: 'put mark in ClickedBox
MarkAndCheck() Else
'smart computer
EndIf
EndSub

The logic behind the code in ComputerTurn is straightforward. At any


time, we have 9 - NumberClicks empty boxes in the grid. The code selects
a random number from 1 to 9 – NumberClicks and counts ahead that
number of empty boxes to identify the box to mark. To mark the identified
box, BoxMark[ClickedBox], we call the subroutine MarkAndCheck. The
program will know whether to place an X or O in the box based on
previously implemented logic.

Now, let’s implement the ComputerTurn subroutine to allow the computer


to play. We need to modify two subroutines. First, when we start a game, if
the computer moves first, we need to invoke ComputerTurn. Make the
shaded changes to the StartGame subroutine: Sub StartGame GameStatus
= "Playing"
XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() 'clear boxes
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
For I = 1 To 9
BoxMark[I] = ""
GraphicsWindow.FillRectangle(BoxX[I] ‐ 5, BoxY[I] ‐ 5, 90, 90)
EndFor
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton)
Controls.HideControl(ExitButton) NumberClicks = 0
If (NumberPlayers = 1 And YouGoFirst = "false") Then
ComputerTurn() EndIf
EndSub

And, after a mark is placed by the human player, the computer needs to take
a turn. This logic is in the MarkAndCheck subroutine. The needed
changes are shaded: Sub MarkAndCheck NumberClicks = NumberClicks +
1
If (XTurn) Then BoxMark[ClickedBox] = "X"
DrawX() XTurn = "false"
Message = "O's Turn"
MessageX = 115
DisplayMessage() Else
BoxMark[ClickedBox] = "O"
DrawO() XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() EndIf
'check for win ‐ will establish a value for WhoWon CheckForWin() If
(WhoWon <> "") Then Message = WhoWon + " Wins!"
MessageX = 115
StopGame() ElseIf (NumberClicks = 9) Then 'draw
Message = "It's a Draw!"
MessageX = 95
StopGame() EndIf
If (NumberPlayers = 1 And WhoWon = "") Then If (XTurn = "true"
And YouGoFirst = "false") Or (XTurn = "false" And YouGoFirst =
"true") Then ComputerTurn() EndIf
EndIf
EndSub

With the added code, if there is no win, the computer takes a turn when it
goes first and it’s X’s turn or takes a turn when the human goes first and it’s
O’s turn.

Save and Run the game. Click Change Options to change options. Choose
1 Player, You Go First and Random Computer. Each option requires
entering a 1:

Make sure things work properly, you should see the computer is pretty easy
to beat! Here’s a game I won when I went first:

Try playing a few games (you go first, computer going first).


Code Design – Smart Computer Moves We’ve come to one of the
more fun and more challenging parts of this game program. How can we
make our computer a smarter opponent? In any game where a computer is
playing against a human, we must be able to write down some rules that
give the computer the appearance of intelligence. Many computer
opponents are unbeatable. For example, it is very hard for a human to beat a
computer at the game of chess.

So how do we make our computer a better Tic Tac Toe player? We try to
imbed choices we would make if we were playing the game. So for the
computer to be a smart player, the programmer needs to be a smart player.
This usually takes practice and study. For the game of Tic Tac Toe, we can
develop a fairly simple, yet very intelligent strategy. Let’s do it.

When it is the computer’s turn, what should its move be? The rules we will
use are (in order of choice):

1. If the computer can win with a move, make that move and the game
is over. So, if there’s a line with two of the computer’s markers and
an empty space, the empty space is the place to mark!
2. If the computer can block with a move, make that move and the
opponent can’t win on the next move. So, if there’s a line with two of
the human player’s markers and an empty space, the empty space is
the place to mark!
3. If there is no possible win or possible block, make a move in this
order: center square, one of the four corner squares, or one of the four
side squares.

I think you see this logic makes sense. You may wonder about Step 3 – why
we choose that particular order. Recall there are 8 possible ways to win in
Tic Tac Toe (3 horizontal, 3 vertical, 2 diagonal). The center square is
needed in 4 of these, any one corner is involved in 3 possibilities, while any
side is involved in just 2 wins. Hence, the order of choices is made on basic
probabilities. Let’s implement this logic in code.
Here is the modified ComputerTurn subroutine that implements this
‘smart’ logic. The changes are shaded: Sub ComputerTurn If
(SmartComputer <> "true") Then 'random logic
'put mark in Nth available square N =
Math.GetRandomNumber(9 ‐ NumberClicks) I = 0
For ClickedBox = 1 To 9
If (BoxMark[ClickedBox] = "") Then I = I + 1
If I = N Then Goto GotMark EndIf
EndIf
EndFor
GotMark: 'put mark in ClickedBox
MarkAndCheck() Else
'smart computer
BestMoves[1] = 5
BestMoves[2] = 1
BestMoves[3] = 3
BestMoves[4] = 7
BestMoves[5] = 9
BestMoves[6] = 2
BestMoves[7] = 4
BestMoves[8] = 6
BestMoves[9] = 8
'determine who has what mark If (YouGoFirst) Then
ComputerMark = "O"
PlayerMark = "X"
Else
ComputerMark = "X"
PlayerMark = "O"
EndIf
'Step 1 (K = 1) ‐ check for win ‐ see if two boxes hold computer
mark and one is empty 'Step 2 (K = 2) ‐ check for block ‐ see if
two boxes hold player mark and one is empty For K = 1 To 2
If K = 1 Then MarkToFind = ComputerMark Else
MarkToFind = PlayerMark EndIf
For I = 1 To 8
N=0
EmptyBox = 0
For J = 1 To 3
BoxNumber[J] = Text.GetSubText(PossibleWins[I], J,
1) Mark[J] = BoxMark[BoxNumber[J]]
If (Mark[J] = MarkToFind) Then N = N + 1
ElseIf (Mark[J] = "") Then EmptyBox =
BoxNumber[J]
EndIf
EndFor
If (N = 2 And EmptyBox <> 0) Then 'mark empty box to
win (K = 1) or block (K = 2) ClickedBox = EmptyBox
MarkAndCheck() Goto LeaveComputerMove EndIf
EndFor
EndFor
'Step 3 ‐ find next best move For I = 1 To 9
If (BoxMark[BestMoves[I]] = "") Then ClickedBox =
BestMoves[I]
MarkAndCheck() Goto LeaveComputerMove EndIf
EndFor
EndIf
LeaveComputerMove:
EndSub

In the ‘smart’ logic, we first find out whether the computer has X or O.
Steps 1 and 2 of the computer logic are done in a For loop with K as index.
In that loop, we go through all the possible wins looking for a line with 2
identical marks and an empty box. For K=1, we look for the computer’s
mark and an empty box – giving the computer a win on the next move. For
K=2, we look for the human’s mark and an empty box – giving the
computer a block on the next move. If neither Step 1 or Step 2 is successful,
we move to Step 3. The next best moves are listed in desired order in the
array BestMoves. In Step 3, we go through this array, finding the first
empty box available and move there.

Save and Run the program. The game is now fully functional. Try playing
it against the computer. You should find it can’t be beat. The best you can
do against the computer is a draw. Before leaving, let’s add a couple of
sounds.
Code Design – Adding Sounds

We know sounds make games a bit more fun. Let’s add a couple to the Tick
Tac Toe game. In the KidGamesSB\KidGamesSB Programs\TicTacToe
folder are two wav files that can be used for sound. The file beep.wav is a
sound we’ll use for games that end a draw. The tada.wav file is a
celebratory sound we’ll use for wins by either player. These files will be
loaded when the program starts. Copy the two sound files to your program’s
folder.

Play the two sounds at the appropriate (shaded) locations in the


MarkAndCheck subroutine: Sub MarkAndCheck NumberClicks =
NumberClicks + 1
If (XTurn) Then BoxMark[ClickedBox] = "X"
DrawX() XTurn = "false"
Message = "O's Turn"
MessageX = 115
DisplayMessage() Else
BoxMark[ClickedBox] = "O"
DrawO() XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() EndIf
'check for win ‐ will establish a value for WhoWon CheckForWin() If
(WhoWon <> "") Then
Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Message = WhoWon + " Wins!"
MessageX = 115
StopGame() ElseIf (NumberClicks = 9) Then 'draw
Sound.Stop(Program.Directory + "\beep.wav")
Sound.Play(Program.Directory + "\beep.wav")
Message = "It's a Draw!"
MessageX = 95
StopGame() EndIf
If (NumberPlayers = 1 And WhoWon = "") Then If (XTurn = "true"
And YouGoFirst = "false") Or (XTurn = "false" And YouGoFirst =
"true") Then ComputerTurn() EndIf
EndIf
EndSub

Save and Run the program. You should now have a complete, running
version of the Tic Tac Toe game. Have fun playing it! Again, you will see
the computer can’t be beat. Here’s a game I played against a ‘smart’
computer where I went first, taking the middle square:

Notice, based on the logic we implemented, since the computer couldn’t


win or block, it took its next best move, the first available corner square.
My next move was the lower left corner:

The computer logic implemented block my next move.


My next move was to block the computer, who in turn blocked me:

I continued playing (moving to the right of the middle row and, following
the computer’s block, a move to the right of the bottom row) until finally
we ended in a draw:

I heard the little beep and the computer’s ready to play again.
Tic Tac Toe Game Program Listing Here is the complete listing of
the Tic Tac Toe Small Basic program: 'Tic Tac Toe

InitializeProgram() Sub InitializeProgram 'graphics window


GraphicsWindow.Width = 340
GraphicsWindow.Height = 460
'Draw message area
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FillRectangle(10, 10, 320, 50)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawRectangle(10, 10, 320, 50)
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 30
Message = "Game Stopped"
MessageX = 70
MessageArea = Shapes.AddText(Message) DisplayMessage() 'draw grid
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(10, 170, 320, 10)
GraphicsWindow.FillRectangle(10, 280, 320, 10)
GraphicsWindow.FillRectangle(110, 70, 10, 320)
GraphicsWindow.FillRectangle(220, 70, 10, 320) 'define buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
StartStopButton = Controls.AddButton("Start Game", 10, 420)
OptionsButton = Controls.AddButton("Change Options", 110, 420)
ExitButton = Controls.AddButton("Exit", 240, 420) 'Default Options
NumberPlayers = 2
YouGoFirst = "true"
SmartComputer = "true"
SetTitle() 'initialize box locations and marks x = 20
y = 80
For I = 1 to 9
BoxX[I] = x BoxY[I] = y x = x + 110
If (x > 240) Then x = 20
y = y + 110
EndIf
EndFor
GameStatus = "Stopped"
Controls.ButtonClicked = ButtonClickedSub
GraphicsWindow.MouseDown = MouseDownSub 'possible wins
PossibleWins[1] = "123"
PossibleWins[2] = "456"
PossibleWins[3] = "789"
PossibleWins[4] = "147"
PossibleWins[5] = "258"
PossibleWins[6] = "369"
PossibleWins[7] = "159"
PossibleWins[8] = "357"
EndSub

Sub DisplayMessage Shapes.Move(MessageArea, MessageX, 15)


Shapes.SetText(MessageArea, Message) EndSub

Sub SetTitle If (NumberPlayers = 1) Then GraphicsWindow.Title = "Tic


Tac Toe ‐ 1 Player"
Else
GraphicsWindow.Title = "Tic Tac Toe ‐ 2 Players"
EndIf
EndSub
Sub ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =
"Stopped") Then If (B = ExitButton) Then Program.End() ElseIf (B =
OptionsButton) Then SetOptions() ElseIf (B = StartStopButton) Then
StartGame() EndIf
ElseIf (GameStatus = "Playing") Then If (B = StartStopButton) Then
'stop program
Message = "Game Stopped"
MessageX = 70
StopGame() EndIf
EndIf
EndSub

Sub SetOptions GraphicsWindow.Hide() TextWindow.Show()


TextWindow.Title = "Tic Tac Toe"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("TIC TAC TOE OPTIONS")
TextWindow.WriteLine("") GetPlayers: TextWindow.CursorLeft = 3
TextWindow.WriteLine("With one player, you play against the
computer.") TextWindow.CursorLeft = 3
TextWindow.WriteLine("With two players, you play against a friend.")
TextWindow.CursorLeft = 3
TextWindow.Write("How many players do you want (1 or 2)? ")
NumberPlayers = TextWindow.ReadNumber() If (NumberPlayers < 1 Or
NumberPlayers > 2) Then Goto GetPlayers EndIf
If (NumberPlayers = 1) Then GetWhoFirst: TextWindow.WriteLine("")
TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can go first or the computer can go
first.") TextWindow.CursorLeft = 3
TextWindow.Write("Who goes first (1‐You, 2‐Computer)? ") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto
GetWhoFirst EndIf
If (T = 1) Then YouGoFirst = "true"
Else
YouGoFirst = "false"
EndIf
GetSmart: TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("Computer can make random moves or smart
moves.") TextWindow.CursorLeft = 3
TextWindow.Write("What do you want (1‐Random, 2‐Smart)? ") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto GetSmart
EndIf
If (T = 2) Then SmartComputer = "true"
Else
SmartComputer = "false"
EndIf
EndIf
SetTitle() TextWindow.Hide() GraphicsWindow.Show() EndSub

Sub StartGame GameStatus = "Playing"


XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() 'clear boxes
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor For
I = 1 To 9
BoxMark[I] = ""
GraphicsWindow.FillRectangle(BoxX[I] ‐ 5, BoxY[I] ‐ 5, 90, 90)
EndFor
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton) Controls.HideControl(ExitButton)
NumberClicks = 0
If (NumberPlayers = 1 And YouGoFirst = "false") Then ComputerTurn()
EndIf
EndSub

Sub StopGame 'restore buttons


GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton) DisplayMessage() EndSub

Sub MouseDownSub If (GameStatus = "Playing") Then 'find which box


was clicked x = GraphicsWindow.MouseX
y = GraphicsWindow.MouseY
ClickedBox = 0
For I = 1 To 9
If (x > BoxX[I] And x < BoxX[I] + 80) Then If (y > BoxY[I]
And y < BoxY[I] + 80) Then ClickedBox = I Goto GotIt EndIf
EndIf
EndFor
GotIt: If (ClickedBox <> 0) Then 'if already clicked then exit If
(BoxMark[ClickedBox] <> "") Then Goto LeaveSub EndIf
MarkAndCheck() EndIf
EndIf
LeaveSub: EndSub

Sub MarkAndCheck NumberClicks = NumberClicks + 1


If (XTurn) Then BoxMark[ClickedBox] = "X"
DrawX() XTurn = "false"
Message = "O's Turn"
MessageX = 115
DisplayMessage() Else
BoxMark[ClickedBox] = "O"
DrawO() XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() EndIf
'check for win ‐ will establish a value for WhoWon CheckForWin() If
(WhoWon <> "") Then Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav") Message = WhoWon + "
Wins!"
MessageX = 115
StopGame() ElseIf (NumberClicks = 9) Then 'draw
Sound.Stop(Program.Directory + "\beep.wav")
Sound.Play(Program.Directory + "\beep.wav") Message = "It's a
Draw!"
MessageX = 95
StopGame() EndIf
If (NumberPlayers = 1 And WhoWon = "") Then If (XTurn = "true" And
YouGoFirst = "false") Or (XTurn = "false" And YouGoFirst = "true")
Then ComputerTurn() EndIf
EndIf
EndSub

Sub DrawX
'draw blue X at ClickedBox GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 10
GraphicsWindow.DrawLine(BoxX[ClickedBox], BoxY[ClickedBox],
BoxX[ClickedBox] + 80, BoxY[ClickedBox] + 80)
GraphicsWindow.DrawLine(BoxX[ClickedBox], BoxY[ClickedBox] +
80, BoxX[ClickedBox] + 80, BoxY[ClickedBox]) EndSub

Sub DrawO
'draw blue O at Clicked Box GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 10
GraphicsWindow.DrawEllipse(BoxX[ClickedBox], BoxY[ClickedBox],
80, 80) EndSub

Sub CheckForWin WhoWon = ""


'check all possible for wins For I = 1 To 8
For J = 1 To 3
BoxNumber[J] = Text.GetSubText(PossibleWins[I], J, 1) Mark[J]
= BoxMark[BoxNumber[J]]
EndFor
If (Mark[1] = Mark[2] And Mark[1] = Mark[3] And Mark[2] =
Mark[3] And Mark[1] <> "") Then 'we have a winner
WhoWon = Mark[1]
For J = 1 To 3
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.FillRectangle(BoxX[BoxNumber[J]] ‐ 5,
BoxY[BoxNumber[J]] ‐ 5, 90, 90) ClickedBox =
BoxNumber[J]
If (WhoWon = "X") Then DrawX() Else
DrawO() EndIf
EndFor
EndIf
EndFor
EndSub

Sub ComputerTurn If (SmartComputer <> "true") Then 'random logic


'put mark in Nth available square N = Math.GetRandomNumber(9 ‐
NumberClicks) I = 0
For ClickedBox = 1 To 9
If (BoxMark[ClickedBox] = "") Then I = I + 1
If I = N Then Goto GotMark EndIf
EndIf
EndFor
GotMark: 'put mark in ClickedBox
MarkAndCheck() Else
'smart computer
BestMoves[1] = 5
BestMoves[2] = 1
BestMoves[3] = 3
BestMoves[4] = 7
BestMoves[5] = 9
BestMoves[6] = 2
BestMoves[7] = 4
BestMoves[8] = 6
BestMoves[9] = 8
'determine who has what mark If (YouGoFirst) Then ComputerMark
= "O"
PlayerMark = "X"
Else
ComputerMark = "X"
PlayerMark = "O"
EndIf
'Step 1 (K = 1) ‐ check for win ‐ see if two boxes hold computer mark
and one is empty 'Step 2 (K = 2) ‐ check for block ‐ see if two boxes
hold player mark and one is empty For K = 1 To 2
If K = 1 Then MarkToFind = ComputerMark Else
MarkToFind = PlayerMark EndIf
For I = 1 To 8
N=0
EmptyBox = 0
For J = 1 To 3
BoxNumber[J] = Text.GetSubText(PossibleWins[I], J, 1)
Mark[J] = BoxMark[BoxNumber[J]]
If (Mark[J] = MarkToFind) Then N = N + 1
ElseIf (Mark[J] = "") Then EmptyBox = BoxNumber[J]
EndIf
EndFor
If (N = 2 And EmptyBox <> 0) Then 'mark empty box to win
(K = 1) or block (K = 2) ClickedBox = EmptyBox
MarkAndCheck() Goto LeaveComputerMove EndIf
EndFor
EndFor
'Step 3 ‐ find next best move For I = 1 To 9
If (BoxMark[BestMoves[I]] = "") Then ClickedBox =
BestMoves[I]
MarkAndCheck() Goto LeaveComputerMove EndIf
EndFor
EndIf
LeaveComputerMove: EndSub
Tic Tac Toe Game Program Review The Tic Tac Toe game program
is now complete. Save and Run the program and make sure it works as
promised. Check that all options work correctly.

If there are errors in your implementation, go back over the steps of


window and code design. Go over the developed code – make sure you
understand how different parts of the program were coded. As mentioned in
the beginning of this chapter, the completed program is saved as TicTacToe
in the KidGamesSB\KidGamesSB Programs\TicTacToe folder.

While completing this program, new concepts and skills you should have
gained include:

➢ Proper steps in program design.


➢ More practice in using subroutines.
➢ How to give the computer intelligence in playing games.
Tic Tac Toe Game Program Enhancements There are several ways
to improve the Tic Tac Toe game. Some possibilities are:

➢ Use images in the grid. With such a change, you could use something
other than X’s and O’s to mark the squares. Try using small digital
photos (jpeg files).
➢ Add better messaging with a computer opponent. As implemented,
the computer quickly makes its move. Perhaps, add a delay (see the
Timer object) and perhaps some color changes in the grid so the
computer has time to tell you where its move will be.
➢ In the current computer logic (Step 3), the computer always picks
corners or sides in the same order. To make things a bit more
unpredictable, add logic so the computer makes corner or side moves
randomly based on the number of corner or side boxes that are
empty.
➢ The computer in this game is pretty smart, but can be made smarter.
Between Steps 2 and 3 in the current computer logic, we could add
another step where the computer would be more aggressive. In this
new step, have the computer search for horizontal, vertical or
diagonal lines with one of its markers and two empty squares. By
choosing one of the empty squares, the computer forces your next
move. Even better is to find a place where with an additional mark,
the computer sets up two wins, making it impossible for you to block
him.
➢ For little kids, maybe the computer is a bit too smart. The random
computer is an option, but goes to the other extreme of maybe not
being smart enough. A change would be to add levels of intelligence
– having the computer use its ‘smart’ logic sometimes and its
‘random’ logic sometimes. To do this, you could generate a random
number from 1 to 100 and based on some threshold, determine
whether to make a smart move or random move. By varying the
threshold, you can make the computer extremely smart or not so
smart. We implement such logic in the next game program, Match
Game.
7. Match Game Program
Review and Preview

The next program we build is a Match Game. This is a one or two


player game - play against a friend, the computer, or play alone. Ten
pairs of photos (you can use your own photos) are hidden on a
playing board. The object of the game is to find matching pairs by
remembering photo locations. We’ll see how to generate an array of
random integers and how to use the Timer object for delays.
Match Game Program Preview

In this chapter, we will build a Match Game. Ten pairs of photos are
hidden on a playing board. The object is to find matching pairs. Turns
alternate between players – an extra turn is earned with each match. The
version we build here allows two players to compete against each other or
to have a single player play a solitaire version or compete against the
computer.

The finished program is saved as MatchGame in the


KidGamesSB\KidGamesSB Programs\MatchGame folder. Start Small
Basic and open the finished program. Run the program (click the Run
toolbar button or press <F5>). The game will appear in its ‘stopped’ state.
At this point, you can click the Start Game button to start the game, click
Change Options to change program options or click Exit to exit the
program.
Click Change Options to change options. A text window will appear:

There are a few options to choose. First, decide if you want one or two
players. If you choose one player, you next decide if you want to play alone
or play the computer. If playing the computer, as a last choice, you decide
how smart you want the computer to be (the difficulty). For this example, I
chose a one player game against a fairly smart computer:

After making your choices, the graphics window reappears with the game
still in the ‘stopped’ state.
Note the title bar reflects the options choices.

Click the Start Game button to start playing. The button choices change.
The message area says Pick a Box. When playing the computer, you go
first.
In this state, you pick two boxes to see what photos are behind them. If
there is a match, a ‘tada’ sound will be heard, the boxes are removed, your
score incremented and you are given another turn. If there is no match, a
different sound is heard, the boxes are recovered and it becomes the
computer’s turn. Play continues in this manner (alternating turns) until all
the matching photos are found or until Stop Game is clicked. Play is
similar for a two player game, alternating turns between the two people
playing. For a one player game, playing alone, the computer keeps track of
how many tries it takes you to find all 10 pairs of photos.
I selected the first two boxes and see:

It’s Seattle’s baseball field and one of my dogs; nice photos, but not a
match. I hear a ‘boing’ sound and the board returns to it’s covered state. You
will most likely see different photos when you run the game because we are
using random numbers.
It then becomes the computer’s turn. It’s choices are:

It’s two dogs – not a match. But, I recognize one of those dogs.

Picking the second box in the top row and the third box in the second row, I
get a match. The photos are removed, my score is incremented and it’s my
turn again:

The game continues in this same manner, alternating turns between you and
the computer. When there is a match, you or the computer get an additional
turn. I continued playing this game against a pretty smart computer. Once
all the matches were found, the final score was me 6 and the computer 4. I
won!
Notice the game returns to its stopped state to allow another game, change
options or to stop the program by clicking Exit.

Continue playing the game to understand its operation. Try using the two
player game and the one player game where you Play Alone. Or, in the one
player game against the computer, try different levels of difficulty. You will
find at the Hardest level, the computer is nearly impossible to beat. Click
Exit when you’re done to stop the game. Look over the code, if you like.

You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.

We address both window design and code design. We discuss how to


display the pairs of pictures, check for a match, handle multiple players, and
decide how to make computer-generated moves. We also discuss how to
“scramble” the photos and the use of the Timer object.
Match Game Window Design

Here is a sketch for the window layout for the Match Game program:

The window used in this program is fairly large. We assume the photos you
use for the game are standard 4 x 6 photos, in landscape mode (width is
greater than height). We use 20 rectangular regions to display the photos in
the window. Identifying numbers are given to each box. These rectangles
are 150 pixels wide (BoxW) by 100 pixels high (BoxH) to maintain the
height-to-width ratio of the photos. On the right side of the pictures are
areas to keep score and display messages. Three button controls will be
used: one to start and stop the game, one to change options and one to exit
the program..

We will now begin writing code for the Match Game program. After
writing code for the first two programs, Safecracker and Tic Tac Toe, you
should know there are certain standard steps needed to get a working
program. Since you should be familiar with these steps by now, in
discussing the code for Match Game, we will combine some steps to speed
up the coding process.
We will write the code in several steps. As a first step, we will write the
code that initializes the game. We look at adding photos. Then, we look at
going from ‘stopped’ state to ‘playing’ state and back. During the code
development process, recognize you may modify a particular subroutine
several times before arriving at the finished product.

Start a new program in Small Basic. Once started, we suggest you


immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Draw Picture Boxes

The first thing we need to do is draw the twenty picture boxes on the left
side of the window. The boxes are initially drawn with a cover graphic. The
file to do this (cover.bmp) is in the KidGamesSB\KidGamesSB
Programs\MatchGame folder. Copy this file to your program’s folder.

Use this code to draw the boxes:

' Match Game


InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 825
GraphicsWindow.Height = 530
GraphicsWindow.BackgroundColor = "LightSkyBlue"
'initialize box locations with covers
Cover = ImageList.LoadImage(Program.Directory + "\cover.bmp")
BoxW = 150
BoxH = 100
x=5
y=5
For I = 1 To 20
BoxX[I] = x BoxY[I] = y
GraphicsWindow.DrawResizedImage(Cover, BoxX[I], BoxY[I],
BoxW, BoxH) x = x + BoxW + 5
If (x > 4 * BoxW) Then x = 5
y = y + BoxH + 5
EndIf
EndFor
EndSub

The first line of code calls a subroutine InitializeProgram where we will


put all code needed to set up the program for use. All remaining code here
goes in that subroutine. The location arrays (BoxX and BoxY) and size of
the twenty rectangles used to display photos are established.

Save and Run the program. The boxes should appear nicely arranged:

If the cover graphic does not appear, make sure it is in your program’s
folder.
Window Design – Scores

The next elements to add to the window are the scores with corresponding
heading information. Add this code to InitializeProgram for the headings:
'headings
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
Heading[1] = Shapes.AddText("Player 1") Heading[2] =
Shapes.AddText("Player 2") Shapes.Move(Heading[1], 670, 5)
Shapes.Move(Heading[2], 670, 70) The headings are displayed using two
Shapes objects (Heading[1] and Heading[2]). Then, add the code to
display the scores (Score[1] and Score[2]): 'scores
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(670, 35, 100, 25)
GraphicsWindow.FillRectangle(670, 100, 100, 25)
GraphicsWindow.BrushColor = "Black"
Score[1] = 0
Score[2] = 0
ScoreDisplay[1] = Shapes.AddText(Score[1]) ScoreDisplay[2] =
Shapes.AddText(Score[2]) Shapes.Move(ScoreDisplay[1], 715, 35)
Shapes.Move(ScoreDisplay[2], 715, 100) Similar to the headings, we use
two Shapes objects (ScoreDisplay[1] and ScoreDisplay[2]) placed over
white rectangles to display the scores.
Save and Run. The scores and headings have been added to the window:
Window Design – Message Area

A message area is used to inform the player(s) what to do next. Add this
code to InitializeProgram: 'Draw message area
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FillRectangle(630, 250, 185, 45)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawRectangle(630, 250, 185, 45)
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 18
Message = "Game Stopped"
MessageX = 30
MessageArea = Shapes.AddText(Message) DisplayMessage() The
message to display is Message and its horizontal location is MessageX.
A Shapes object (MessageArea) displays the message in a black
bordered, yellow rectangle.

The subroutine DisplayMessage writes the message. Add this to your code:
Sub DisplayMessage Shapes.Move(MessageArea, 630 + MessageX, 260)
Shapes.SetText(MessageArea, Message) EndSub

Save and Run the program. You should see the initial ‘Game Stopped’
message:
Window Design – Add Buttons

The final item we need are three button controls used to start/stop the game,
change options and exit the program.

Add this code at the end of InitializeProgram: 'define buttons


GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
StartStopButton = Controls.AddButton("Start Game", 630, 410)
OptionsButton = Controls.AddButton("Change Options", 630, 450)
ExitButton = Controls.AddButton("Exit", 630, 490) Save and Run the
program. The finished window is displayed:

We establish three buttons (StartStopButton, OptionsButton,


ExitButton). The window design is complete.
Code Design – Initializing Stopped State

Any time we start a program, there are certain initializations that must take
place. Let’s look at the initializations needed in the Match Game. All
initializations are done in the first part of the program code (before any
subroutines).

We want to initialize the program options and use this to update the window
title. The options are the number of players (NumberPlayers), whether a
single player plays alone (PlayAlone) and how difficult you want a game
against the computer to be (Difficulty). Add this code to
InitializeProgram: 'Default Options
NumberPlayers = 2
PlayAlone = "true"
Difficulty = 1
SetTitle() GameStatus = "Stopped"

The option variables are initialized as is the window title based on the
options (using subroutine SetTitle). The GameStatus is set to “Stopped”.

The subroutine SetTitle is also needed: Sub SetTitle If (NumberPlayers =


1) Then GraphicsWindow.Title = "Match Game ‐ 1 Player, "
If (PlayAlone) Then GraphicsWindow.Title =
GraphicsWindow.Title + "Play Alone"
Else
GraphicsWindow.Title = GraphicsWindow.Title + "Play
Computer"
EndIf
Else
GraphicsWindow.Title = "Match Game ‐ 2 Players"
EndIf
EndSub
A different title is displayed based selected options.

Save and Run the program. You’ll see in the ‘stopped’ state (using default
properties), the Match Game looks like this:

Make sure you see how all these components were created in the code. As
desired, the game initializes in Two Players mode.

We have three choices at this point – either click Start Game to start, click
Change Options to change options, or click Exit to exit the program. We
will write code for each of these options in reverse order.

First, we need to be able to detect button clicks so add this line at the end of
InitializeProgram: Controls.ButtonClicked = ButtonClickedSub With this,
each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.

The code for exiting is simple. It is placed in the ButtonClickedSub


subroutine: Sub ButtonClickedSub B = Controls.LastClickedButton If
(GameStatus = "Stopped") Then If (B = ExitButton) Then Program.End()
EndIf
EndIf
EndSub

This simply says whenever Exit is clicked, the program ends. Run the
program. Click Exit to make sure the game stops.

If the user clicks Change Options, we want to provide the ability to change
program options. We will use the Small Basic text window to establish
game options. Add the shaded code to the ButtonClickedSub subroutine:
Sub ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =
"Stopped") Then If (B = ExitButton) Then Program.End()
ElseIf (B = OptionsButton) Then SetOptions()
EndIf
EndIf
EndSub

The options are set in the SetOptions subroutine – add this routine: Sub
SetOptions GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title
= "Match Game"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("MATCH GAME OPTIONS")
TextWindow.WriteLine("") GetPlayers: TextWindow.CursorLeft = 3
TextWindow.WriteLine("With one player, you play alone or against
the computer.") TextWindow.CursorLeft = 3
TextWindow.WriteLine("With two players, you play against a
friend.") TextWindow.CursorLeft = 3
TextWindow.Write("How many players do you want (1 or 2)? ")
NumberPlayers = TextWindow.ReadNumber() If (NumberPlayers < 1
Or NumberPlayers > 2) Then Goto GetPlayers EndIf
If (NumberPlayers = 1) Then Heading[1] = "You"
GetPlayAlone: TextWindow.WriteLine("")
TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can play alone or play the
computer.") TextWindow.CursorLeft = 3
TextWindow.Write("Make your choice (1‐Play Alone, 2‐Play
Computer)? ") T = TextWindow.ReadNumber() If (T < 1 Or T >
2) Then Goto GetPlayAlone EndIf
If (T = 1) Then PlayAlone = "true"
Heading[2] = "Guesses"
Else
PlayAlone = "false"
Heading[2] = "Computer"
GetDifficulty: TextWindow.WriteLine("")
TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can set the game difficulty.")
TextWindow.CursorLeft = 3
TextWindow.Write("Make your choice (1‐Easiest, 2‐Easy, 3‐
Hard, 4‐Hardest)? ") Difficulty = TextWindow.ReadNumber()
If (Difficulty < 1 Or Difficulty > 4) Then Goto GetDifficulty
EndIf
EndIf
Else
Heading[1] = "Player 1"
Heading[2] = "Player 2"
EndIf
SetTitle() DisplayHeadings() TextWindow.Hide()
GraphicsWindow.Show() EndSub

This routine hides the graphics window, displays a text window and asks
the user questions necessary to establish the three options
(NumberPlayers, PlayAlone, Difficulty). Note, if two players are selected,
there is no need to ask if you want to play alone or against the computer. If
playing alone, there is no need to ask how difficult you want the game to
be. Values are established for the score headings. For two players, the two
scoring boxes on the right of the window are headed Player 1 and Player 2.
For one player, the top scoring box is headed You. If playing alone, the
second is headed Guesses. If playing the computer, it is headed Computer.
Once the questions are answered, the program returns to the game in
‘stopped’ state.

Save and Run the program. Click the Change Options button the change
options:

Make your choices and press Enter after each. The Match Game window
will again appear.

Make sure the proper titling information appears based on your choices.
Here’s the window for two players (the default option):
Here’s the window for one player, playing alone:
And, here’s the window for one player, playing the computer:

The code for clicking the Start Game button (to start the game) is much
more complicated. We will build it in several steps. First, let’s look at
adding photos to the game. Then, we look at switching the game from
stopped to playing state.
Code Design – Adding Photos

One neat thing about this game is that you can use your own photos! This
personalizes the game that makes things a lot more fun. You need to select
10 photos (jpg files from your digital camera) that you want to use - make
sure these photos are stored somewhere on your computer. It works best if
they are Iandscape mode (wider than tall). If you don’t have photos to use,
we include ten sample photos in the KidGamesSB\KidGamesSB
Programs\MatchGame folder:

clara.jpg one of the KIDware dogs


toby.jpg the other KIDware dog
Blue hills.jpg a stock photo of hills
Sunset.jpg a stock sunset photo
Water lilies.jpg some pretty flowers
Winter.jpg a winter scene
spaceneedle.jpg the Space Needle in Seattle
market.jpg the Pike Place Market in Seattle
safeco.jpg Safeco Field in Seattle, home of the Mariners
qwest.jpg Qwest Field in Seattle, home of the Seahawks

We will use these samples to demonstrate the steps needed to select photos.
And, these photos are used through the rest of this chapter to demonstrate
game play.

To use the sample photos, first copy the ten files to your program’s folder.
Next, find this line in the InitializeProgram subroutine: GameStatus =
"Stopped"

Add this code after this line:

'load images
Photo[1] = ImageList.LoadImage(Program.Directory + "\clara.jpg")
Photo[2] = ImageList.LoadImage(Program.Directory + "\toby.jpg")
Photo[3] = ImageList.LoadImage(Program.Directory + "\Blue hills.jpg")
Photo[4] = ImageList.LoadImage(Program.Directory + "\Sunset.jpg")
Photo[5] = ImageList.LoadImage(Program.Directory + "\Water
lilies.jpg") Photo[6] = ImageList.LoadImage(Program.Directory +
"\Winter.jpg") Photo[7] = ImageList.LoadImage(Program.Directory +
"\spaceneedle.jpg") Photo[8] = ImageList.LoadImage(Program.Directory
+ "\market.jpg") Photo[9] = ImageList.LoadImage(Program.Directory +
"\safeco.jpg") Photo[10] = ImageList.LoadImage(Program.Directory +
"\qwest.jpg") This loads the photos from your program file into memory.
To use your own photos, simply copy them to your program’s folder, then
change the lines of code above to reference your photo file names rather
than the sample files.

Let’s check to make sure the photos loaded in correctly. Add these test lines
of code after the above lines: For I = 1 To 10
GraphicsWindow.DrawResizedImage(Photo[I], BoxX[I], BoxY[I],
BoxW, BoxH) EndFor

This code displays the ten photos in the first 10 rectangular photo boxes.

Save and Run the program. The photos should appear. If they don’t, make
sure they are in your program’s folder and the file names match the code.
Here are the samples:

Delete the lines that display the photos.

We’re nearly ready to begin looking at the code behind the Start Game
button. A key step in starting this game is to ‘hide’ two copies of each photo
behind the 20 picture boxes. There are 10 photos, represented in the array
Photo, with indices from 1 to 10. We want to randomly place two copies of
each index in another array (with 20 elements). The elements of this second
array tell us which photo is behind which picture box. We need some way to
shuffle integer indices around. This is actually a very common game task
which can be used for shuffling cards, selecting multiple choice answers, or
here to hide photos. We will build a subroutine to perform this task.
Code Design – Integer Shuffling

We will be presenting code for a shuffle process, so called because it can be


used to shuffle a deck of cards. Here, we’ll just be shuffling 20 “cards,”
though the code can be generalized to any number of “cards.” You might be
asking, why we are shuffling 20 values, not 10, since we only have 10
photos? We need two copies of each of the 10 photo indices, hence there are
20 total items being shuffled. We propose randomly shuffling the integers
from 1 to 20. After the shuffle, for any value greater than 10, we will
subtract 10. This will give us a list of 20 random integers. This list will have
two of each index from 1 to 10, telling us which photo is behind which
picture box. Let’s see how to do this.

Usually when we need a computer version of something we can do without


a computer, it is fairly easy to write down the steps taken and duplicate
them in code. When we shuffle a deck of cards, we separate the deck in two
parts, then interleaf the cards as we fan each part, making that familiar
shuffling noise. I don’t know how you could write code to do this. We’ll
take another approach which is hard or tedious to do off the computer, but is
easy to do on a computer.

We perform what is called a “one card shuffle.” In a one card shuffle, you
pull a single card (at random) out of the deck and lay it aside on a pile.
Repeat this 52 times and the cards are shuffled. Try it! I think you see this
idea is simple, but doing a one card shuffle with a real deck of cards would
be awfully time-consuming. We’ll use the idea of a one card shuffle here,
with a slight twist. Rather than lay the selected card on a pile, we will swap
it with the bottom card in the stack of cards remaining to be shuffled. This
takes the selected card out of the deck and replaces it with the remaining
bottom card. The result is the same as if we lay it aside.

Here’s how the shuffle works with N numbers:

➢ Start with a list of N consecutive integers.


➢ Randomly pick one item from the list. Swap that item with the last
item. You now have one fewer items in the list to be sorted (called
the remaining list), or N is now N - 1.
➢ Randomly pick one item from the remaining list. Swap it with the
item on the bottom of the remaining list. Again, your remaining list
now has one fewer items.
➢ Repeatedly remove one item from the remaining list and swap it with
the item on the bottom of the remaining list until you have run out of
items. When done, the list will have been replaced with the original
list in random order.

The code to do a one card shuffle, or sort N integers, is placed in a


subroutine named NRandomIntegers. Before calling the subroutine,
establish a value for N, the number of integers to sort. The subroutine
places the randomly sorted integers an array named NIntegers. The code is:
Sub NRandomIntegers 'Order all elements initially
For I = 1 To N
NIntegers[I] = I EndFor
'J is the number of integers remaining For J = N To 2 Step ‐1
I = Math.GetRandomNumber(J) T = NIntegers[J]
NIntegers[J] = NIntegers[I]
NIntegers[I] = T
EndFor
EndSub

You should be able to see each step of the shuffle subroutine. This
subroutine is general (sorting N integers) and can be used in other programs
requiring random lists of integers.

Add the NRandomIntegers subroutine to your Match Game program. It


will be used to hide the 10 photos behind the 20 picture boxes. In the
program, we will use an array PhotoIndex (dimensioned to 20) to hold the
randomly sorted integers (the shuffled photo indices). The snippet of code
that does a shuffle (and adjusts the values greater than 10) is: N = 20
NRandomIntegers() PhotoIndex = NIntegers For I = 1 To 20
If (PhotoIndex[I] > 10) Then PhotoIndex[I] = PhotoIndex[I] ‐ 10
EndIf
EndFor

Let’s look at an example of how this works. If I run this snippet of code
through a little example, the 20 elements of PhotoIndex computed in one
particular call to NRandomIntegers are (arranged like our photo boxes):

You should see all the integers from 1 to 20. Now, subtracting 10 from each
value greater than 10 yields:

As desired, we now have random pairs of the integers from 1 to 10.


Matching pairs of integers represent matching pairs of photos in Match
Game.

How do we know what photo is behind what picture box? Recall the 20
boxes are identified by these values:
Say we have a picture box, represented by index I. To determine the photo,
examine PhotoIndex[I]; call this value J. The photo behind this picture box
is then Photo[J], element J of the array holding the 10 photos being used.
To display this photo, the proper line of code is:
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[I]], BoxX[I],
BoxY[I], BoxW, BoxH) We can now use the shuffling function to start
building the code behind clicking the Start Game button to start.
Code Design – Stopped to Playing to Stopped State In the
Safecracker and Tic Tac Toe programs, we used the same button
(StartStopButton) to both start and stop the game. That is also the case
here. We will look at the code to both start and stop the game.

When the user clicks the Start Game button in the ‘stopped’ state, several
things must happen to switch Match Game to ‘playing’ state:

➢ Change the GameStatus to “Playing”


➢ Change the caption of StartStopButton to Stop Game.
➢ Hide OptionsButton and ExitButton.
➢ Initialize scores and corresponding displays to zero.
➢ Initialize number of photos remaining (PhotosRemaining = 20).
➢ Shuffle photos using NRandomIntegers subroutine.
➢ Initialize picture boxes for displaying photos.
➢ Establish this as Player 1’s turn.
➢ Set message to player.
➢ Allow player to click on picture boxes.

Conversely, when the user clicks the Stop Game button in ‘playing’ state,
these things must happen to switch Match Game to ‘stopped’ state:

➢ Change the GameStatus to “Stopped”


➢ Display Game Stopped message.
➢ Stop allowing clicking on picture boxes.
➢ Change the caption of StartStopButton to Start Game.
➢ Show OptionsButton and ExitButton.

First, let’s look at the code to start the game. We use several variables to
help keep track of where we are in the game. PhotosRemaining tells us
how many photos are still hidden, while the Score array holds the two
players scores (number of matched photos found). The PhotoFound array
tells us whether a photo behind the corresponding picture box has been
uncovered (so it can’t be clicked twice). PlayerNumber tells us whose turn
it is and ChoiceNumber tells whether it is the player’s first choice on the
playing board or second choice. The Choice array holds the indices of the
two picture boxes selected. CanClick is used to determine if it’s okay to
click on the picture boxes. It is “true” when playing, “false” (the initial
value) when stopped. We use this to make sure only two boxes are clicked.

Add the shaded code to the ButtonClickedSub subroutine (and the


corresponding StartGame subroutine) to implement the steps for clicking
Start Game to start a game and initializes the new variables is: Sub
KeyDownSub K = Text.ConvertToUpperCase(GraphicsWindow.LastKey)
If (GameStatus = "Stopped") Then If (K = "E") Then Program.End()
ElseIf (K = "C") Then SetOptions()
ElseIf (K = "S") Then StartGame()
EndIf
EndIf
EndSub

Sub StartGame GameStatus = "Playing"


'clear screen
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(0, 0, 625, 530) Score[1] = 0
Score[2] = 0
UpdateScores() PhotosRemaining = 20
N = 20
NRandomIntegers() PhotoIndex = NIntegers For I = 1 To 20
If (PhotoIndex[I] > 10) Then PhotoIndex[I] = PhotoIndex[I] ‐ 10
EndIf
PhotoFound[I] = "false"
GraphicsWindow.DrawResizedImage(Cover, BoxX[I], BoxY[I],
BoxW, BoxH) EndFor
PlayerNumber = 1
ChoiceNumber = 1
If (NumberPlayers = 1) Then Message = "Pick a Box"
MessageX = 45
Else
Message = "Player 1, Pick a Box"
MessageX = 10
EndIf
DisplayMessage() 'reset buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton)
Controls.HideControl(ExitButton) CanClick = "true"
EndSub

The steps follow should be clear. Note especially where the “shuffling”
routine was used to form the PhotoIndex array.
Save and Run the program. Click Start Game and you should see:

The only noticeable changes are the two player message in the message
area (Player 1, Pick a Box) and the single button. Stop the program (you
can’t click Stop Game to stop yet) and try the other options if you’d like.

Add the shaded code to the KeyDownSub subroutine (and associated


StopGame subroutine) that implements the steps for clicking Stop Game
to stop: Sub ButtonClickedSub B = Controls.LastClickedButton If
(GameStatus = "Stopped") Then If (B = ExitButton) Then Program.End()
ElseIf (B = OptionsButton) Then SetOptions() ElseIf (B =
StartStopButton) Then StartGame() EndIf
ElseIf (GameStatus = "Playing") Then If (B = StartStopButton)
Then 'stop program
Message = "Game Stopped"
MessageX = 30
StopGame() EndIf
EndIf
EndSub
Sub StopGame 'restore buttons
GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton) CanClick = "false"
DisplayMessage() EndSub

Save and Run the program. You should be able to now move from
‘stopped’ to ‘playing’ state and back. Let’s write the code for the two player
game, first looking at how to display a photo following a click on a picture
box.
Code Design – Displaying Photos

In the Match Game two player game, when a player clicks a picture box in
the window, we want the proper photo to appear. After clicking a second
box, another photo is displayed and we see if there is a match. If there is a
match, the photos are removed and the player is given another turn. If there
is no match, the photos are hidden again and we switch to the next player.

So, when a picture box is clicked, we follow these steps:

➢ Make sure the box has not already been clicked.


➢ Display photo.
➢ If first choice, allow second choice and display that photo. Compare
the two photos.
➢ If photos match: o Play matching sound.
o Remove picture boxes with photos from window o Increment
proper player score by 1.
o Decrement PhotosRemaining by 2.
o If PhotosRemaining = 0, determine winner, play game over sound
and stop game.
o If PhotosRemaining <> 0, give player another turn.
➢ If photos do not match: o Play no match sound.
o Replace photos with ‘cover’ graphic.
o Swap players.

To detect mouse clicks, we need this line at the end of InitializeProgram:


GraphicsWindow.MouseDown = MouseDownSub With this, each time a
MouseDown event occurs, the subroutine named MouseDownSub is
called. The code to perform the steps above will be in this subroutine.

Notice in the above steps, we refer to playing sounds. In previous games,


we added sounds at the very end. We know all games use sounds so, from
now on, they will be added when needed in programs. We use three sounds
in this game. In the KidGamesSB\KidGamesSB Programs\MatchGame
folder are three wav files that can be used for sound. The tada.wav file is a
sound we’ll use when two photos match. The boing.wav file is used when
there is no match. And, the wow.wav sound is used when a game is over.
Copy the three sound files to your program’s folder.

Add this subroutine (MouseDownSub) to your program. This implements


the steps to accept clicking of the picture boxes: Sub MouseDownSub If
(GameStatus = "Playing" And CanClick) Then 'find which box was clicked
x = GraphicsWindow.MouseX
y = GraphicsWindow.MouseY
BoxNumber = 0
For I = 1 To 20
If (x > BoxX[I] And x < BoxX[I] + BoxW) Then If (y >
BoxY[I] And y < BoxY[I] + BoxH) Then BoxNumber = I
Goto GotIt EndIf
EndIf
EndFor
GotIt: If (BoxNumber <> 0) Then 'if already clicked then exit
If (PhotoFound[BoxNumber]) Then Goto
LeaveMouseDownSub EndIf
ShowPhotoAndCheck() EndIf
EndIf
LeaveMouseDownSub: EndSub

The first part of the code determines which picture box (if any) was clicked
(the variable BoxNumber). If it was already clicked, the subroutine is
exited. If an acceptable value, another subroutine (ShowPhotoAndCheck)
is called to show the picture and check for a match.

Add this subroutine (ShowPhotoAndCheck) to your program. This


implements the needed steps to accept a player’s selection of photo pairs:
Sub ShowPhotoAndCheck 'show image behind selected Photo box
(BoxNumber)
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[BoxNumber]],
BoxX[BoxNumber], BoxY[BoxNumber], BoxW, BoxH)
PhotoFound[BoxNumber] = "true"
If (ChoiceNumber = 1) Then Choice[1] = BoxNumber
ChoiceNumber = 2
If (NumberPlayers = 2) Then Message = "Player " +
PlayerNumber + ", Pick Another"
MessageX = 5
DisplayMessage() Else
'one player logic
EndIf
Else
CanClick = "false"
Choice[2] = BoxNumber ChoiceNumber = 1
If (PhotoIndex[Choice[1]] = PhotoIndex[Choice[2]]) Then 'a
match
Sound.Stop(Program.Directory + "\tada.wav")
Sound.PlayAndWait(Program.Directory + "\tada.wav") 'blank
out boxes
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.FillRectangle(BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) Score[PlayerNumber] =
Score[PlayerNumber] + 1
UpdateScores() PhotosRemaining = PhotosRemaining ‐ 2
If (PhotosRemaining = 0) Then
Sound.Stop(Program.Directory + "\wow.wav")
Sound.Play(Program.Directory + "\wow.wav") If
(NumberPlayers = 2) Then If (Score[1] > Score[2]) Then
Message = "Player 1 Wins!"
MessageX = 30
ElseIf (Score[2] > Score[1]) Then Message = "Player
2 Wins!"
MessageX = 30
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
Else
'one player logic
EndIf
StopGame() EndIf
'another turn?
If (PhotosRemaining <> 0) Then If (NumberPlayers = 2)
Then Message = "Player " + PlayerNumber + ", Pick Again"
MessageX = 10
DisplayMessage() Else
'one player logic
EndIf
EndIf
Else
'no match
Sound.Stop(Program.Directory + "\boing.wav")
Sound.PlayAndWait(Program.Directory + "\boing.wav")
PhotoFound[Choice[1]] = "false"
PhotoFound[Choice[2]] = "false"
GraphicsWindow.DrawResizedImage(Cover,
BoxX[Choice[1]], BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.DrawResizedImage(Cover,
BoxX[Choice[2]], BoxY[Choice[2]], BoxW, BoxH) 'swap
players
If (NumberPlayers = 2) Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
Message = "Player " + PlayerNumber + ", Pick a Box"
<</p> span class="textStyle37">MessageX = 10
DisplayMessage() Else
'one player logic
EndIf
EndIf
CanClick = "true"
EndIf
EndSub

I know this is a lot of code to throw at you at once, but it’s simply a
straightforward implementation of the listed steps. Now that you’re
becoming a great game programmer, you should be able to follow the logic.
It’s similar to that used in the Tic Tac Toe game. Clicking any of the twenty
picture boxes used to display photos will invoke this subroutine. The first
part of the code determines the index of the picture box that was clicked
(the variable BoxNumber). If the box has already been clicked (or
CanClick is “false”), the subroutine is exited. Otherwise, the photo behind
the selected box (Photo[PhotoIndex[BoxNumber]]) is displayed. If this is
the first choice (ChoiceNumber = 1), we tell the player to pick again (using
the message area).

Following display of the second choice, we look to see if the two selections
match. The selected boxes are stored in the Choice array. If there is a
match, the photos are removed, a sound is played and we check to see if all
the photos have been selected. If photos remain, the same player is given
another turn. Similarly, for no match, a sound is heard, the photos are
recovered and players are swapped.

All of this code is for a two player game. Notice, however, we have left
“hooks” (represented by comment statements) for later modifications for a
one player game. It looks like everything should work just fine. Run and
Save the program. Click on one picture box. The photo should display.
Here’s my screen:

When you click on a second box, the picture doesn’t display, but the results
are still determined and play switches to Player 2. What happened?

In displaying graphics, Small Basic must refresh the window occasionally.


With the current code, the refresh does not occur before the program checks
for a match, hence the second photo is not seen. We need to slow down the
program a bit to allow the window to refresh. One approach is the Small
Basic Delay method. Unfortunately, this method does not always work –
and it won’t work here. It blocks the refresh process. Try it if you like.

We take a second approach – using the Timer object. This object allows us
to delay processing code (the code is in a subroutine tied to the Timer Tick
event) an amount of time specified by the Timer Interval property. Let’s
make the necessary changes. Once it’s time to display the second picture
box, we will delay for one seconds (1000 milliseconds).

Add this code at the end of InitializeProgram: Timer.Interval = 1000


Timer.Pause() Timer.Tick = TickSub This establishes the Interval,
assigns the TickSub subroutine to the Tick event and turns off the Timer
initially.

Remove the shaded code shown below in the ShowPhotoAndCheck


subroutine and put it in the TickSub subroutine. This is the code that will
be delayed by a second: Sub ShowPhotoAndCheck 'show image behind
selected Photo box (BoxNumber)
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[BoxNumber]],
BoxX[BoxNumber], BoxY[BoxNumber], BoxW, BoxH)
PhotoFound[BoxNumber] = "true"
If (ChoiceNumber = 1) Then Choice[1] = BoxNumber
ChoiceNumber = 2
If (NumberPlayers = 2) Then Message = "Player " +
PlayerNumber + ", Pick Another"
MessageX = 5
DisplayMessage() Else
'one player logic
EndIf
Else
CanClick = "false"
Choice[2] = BoxNumber ChoiceNumber = 1
If (PhotoIndex[Choice[1]] = PhotoIndex[Choice[2]]) Then 'a
match
Sound.Stop(Program.Directory + "\tada.wav")
Sound.PlayAndWait(Program.Directory + "\tada.wav") 'blank
out boxes
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.FillRectangle(BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) Score[PlayerNumber] =
Score[PlayerNumber] + 1
UpdateScores() PhotosRemaining = PhotosRemaining ‐ 2
If (PhotosRemaining = 0) Then
Sound.Stop(Program.Directory + "\wow.wav")
Sound.Play(Program.Directory + "\wow.wav") If
(NumberPlayers = 2) Then If (Score[1] > Score[2]) Then
Message = "Player 1 Wins!"
MessageX = 30
ElseIf (Score[2] > Score[1]) Then Message = "Player
2 Wins!"
MessageX = 30
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
Else
'one player logic
EndIf
StopGame() EndIf
'another turn?
If (PhotosRemaining <> 0) Then If (NumberPlayers = 2)
Then Message = "Player " + PlayerNumber + ", Pick Again"
MessageX = 10
DisplayMessage() Else
'one player logic
EndIf
EndIf
Else
'no match
Sound.Stop(Program.Directory + "\boing.wav")
Sound.PlayAndWait(Program.Directory + "\boing.wav")
PhotoFound[Choice[1]] = "false"
PhotoFound[Choice[2]] = "false"
GraphicsWindow.DrawResizedImage(Cover,
BoxX[Choice[1]], BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.DrawResizedImage(Cover,
BoxX[Choice[2]], BoxY[Choice[2]], BoxW, BoxH) 'swap
players
If (NumberPlayers = 2) Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
Message = "Player " + PlayerNumber + ", Pick a Box"
MessageX = 10
DisplayMessage() Else
'one player logic
EndIf
EndIf
CanClick = "true"
EndIf
EndSub

Add the shaded line to the modified ShowPhotoAndCheck subroutine to


turn on the timer at the proper time: Sub ShowPhotoAndCheck 'show
image behind selected Photo box (BoxNumber)
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[BoxNumber]],
BoxX[BoxNumber], BoxY[BoxNumber], BoxW, BoxH)
PhotoFound[BoxNumber] = "true"
If (ChoiceNumber = 1) Then Choice[1] = BoxNumber
ChoiceNumber = 2
If (NumberPlayers = 2) Then Message = "Player " +
PlayerNumber + ", Pick Another"
MessageX = 5
DisplayMessage() Else
'one player logic
EndIf
Else
CanClick = "false"
Timer.Resume()
EndIf
EndSub

At the top of the TickSub subroutine, add this line turning off the timer
before processing the code: Timer.Pause() To review what we’ve done.
Once it’s time for the second choice of picture, we turn on the timer object.
One second (1000 milliseconds) later, the timer is turned off and the code in
TickSub is executed. This delay allows all pictures to be properly
displayed.

Save and Run the program again. You and a friend should now be able to
play a two player version of Match Game with all pictures appearing
nicely. When a match is found, you will hear a ‘tada’ sound and the photos
will disappear. When no match is found, you will hear a ‘boing’ sound and
the photos will be recovered. When done, you’ll hear a crowd saying
“wow”. Give it a try. I played a two player game by myself. Here’s the
window after five matches have been found (3 by Player 1, 2 by Player 2)
and one box has been uncovered:

Playing the game to completion, the window looks like this, where we
could now select other options and play again:
Player 2 wins! Actually, I was Player 1 and Player 2. In such a case, when
you don’t have a playing partner, it’s fun to play alone or play the computer.
Let’s code up those options now.
Code Design – One Player, Solitaire Game

If the One Player, Play Alone options are selected in Match Game, a
single player tries to find matching photos on the playing form. The
computer keeps track of how many guesses it takes until all matches have
been found.

The steps in the one player, solitaire game following a click on a photo box
are:

➢ Make sure the box has not already been clicked.


➢ Increment number of guesses (use Score[2]) ➢ Display photo.
➢ If first choice, allow second choice and display that photo. Compare
the two photos.
➢ If photos match: o Play matching sound.
o Remove picture boxes with photos from form o Increment number
of matches by 1.
o Decrement PhotosRemaining by 2.
o If PhotosRemaining = 0, play game over sound and stop game.
o If PhotosRemaining <> 0, continue playing.
➢ If photos do not match: o Play no match sound.
o Replace photos with ‘cover’ graphic.
o Continue playing.

To implement these steps, we make a few modifications to the


ShowPhotoAndCheck subroutine and the TickSub subroutine. Those
modifications are shaded: Sub ShowPhotoAndCheck
'one player/solitaire game
If (NumberPlayers = 1 and PlayAlone) Then Score[2] = Score[2] + 1
UpdateScores() EndIf
'show image behind selected Photo box (BoxNumber)
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[BoxNumber
]], BoxX[BoxNumber], BoxY[BoxNumber], BoxW, BoxH)
PhotoFound[BoxNumber] = "true"
If (ChoiceNumber = 1) Then Choice[1] = BoxNumber
ChoiceNumber = 2
If (NumberPlayers = 2) Then Message = "Player " +
PlayerNumber + ", Pick Another"
MessageX = 5
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick Another Box"
MessageX = 25
DisplayMessage() Else
'play computer logic
EndIf
EndIf
Else
CanClick = "false"
Timer.Resume() EndIf
EndSub

Sub TickSub Timer.Pause() Choice[2] = BoxNumber ChoiceNumber = 1


If (PhotoIndex[Choice[1]] = PhotoIndex[Choice[2]]) Then 'a match
Sound.Stop(Program.Directory + "\tada.wav")
Sound.PlayAndWait(Program.Directory + "\tada.wav") 'blank out
boxes
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.FillRectangle(BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) Score[PlayerNumber] =
Score[PlayerNumber] + 1
UpdateScores() PhotosRemaining = PhotosRemaining ‐ 2
If (PhotosRemaining = 0) Then Sound.Stop(Program.Directory +
"\wow.wav") Sound.Play(Program.Directory + "\wow.wav") If
(NumberPlayers = 2) Then If (Score[1] > Score[2]) Then
Message = "Player 1 Wins!"
MessageX = 30
ElseIf (Score[2] > Score[1]) Then Message = "Player 2
Wins!"
MessageX = 30
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
Else
'one player logic
If (PlayAlone) Then Message = "All Matches Found!"
MessageX = 20
Else
'play computer logic
EndIf
EndIf
StopGame() EndIf
'another turn?
If (PhotosRemaining <> 0) Then If (NumberPlayers = 2) Then
Message = "Player " + PlayerNumber + ", Pick Again"
MessageX = 10
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick a Box"
MessageX = 45
DisplayMessage() Else
'play computer logic
EndIf
EndIf
EndIf
Else
'no match
Sound.Stop(Program.Directory + "\boing.wav")
Sound.PlayAndWait(Program.Directory + "\boing.wav")
PhotoFound[Choice[1]] = "false"
PhotoFound[Choice[2]] = "false"
GraphicsWindow.DrawResizedImage(Cover, BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.DrawResizedImage(Cover, BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) 'swap players
If (NumberPlayers = 2) Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
Message = "Player " + PlayerNumber + ", Pick a Box"
MessageX = 10
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick a Box"
MessageX = 45
DisplayMessage() Else
'play computer logic
EndIf
EndIf
EndIf
CanClick = "true"
EndSub
Again, note we have left “hooks” (comment statements) for one player
game versus the computer (play computer logic).

Save and Run the game. Change the options to One Player and Play
Alone. Click Start Game to start the game. Here’s the first box I
uncovered:

I uncovered another, but no match.

From here on, you just keep uncovering photos. The computer keeps track
of how many guesses (photos uncovered) it took you to find all the
matches. Here’s the form once I finished (I did do okay – it took me 46
guesses):

Now, let’s see how to change the game to play against the computer.
Code Design – Computer Moves

It’s time to give some intelligence to the computer, trying to make it a


reasonable opponent in Match Game. Recall in the Tic Tac Toe game, we
had two options for a computer opponent: random or smart. The random
opponent was fairly easy to beat and the smart opponent was impossible to
beat. As an improvement to the Tic Tac Toe game, we suggested graduated
levels of computer intelligence. We will take that approach here.

For Match Game, we will still develop logic for a random choice
(minimum intelligence) and a smart choice (maximum intelligence) by the
computer. To give graduated levels of intelligence, we will decide how
often we want the computer to make a random choice versus how often it
will make a smart choice. That graduated level of intelligence is set as the
Difficulty variable when changing options.

The Difficulty variable can have one of four values: 1-Easiest, 2-Easy, 3-
Hard and 4-Hardest. We will set some rules for intelligence at each level.
Feel free to change these if you’d like. These rules establish what
percentage of computer moves are random and what percentage are smart.
Obviously lower levels of intelligence will have more random choices. The
rules selected are:

Easiest Difficulty: 75% Random, 25% Smart


Easy Difficulty: 50% Random, 50% Smart
Hard Difficulty: 25% Random, 75% Smart
Hardest Difficulty: 10% Random, 90% Smart

So even at the highest level of difficulty, we allow that the computer can
make a mistake.

Let’s build a framework for implementing a computer opponent, then


develop the code for a random or a smart move. We will use a random
number to determine whether a random (SmartComputer is “false”) or
smart (SmartComputer is “true”) move is to be made, based on the value
of Difficulty (initialized at 1, the Easy level). The resulting picture box to
be uncovered will be represented by BoxNumber.

Code two empty subroutines (RandomChoice and SmartChoice) that


determine BoxNumber for the random and smart computer options: Sub
RandomChoice EndSub

Sub SmartChoice EndSub

We’ll add some code to these soon.

Add a subroutine (ComputerTurn) that generates the computer’s selection


based on the selected difficulty and corresponding rules for move
generation: Sub ComputerTurn If (ChoiceNumber = 1) Then If (Difficulty
= 1) Then Threshold = 25
ElseIf (Difficulty = 2) Then Threshold = 50
ElseIf (Difficulty = 3) Then Threshold = 75
Else
Threshold = 90
EndIf
If (Math.GetRandomNumber(100) <= Threshold) Then
SmartComputer = "true"
Else
SmartComputer = "false"
EndIf
EndIf
If (SmartComputer) Then SmartChoice() Else
RandomChoice() EndIf
'have BoxNumber
ShowPhotoAndCheck() EndSub

In this code, if it’s the first choice (ChoiceNumber = 1), we decide whether
we have a smart computer for both computer selections. This is done by
establishing a Threshold (from 1 to 100) based on difficulty. The higher the
threshold, the smarter the computer. We then generate a random number
from 1 to 100. If this number is less than or equal to the threshold, we use a
smart computer (SmartComputer is “true”). In such a case, the
BoxNumber will be found using the SmartChoice subroutine (which has
no code yet). If SmartComputer is “false”, we obtain BoxNumber from
the RandomChoice subroutine (also empty). Once, we know BoxNumber,
we simulate a click on that box by calling the ShowPhotoAndCheck
subroutine.

Lastly, we need to modify the ShowPhotoAndCheck subroutine and the


TickSub subroutine to allow a computer opponent (recall the “hooks” are
marked by comment statements). In a game against the computer, the
computer is Player 2 – you always get to go first. These shaded
modifications simply call ComputerTurn at the proper time and swap
players when appropriate: Sub ShowPhotoAndCheck
'one player/solitaire game
If (NumberPlayers = 1 and PlayAlone) Then Score[2] = Score[2] + 1
UpdateScores() EndIf
'show image behind selected Photo box (BoxNumber)
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[BoxNumber
]], BoxX[BoxNumber], BoxY[BoxNumber], BoxW, BoxH)
PhotoFound[BoxNumber] = "true"
If (ChoiceNumber = 1) Then Choice[1] = BoxNumber
ChoiceNumber = 2
If (NumberPlayers = 2) Then Message = "Player " +
PlayerNumber + ", Pick Another"
MessageX = 5
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick Another Box"
MessageX = 25
DisplayMessage() Else
'play computer logic
Message = "Picking Another"
MessageX = 30
DisplayMessage() ComputerTurn()
EndIf
EndIf
Else
CanClick = "false"
Timer.Resume() EndIf
EndSub

Sub TickSub Timer.Pause() Choice[2] = BoxNumber ChoiceNumber = 1


If (PhotoIndex[Choice[1]] = PhotoIndex[Choice[2]]) Then 'a match
Sound.Stop(Program.Directory + "\tada.wav")
Sound.PlayAndWait(Program.Directory + "\tada.wav") 'blank out
boxes
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.FillRectangle(BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) Score[PlayerNumber] =
Score[PlayerNumber] + 1
UpdateScores() PhotosRemaining = PhotosRemaining ‐ 2
If (PhotosRemaining = 0) Then Sound.Stop(Program.Directory +
"\wow.wav") Sound.Play(Program.Directory + "\wow.wav") If
(NumberPlayers = 2) Then If (Score[1] > Score[2]) Then
Message = "Player 1 Wins!"
MessageX = 30
ElseIf (Score[2] > Score[1]) Then Message = "Player 2
Wins!"
MessageX = 30
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
Else
'one player logic
If (PlayAlone) Then Message = "All Matches Found!"
MessageX = 20
Else
'play computer logic
If (Score[1] > Score[2]) Then Message = "You Win!"
MessageX = 55
ElseIf (Score[2] > Score[1]) Then Message =
"Computer Wins!"
MessageX = 25
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
EndIf
EndIf
StopGame() EndIf
'another turn?
If (PhotosRemaining <> 0) Then If (NumberPlayers = 2) Then
Message = "Player " + PlayerNumber + ", Pick Again"
MessageX = 10
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick a Box"
MessageX = 45
DisplayMessage() Else 'play computer logic
Message = "Picking Again"
MessageX = 45
DisplayMessage() ComputerTurn()
EndIf
EndIf
EndIf
Else
'no match
Sound.Stop(Program.Directory + "\boing.wav")
Sound.PlayAndWait(Program.Directory + "\boing.wav")
PhotoFound[Choice[1]] = "false"
PhotoFound[Choice[2]] = "false"
GraphicsWindow.DrawResizedImage(Cover, BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.DrawResizedImage(Cover, BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) 'swap players
If (NumberPlayers = 2) Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
Message = "Player " + PlayerNumber + ", Pick a Box"
MessageX = 10
DisplayMessage() Else
'one player logic
If (PlayAlone = "false") Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
EndIf
If (PlayerNumber = 1) Then Message = "Pick a Box"
MessageX = 45
DisplayMessage() Else
'play computer logic
Message = "Computer Picking"
MessageX = 20
DisplayMessage() ComputerTurn()
EndIf
EndIf
EndIf
CanClick = "true"
EndSub

The framework is in place. If you trying running the game, the Two Player
and One Player, Play Alone options will still work. Playing against the
computer will not work because we need code for the RandomChoice and
SmartChoice subroutines. We’ll do RandomChoice first.
Code Design – Random Computer

For random moves, the computer will simply choose (at random) one of the
available picture boxes in the window. This code is very similar to the
random move code for the Tic Tac Toe game.

Place the shaded code in the RandomChoice subroutine: Sub


RandomChoice
If (ChoiceNumber = 1) Then N =
Math.GetRandomNumber(PhotosRemaining) Else
N = Math.GetRandomNumber(PhotosRemaining ‐ 1) EndIf
Count = 0
For BoxNumber = 1 To 20
If (PhotoFound[BoxNumber] = "false") Then Count = Count + 1
If (Count = N) Then Goto LeaveRandomChoice EndIf
EndIf
EndFor
LeaveRandomChoice:
EndSub

The logic behind this code is straightforward. We either have


PhotosRemaining unselected boxes (if it’s the first choice) or
PhotosRemaining – 1 unselected boxes (if it’s the second choice). The
code selects a random number within this range and counts ahead that
number of unselected boxes to identify the box to choose (BoxNumber).

We can test our random logic, but there’s one problem. If (in
ComputerTurn) we select a smart computer, there is no code in the
corresponding subroutine (SmartMove). To make things work, add this one
line of code to the SmartMove subroutine: Sub SmartChoice
RandomChoice()
EndSub
We’re simply making the smart computer be random (temporarily) to allow
testing of the computer move logic.

Save and Run the Match Game program. Select the One Player, Play
Computer options. Difficulty doesn’t matter since all code is random at the
moment. Click Start Game to start. You go first, trying to find matching
photos. Once it’s the computer’s turn, notice two things. First, the photos
are uncovered (in pairs) randomly, very seldom do they match. Second, the
photos appear and disappear fairly quickly.

Here’s another case where want to slow things down a bit. Since the
graphics appear okay, we can use the Small Basic Delay method here. Put
this line at the top of the ComputerMove subroutine: Program.Delay(1000)
This implements a one second delay before generating a computer move.
As mentioned earlier, sometimes the Delay method works okay, sometimes
not.

Save and Run the game again. As options, select One Player and Play
Computer. Again, Difficulty does not matter. Start the game (click Start
Game). You can now play against a random computer. You’ll see the
computer is not that smart, making it pretty easy for you to win. We’ll fix
that next by coding up a far more intelligent and formidable computer
opponent. Here’s a game I played (the computer did find one match!):
Code Design – Smart Computer

So how can we make the computer a better Match Game opponent? Well,
we could cheat! Since the computer generated the random numbers to hide
the photos behind the picture boxes, the computer knows where everything
is. Once it’s the computer’s turn, it could just go through that list and find
all the matching pairs. You could never win. Obviously, not a good
approach.

The approach we’ll take is to give the computer perfect memory. In other
words, once a photo has been uncovered, the computer will remember
where that photo is. Then, when the computer has a turn (as a smart
computer), it will search its memory for matches. If it finds a match, it will
take it. First, let’s code the memory.

We use an array (Memory) that stores the indices of photos behind the 20
picture boxes as each photo is uncovered. A zero value means the photo
behind the picture box has not yet been uncovered.

The Memory array is initialized in the StartGame subroutine (the added


code is shaded): Sub StartGame GameStatus = "Playing"
'clear screen
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(0, 0, 625, 530) Score[1] = 0
Score[2] = 0
UpdateScores() PhotosRemaining = 20
N = 20
NRandomIntegers() PhotoIndex = NIntegers For I = 1 To 20
If (PhotoIndex[I] > 10) Then PhotoIndex[I] = PhotoIndex[I] ‐ 10
EndIf
Memory[I] = 0
PhotoFound[I] = "false"
GraphicsWindow.DrawResizedImage(Cover, BoxX[I], BoxY[I],
BoxW, BoxH) EndFor
PlayerNumber = 1
ChoiceNumber = 1
If (NumberPlayers = 1) Then Message = "Pick a Box"
MessageX = 45
Else
Message = "Player 1, Pick a Box"
MessageX = 10
EndIf
DisplayMessage() 'reset buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton)
Controls.HideControl(ExitButton) CanClick = "true"
EndSub

The values in the Memory array are set and reset in the
ShowPhotoAndCheck and TickSub event subroutines. The needed
changes are shaded: Sub ShowPhotoAndCheck 'one player/solitaire game
If (NumberPlayers = 1 and PlayAlone) Then Score[2] = Score[2] + 1
UpdateScores() EndIf
'show image behind selected Photo box (BoxNumber)
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[BoxNumber
]], BoxX[BoxNumber], BoxY[BoxNumber], BoxW, BoxH)
PhotoFound[BoxNumber] = "true"
Memory[BoxNumber] = PhotoIndex[BoxNumber]
If (ChoiceNumber = 1) Then Choice[1] = BoxNumber
ChoiceNumber = 2
If (NumberPlayers = 2) Then Message = "Player " +
PlayerNumber + ", Pick Another"
MessageX = 5
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick Another Box"
MessageX = 25
DisplayMessage() Else
'play computer logic
Message = "Picking Another"
MessageX = 30
DisplayMessage() ComputerTurn() EndIf
EndIf
Else
CanClick = "false"
Timer.Resume() EndIf
EndSub

Sub TickSub Timer.Pause() Choice[2] = BoxNumber ChoiceNumber = 1


If (PhotoIndex[Choice[1]] = PhotoIndex[Choice[2]]) Then 'a match
Sound.Stop(Program.Directory + "\tada.wav")
Sound.PlayAndWait(Program.Directory + "\tada.wav") 'blank out
boxes
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.FillRectangle(BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH)
'clear memory so boxes are not checked again for match
Memory[Choice[1]] = 0
Memory[Choice[2]] = 0
Score[PlayerNumber] = Score[PlayerNumber] + 1
UpdateScores() PhotosRemaining = PhotosRemaining ‐ 2
If (PhotosRemaining = 0) Then Sound.Stop(Program.Directory +
"\wow.wav") Sound.Play(Program.Directory + "\wow.wav") If
(NumberPlayers = 2) Then If (Score[1] > Score[2]) Then
Message = "Player 1 Wins!"
MessageX = 30
ElseIf (Score[2] > Score[1]) Then Message = "Player 2
Wins!"
MessageX = 30
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
Else
'one player logic
If (PlayAlone) Then Message = "All Matches Found!"
MessageX = 20
Else
'play computer logic
If (Score[1] > Score[2]) Then Message = "You Win!"
MessageX = 55
ElseIf (Score[2] > Score[1]) Then Message =
"Computer Wins!"
MessageX = 25
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
EndIf
EndIf
StopGame() EndIf
'another turn?
If (PhotosRemaining <> 0) Then If (NumberPlayers = 2) Then
Message = "Player " + PlayerNumber + ", Pick Again"
MessageX = 10
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick a Box"
MessageX = 45
DisplayMessage() Else
'play computer logic
Message = "Picking Again"
MessageX = 45
DisplayMessage() ComputerTurn() EndIf
EndIf
EndIf
Else
'no match
Sound.Stop(Program.Directory + "\boing.wav")
Sound.PlayAndWait(Program.Directory + "\boing.wav")
PhotoFound[Choice[1]] = "false"
PhotoFound[Choice[2]] = "false"
GraphicsWindow.DrawResizedImage(Cover, BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.DrawResizedImage(Cover, BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) 'swap players
If (NumberPlayers = 2) Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
Message = "Player " + PlayerNumber + ", Pick a Box"
MessageX = 10
DisplayMessage() Else
'one player logic
If (PlayAlone = "false") Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
EndIf
If (PlayerNumber = 1) Then Message = "Pick a Box"
MessageX = 45
DisplayMessage() Else
'play computer logic
Message = "Computer Picking"
MessageX = 20
DisplayMessage() ComputerTurn() EndIf
EndIf
EndIf
CanClick = "true"
EndSub

Now, how do we use the Memory array to make a smart move? The rules
we will use for the computer’s two choices are:

Choice 1: 1. Check Memory array for a match.


2. If a match is found, select the first matching picture box.
3. If no match is found, select a random box.

Choice 2: 1. If a match was found with Choice 1, select the second


matching picture box.
2. If no match was found with Choice 1, check again for a match (the
random choice in Choice 1 may match a photo stored in memory).
3. If a match is found, select the matching picture box. 4. If no match is
found, select a random box.

Let’s implement this logic in code.


First, add the subroutine CheckForMatch. This routine computes two
integers in an array (Matches). If these both of these integers are non-zero,
it tells the computer which two picture boxes have matching photos: Sub
CheckForMatch Matches[1] = 0
Matches[2] = 0
For I = 1 To 20
For J = 1 To 20
If (Memory[I] <> 0 And Memory[I] = Memory[J] And I <> J)
Then Matches[1] = I Matches[2] = J
EndIf
EndFor
EndFor
EndSub

This routine does a simple comparison of all picture boxes looking for
matching non-zero values in the Memory array.

Now, remove the line using a random choice in the SmartChoice


subroutine. Replace that line with this code which implements the smart
computer steps outlined above: Sub SmartChoice If (ChoiceNumber = 1)
Then CheckForMatch() If (Matches[1] <> 0 And Matches[2] <> 0) Then
BoxNumber = Matches[1]
Else
RandomChoice() EndIf
Else
If (Matches[1] <> 0 And Matches[2] <> 0) Then BoxNumber =
Matches[2]
Else
CheckForMatch() If (Matches[1] <> 0 And Matches[2] <> 0)
Then If (Matches[1] <> Choice[1]) Then BoxNumber =
Matches[1]
Else
BoxNumber = Matches[2]
EndIf
Else
RandomChoice() EndIf
EndIf
EndIf
EndSub

Save and Run the program. The game is now fully functional. Try playing
it against the computer with the Hardest difficulty. You should find it is
very hard to beat. Continue playing seeing how the various levels of
difficulty do indeed adjust the computer’s intelligence. Here’s a game I
played with Hard (Level 3) difficulty. I selected the first two boxes and see:

It’s Seattle’s baseball field and one of my dogs; nice photos, but not a
match.
It then becomes the computer’s turn. It’s choices are:

It’s two dogs – not a match. But, I recognize one of those dogs.

Picking the second box in the top row and the third box in the second row, I
get a match. The photos are removed, my score is incremented and it’s my
turn again:

Once all the matches were found, the final score was me 6 and the computer
4. I won!
Match Game Program Listing

Here is the complete listing of the Match Game Small Basic program: '
Match Game
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 825
GraphicsWindow.Height = 530
GraphicsWindow.BackgroundColor = "LightSkyBlue"
'initialize box locations with covers
Cover = ImageList.LoadImage(Program.Directory + "\cover.bmp")
BoxW = 150
BoxH = 100
x=5
y=5
For I = 1 To 20
BoxX[I] = x BoxY[I] = y
GraphicsWindow.DrawResizedImage(Cover, BoxX[I], BoxY[I],
BoxW, BoxH) x = x + BoxW + 5
If (x > 4 * BoxW) Then x = 5
y = y + BoxH + 5
EndIf
EndFor
'headings
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
Heading[1] = Shapes.AddText("Player 1") Heading[2] =
Shapes.AddText("Player 2") Shapes.Move(Heading[1], 670, 5)
Shapes.Move(Heading[2], 670, 70) 'scores
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(670, 35, 100, 25)
GraphicsWindow.FillRectangle(670, 100, 100, 25)
GraphicsWindow.BrushColor = "Black"
Score[1] = 0
Score[2] = 0
ScoreDisplay[1] = Shapes.AddText(Score[1]) ScoreDisplay[2] =
Shapes.AddText(Score[2]) Shapes.Move(ScoreDisplay[1], 715, 35)
Shapes.Move(ScoreDisplay[2], 715, 100) 'Draw message area
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FillRectangle(630, 250, 185, 45)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawRectangle(630, 250, 185, 45)
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 18
Message = "Game Stopped"
MessageX = 30
MessageArea = Shapes.AddText(Message) DisplayMessage() 'define
buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
StartStopButton = Controls.AddButton("Start Game", 630, 410)
OptionsButton = Controls.AddButton("Change Options", 630, 450)
ExitButton = Controls.AddButton("Exit", 630, 490) 'Default Options
NumberPlayers = 2
PlayAlone = "true"
Difficulty = 1
SetTitle() GameStatus = "Stopped"
'load images
Photo[1] = ImageList.LoadImage(Program.Directory + "\clara.jpg")
Photo[2] = ImageList.LoadImage(Program.Directory + "\toby.jpg")
Photo[3] = ImageList.LoadImage(Program.Directory + "\Blue hills.jpg")
Photo[4] = ImageList.LoadImage(Program.Directory + "\Sunset.jpg")
Photo[5] = ImageList.LoadImage(Program.Directory + "\Water
lilies.jpg") Photo[6] = ImageList.LoadImage(Program.Directory +
"\Winter.jpg") Photo[7] = ImageList.LoadImage(Program.Directory +
"\spaceneedle.jpg") Photo[8] = ImageList.LoadImage(Program.Directory
+ "\market.jpg") Photo[9] = ImageList.LoadImage(Program.Directory +
"\safeco.jpg") Photo[10] = ImageList.LoadImage(Program.Directory +
"\qwest.jpg") Controls.ButtonClicked = ButtonClickedSub
GraphicsWindow.MouseDown = MouseDownSub Timer.Interval = 1000
Timer.Pause() Timer.Tick = TickSub EndSub

Sub DisplayMessage Shapes.Move(MessageArea, 630 + MessageX, 260)


Shapes.SetText(MessageArea, Message) EndSub

Sub SetTitle If (NumberPlayers = 1) Then GraphicsWindow.Title = "Match


Game ‐ 1 Player, "
If (PlayAlone) Then GraphicsWindow.Title = GraphicsWindow.Title
+ "Play Alone"
Else
GraphicsWindow.Title = GraphicsWindow.Title + "Play
Computer"
EndIf
Else
GraphicsWindow.Title = "Match Game ‐ 2 Players"
EndIf
EndSub

Sub ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =


"Stopped") Then If (B = ExitButton) Then Program.End() ElseIf (B =
OptionsButton) Then SetOptions() ElseIf (B = StartStopButton) Then
StartGame() EndIf
ElseIf (GameStatus = "Playing") Then If (B = StartStopButton) Then
'stop program
Message = "Game Stopped"
MessageX = 30
StopGame() EndIf
EndIf
EndSub

Sub SetOptions GraphicsWindow.Hide() TextWindow.Show()


TextWindow.Title = "Match Game"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("MATCH GAME OPTIONS")
TextWindow.WriteLine("") GetPlayers: TextWindow.CursorLeft = 3
TextWindow.WriteLine("With one player, you play alone or against the
computer.") TextWindow.CursorLeft = 3
TextWindow.WriteLine("With two players, you play against a friend.")
TextWindow.CursorLeft = 3
TextWindow.Write("How many players do you want (1 or 2)? ")
NumberPlayers = TextWindow.ReadNumber() If (NumberPlayers < 1 Or
NumberPlayers > 2) Then Goto GetPlayers EndIf
If (NumberPlayers = 1) Then Shapes.SetText(Heading[1], "You")
GetPlayAlone: TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can play alone or play the computer.")
TextWindow.CursorLeft = 3
TextWindow.Write("Make your choice (1‐Play Alone, 2‐Play
Computer)? ") T = TextWindow.ReadNumber() If (T < 1 Or T > 2)
Then Goto GetPlayAlone EndIf
If (T = 1) Then PlayAlone = "true"
Shapes.SetText(Heading[2], "Guesses") Else
PlayAlone = "false"
Shapes.SetText(Heading[2], "Computer") GetDifficulty:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can set the game difficulty.")
TextWindow.CursorLeft = 3
TextWindow.Write("Make your choice (1‐Easiest, 2‐Easy, 3‐
Hard, 4‐Hardest)? ") Difficulty = TextWindow.ReadNumber() If
(Difficulty < 1 Or Difficulty > 4) Then Goto GetDifficulty EndIf
EndIf
Else
Shapes.SetText(Heading[1], "Player 1") Shapes.SetText(Heading[2],
"Player 2") EndIf
SetTitle() TextWindow.Hide() GraphicsWindow.Show() EndSub

Sub NRandomIntegers 'Order all elements initially


For I = 1 To N
NIntegers[I] = I EndFor
'J is the number of integers remaining For J = N To 2 Step ‐1
I = Math.GetRandomNumber(J) T = NIntegers[J] NIntegers[J] =
NIntegers[I]
NIntegers[I] = T
EndFor
EndSub

Sub StartGame GameStatus = "Playing"


'clear screen
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(0, 0, 625, 530) Score[1] = 0
Score[2] = 0
Shapes.SetText(ScoreDisplay[1], Score[1])
Shapes.SetText(ScoreDisplay[2], Score[2]) PhotosRemaining = 20
N = 20
NRandomIntegers() PhotoIndex = NIntegers For I = 1 To 20
If (PhotoIndex[I] > 10) Then PhotoIndex[I] = PhotoIndex[I] ‐ 10
EndIf
Memory[I] = 0
PhotoFound[I] = "false"
GraphicsWindow.DrawResizedImage(Cover, BoxX[I], BoxY[I],
BoxW, BoxH) EndFor
PlayerNumber = 1
ChoiceNumber = 1
If (NumberPlayers = 1) Then Message = "Pick a Box"
MessageX = 45
Else
Message = "Player 1, Pick a Box"
MessageX = 10
EndIf
DisplayMessage() 'reset buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton) Controls.HideControl(ExitButton)
CanClick = "true"
EndSub

Sub StopGame 'restore buttons


GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton) CanClick = "false"
DisplayMessage() EndSub

Sub MouseDownSub If (GameStatus = "Playing" And CanClick) Then


'find which box was clicked
x = GraphicsWindow.MouseX
y = GraphicsWindow.MouseY
BoxNumber = 0
For I = 1 To 20
If (x > BoxX[I] And x < BoxX[I] + BoxW) Then If (y > BoxY[I]
And y < BoxY[I] + BoxH) Then BoxNumber = I Goto GotIt
EndIf
EndIf
EndFor
GotIt: If (BoxNumber <> 0) Then 'if already clicked then exit
If (PhotoFound[BoxNumber]) Then Goto LeaveMouseDownSub
EndIf
ShowPhotoAndCheck() EndIf
EndIf
LeaveMouseDownSub: EndSub

Sub ShowPhotoAndCheck 'one player/solitaire game


If (NumberPlayers = 1 and PlayAlone) Then Score[2] = Score[2] + 1
Shapes.SetText(ScoreDisplay[2], Score[2]) EndIf
'show image behind selected Photo box (BoxNumber)
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[BoxNumber]],
BoxX[BoxNumber], BoxY[BoxNumber], BoxW, BoxH)
PhotoFound[BoxNumber] = "true"
Memory[BoxNumber] = PhotoIndex[BoxNumber]
If (ChoiceNumber = 1) Then Choice[1] = BoxNumber ChoiceNumber =
2
If (NumberPlayers = 2) Then Message = "Player " + PlayerNumber
+ ", Pick Another"
MessageX = 5
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick Another Box"
MessageX = 25
DisplayMessage() Else
'play computer logic
Message = "Picking Another"
MessageX = 30
DisplayMessage() ComputerTurn() EndIf
EndIf
Else
CanClick = "false"
Timer.Resume() EndIf
EndSub

Sub TickSub Timer.Pause() Choice[2] = BoxNumber ChoiceNumber = 1


If (PhotoIndex[Choice[1]] = PhotoIndex[Choice[2]]) Then 'a match
Sound.Stop(Program.Directory + "\tada.wav")
Sound.PlayAndWait(Program.Directory + "\tada.wav") 'blank out
boxes
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(BoxX[Choice[1]], BoxY[Choice[1]],
BoxW, BoxH) GraphicsWindow.FillRectangle(BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) 'clear memory so boxes are not
checked again for match Memory[Choice[1]] = 0
Memory[Choice[2]] = 0
Score[PlayerNumber] = Score[PlayerNumber] + 1
Shapes.SetText(ScoreDisplay[PlayerNumber], Score[PlayerNumber])
PhotosRemaining = PhotosRemaining ‐ 2
If (PhotosRemaining = 0) Then Sound.Stop(Program.Directory +
"\wow.wav") Sound.Play(Program.Directory + "\wow.wav") If
(NumberPlayers = 2) Then If (Score[1] > Score[2]) Then Message =
"Player 1 Wins!"
MessageX = 30
ElseIf (Score[2] > Score[1]) Then Message = "Player 2
Wins!"
MessageX = 30
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
Else
'one player logic
If (PlayAlone) Then Message = "All Matches Found!"
MessageX = 20
Else
'play computer logic
If (Score[1] > Score[2]) Then Message = "You Win!"
MessageX = 55
ElseIf (Score[2] > Score[1]) Then Message = "Computer
Wins!"
MessageX = 25
Else
Message = "It's a Tie!"
MessageX = 45
EndIf
EndIf
EndIf
StopGame() EndIf
'another turn?
If (PhotosRemaining <> 0) Then If (NumberPlayers = 2) Then
Message = "Player " + PlayerNumber + ", Pick Again"
MessageX = 10
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick a Box"
MessageX = 45
DisplayMessage() Else
'play computer logic
Message = "Picking Again"
MessageX = 45
DisplayMessage() ComputerTurn() EndIf
EndIf
EndIf
Else
'no match
Sound.Stop(Program.Directory + "\boing.wav")
Sound.PlayAndWait(Program.Directory + "\boing.wav")
PhotoFound[Choice[1]] = "false"
PhotoFound[Choice[2]] = "false"
GraphicsWindow.DrawResizedImage(Cover, BoxX[Choice[1]],
BoxY[Choice[1]], BoxW, BoxH)
GraphicsWindow.DrawResizedImage(Cover, BoxX[Choice[2]],
BoxY[Choice[2]], BoxW, BoxH) 'swap players
If (NumberPlayers = 2) Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
Message = "Player " + PlayerNumber + ", Pick a Box"
MessageX = 10
DisplayMessage() Else
'one player logic
If (PlayAlone = "false") Then If (PlayerNumber = 1) Then
PlayerNumber = 2
Else
PlayerNumber = 1
EndIf
EndIf
If (PlayerNumber = 1) Then Message = "Pick a Box"
MessageX = 45
DisplayMessage() Else
'play computer logic
Message = "Computer Picking"
MessageX = 20
DisplayMessage() ComputerTurn() EndIf
EndIf
EndIf
CanClick = "true"
EndSub

Sub RandomChoice If (ChoiceNumber = 1) Then N =


Math.GetRandomNumber(PhotosRemaining) Else
N = Math.GetRandomNumber(PhotosRemaining ‐ 1) EndIf
Count = 0
For BoxNumber = 1 To 20
If (PhotoFound[BoxNumber] = "false") Then Count = Count + 1
If (Count = N) Then Goto LeaveRandomChoice EndIf
EndIf
EndFor
LeaveRandomChoice: EndSub

Sub SmartChoice If (ChoiceNumber = 1) Then CheckForMatch() If


(Matches[1] <> 0 And Matches[2] <> 0) Then BoxNumber = Matches[1]
Else
RandomChoice() EndIf
Else
If (Matches[1] <> 0 And Matches[2] <> 0) Then BoxNumber =
Matches[2]
Else
CheckForMatch() If (Matches[1] <> 0 And Matches[2] <> 0)
Then If (Matches[1] <> Choice[1]) Then BoxNumber =
Matches[1]
Else
BoxNumber = Matches[2]
EndIf
Else
RandomChoice() EndIf
EndIf
EndIf
EndSub

Sub ComputerTurn Program.Delay(1000) If (ChoiceNumber = 1) Then If


(Difficulty = 1) Then Threshold = 25
ElseIf (Difficulty = 2) Then Threshold = 50
ElseIf (Difficulty = 3) Then Threshold = 75
Else
Threshold = 90
EndIf
If (Math.GetRandomNumber(100) <= Threshold) Then
SmartComputer = "true"
Else
SmartComputer = "false"
EndIf
EndIf
If (SmartComputer) Then SmartChoice() Else
RandomChoice() EndIf
'have BoxNumber
ShowPhotoAndCheck() EndSub

Sub CheckForMatch Matches[1] = 0


Matches[2] = 0
For I = 1 To 20
For J = 1 To 20
If (Memory[I] <> 0 And Memory[I] = Memory[J] And I <> J)
Then Matches[1] = I Matches[2] = J
EndIf
EndFor
EndFor
EndSub
Match Game Program Review

The Match Game program is now complete. Save and Run the program
and make sure it works as promised. Check that all options work correctly.

If there are errors in your implementation, go back over the steps of


window and code design. Go over the developed code – make sure you
understand how different parts of the program were coded. As mentioned in
the beginning of this chapter, the completed program is saved as
MatchGame in the KidGamesSB\KidGamesSB Programs\MatchGame
folder.

While completing this program, new concepts and skills you should have
gained include:

➢ Proper steps in game design and game flow.


➢ How to randomly sort integers (shuffle numbers).
➢ How to implement delays in games.
➢ How to give the computer graduated intelligence in playing games.
Match Game Program Enhancements

There are several ways to improve the Match Game program. Some
possibilities are:

➢ Design a tool that allows for selection of photos used in the game.
This requires some advanced skills. Your tool would write a file with
the name of the 10 photos to use (and their location). Then when
Match Game begins, it would open that file and automatically load
the files. Reading and writing to files is briefly covered in our last
game program.
➢ Make the number of photo boxes adjustable for an added difficulty
adjustment (fewer boxes for little kids).
➢ Add additional levels of difficulty by having finer adjustments on the
threshold between random and smart computer moves.
➢ As written, a player could theoretically find all ten pairs without
giving the other player a chance. Perhaps, rewrite the game so a
player only gets one extra turn after a match.
➢ The computer in this game is pretty smart, but it can be smarter. How
you ask? If the computer uncovers a photo that has no match, its next
choice could be a photo that’s already been uncovered. This would
not give the computer any more information about hidden photos, but
it also does not give you, the opponent, any needed information
either.
8. Pizza Delivery Program
Review and Preview

The next program we build is a Pizza Delivery business simulation.


You have been asked to be in charge of deliveries for the
neighborhood pizza parlor for one night. You take phone orders, tell
the crew how many pizzas to bake, and tell the delivery car where to
go.

The program teaches mental math, logical thinking skills and good business
practices. We’ll see how to use a Timer to control many events.
Pizza Delivery Program Preview

In this chapter, we will build a Pizza Delivery game. In this simulation


game, lots of decisions need to be made. The basic idea is to read the
incoming phone orders and tell the delivery car where to go. You also need
to make sure you always have fresh-baked pizzas ready to go out the door.
The delivery area is a grid of 20 by 20 squares. The more pizzas you sell,
the more money you make!

The finished program is saved as PizzaDelivery in the


KidGamesSB\KidGamesSB Programs\PizzaDelivery folder. Start Small
Basic and open the finished program. Run the program (click the Run
toolbar button or press <F5>). The game will appear in its ‘stopped’ state.
At this point, you can click the Start Game button to start the game or click
Exit to exit the program.
Before starting the game, let’s describe its operation. You sell and deliver
pizzas from 6:00 to 11:00. A clock in the upper right corner shows the time.
It doesn't take 5 hours to use the program - the five hours go by in about 15
minutes, so think fast. The phone rings when an order comes in. The order
box under the clock shows what time the order was called in, the
coordinates for delivery, and the number of pizzas ordered. The order is also
displayed on the neighborhood grid (20 rows by 20 columns) on the left
side of the window.

In the message area under the orders, you are told the current location of the
car in the grid. At the beginning of the program, the car is at the pizza parlor
(marked by an X on the grid). You are shown how many pizzas are baked
and ready and how many are in the car. To load pizzas in the car, click the
Load button. To tell the car where to go, click on the grid position. The car
will travel to the desired position. When it arrives, the car's horn will sound
and tell you the result of the delivery. There are four possible results: (1)
on-time delivery, (2) late delivery, (3) not enough pizzas in the car to make
the delivery, or (4) no pizza ordered at the given location. If you make a
successful delivery, the amount of sales (displayed at the top of the
window) is updated. When you need to return to the pizza parlor to load
more pizzas, click the location marked by X.

You also need to control the pizza oven to make sure there are always
pizzas available for delivery. To bake pizzas, click Add Pizza for each
pizza you want to bake (pizzas can’t be taken out once they’re in). When
the oven is loaded, click Bake Pizza. You will be told when the pizzas are
ready. When the pizzas are done, a bell will ring and the pizzas are moved
to the ready area. The Baked box always displays how many pizzas are
available for loading into the car. At any time during the program, you may
pause the action by clicking Pause Game. To restart, click Restart Game.
To stop the program before 11:00, click Stop Game. Once the program
stops, a summary screen will show your sales and costs results and compute
your profits (if any). After reading the results, press Enter.

This may seem like lots of instructions but the process becomes fairly
obvious as you play the game. Run the program (press <F5>). The game
will appear in its ‘stopped’ state and the delivery grid will appear. At this
point, you simply click Start Game to get things going. There are no
options to select. The randomness inherent in the Pizza Delivery game
makes each new game a different experience. Once the game starts, the first
thing you notice is the phone starts ringing with orders. Here’s my window
after a couple of orders have come in:

At 6:06, an order for 1 pizza was taken for delivery to Row 6, Column N
(also marked on grid). At 6:09, 5 pizzas were ordered at 12 H.

Right now, I don’t have pizzas to deliver. The game starts with 8 pizzas
ready to go. If I click Load (the car can only be loaded at the pizza parlor),
those pizzas are put in the car. Then, if I click 8 K on the grid, my car goes
there, beeps and makes a delivery. Then, I see:

The pizza was delivered on-time and I made $10. Another order came in
while I was traveling. Next, I deliver 5 pizzas to 12 H, followed by 2 pizzas
at 10 J. At that point, I am out of pizzas. I click the X mark at 19 D to return
to the pizza parlor.

Another order came in, but I have no pizzas to deliver.


I click the Add Pizza button 8 times to load the oven, then click Bake
Pizza to start the oven (the oven turns red to show it’s on):
I could have started the baking process while I was out on the road (you can
do several things at once in Pizza Delivery), speeding things up a bit. Now,
I’m forced to wait several minutes while the pizzas bake. Once they’re
done, there are more deliveries to make and more pizzas to bake. It’s a
hectic night at the pizza parlor!

So, in Pizza Delivery, you keep baking pizzas, loading the car and sending
the pizzas out to the waiting deliveries. Late deliveries are penalized and if
you’re too late, the customer gives up and cancels the order – just like the
real world. After playing for a little over an hour, my window looks like

this:

I’ve got lots of orders and lots of pizzas going. The customer at 10 S has
been waiting a while (noted by the red grid background). I need to rush
those pizzas out.

I ran Pizza Delivery until a little after 9 o’clock (closing before the usual
11:00).
Looking at the window, I still had lots of deliveries to make and lots of
wasted pizza. I probably could have made a lot more money in the last two
hours.

At that point, I clicked Stop Game and the following text window
appeared:
I did okay, netting $200.30

Continue playing the game to understand its operation. Try playing all the
way to 11:00 to see how much money you can make. Orders stop at 10:30
to allow you to finish deliveries. Click Exit when you’re done to stop the
game. Skim over the code, if you like.

Simulations like Pizza Delivery are lots of fun. You get to see how your
decisions affect your bottom line – net profits. And, programming such
simulations are fun too – you get to make the rules to try to make the
program realistic. As we build this program, we’ll discuss such rules in
detail. You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.

We address window design. We discuss the code needed to build both the
delivery window (a graphics window) and the results window (a text
window). For the delivery window, we will show you how to draw the
delivery grid and establish initial conditions. And, we address code design.
We discuss how to implement the various aspects of the game: running the
clock, establishing phone orders, running the pizza oven, storing pizzas,
loading the car, moving the car and seeing delivery results. We will see how
to display a fixed sized list of items (the orders), how to handle multiple
events with a single timer object.
Pizza Delivery Window Design

Here is a sketch for the window layout for the Pizza Delivery program:

The delivery grid is sketched on the left. The clock and sales values are at
the top right. Under that is a box to list orders and car location/status. Under
that is the pizza oven (with two button controls) that shows pizzas baking in
the oven. Next is a display for the number of baked pizzas. Then, a display
of the number of pizzas in the car (with a button to load the car). Two
button controls complete the design: one to start, pause and restart the game
and one to stop a game or exit the program.

We will now begin writing code for the Pizza Delivery program. We will
write the code in several steps. As a first step, we will write the code the
defines the delivery grid and other window components. Then, the code that
initializes the game. Then, we add additional elements to the game, one at a
time. During the code development process, recognize you may modify a
particular procedure several times before arriving at the finished product.
Start a new program in Small Basic. Once started, we suggest you
immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Building Delivery Grid

For the Pizza Delivery game, we want a delivery grid that looks like this:

Notice we have labeling information for the columns and rows and a 20 x
20 grid used to display orders. Individual elements in the grid are referred
to by a row number and a column letter. We will build this grid using 441
(21 x 21) rectangles. Let’s see how to do this.

The process is fairly straightforward. For each of the 441 rectangles, we


define left, top, width and height values for proper positioning. The first
row in the grid will be used to label the columns; the first column will be
used to label the rows. We will ignore the rectangle in the upper left corner.
The remaining 20 x 20 grid of rectangles will be used to display orders and
car motion. The labeling rectangles will not have borders, the interior
rectangles will.
The rectangles will be defined by several two-dimensional arrays (the first
dimension being the row and the second being the column):

DeliveryGridX Left position of rectangle


DeliveryGridY Top position of rectangle
DeliveryGridColor Background color of rectangle
DeliveryGridText Text to display in rectangle

We will use the 0th elements of these arrays to represent the row and column
labels. We ignore the [0][0] elements.

Use this code to establish the delivery grid and its labels: ' Pizza Delivery
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 715
GraphicsWindow.Height = 520
GraphicsWindow.Title = "Pizza Delivery"
'draw new delivery grid
DrawGrid()
EndSub

Sub DrawGrid GraphicsWindow.BrushColor = "SteelBlue"


GraphicsWindow.FillRectangle(0, 0, 500, 520) 'GridR is row, GridC
is column; build one row at a time GridW = 22
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
For GridR = 0 To 20
For GridC = 0 To 20
DeliveryGridX[GridR][GridC] = 10 + GridC * GridW
DeliveryGridY[GridR][GridC] = 20 + GridR * GridW
If (GridR = 0) Then If (GridC <> 0) Then 'column letters
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(DeliveryGridX[GridR]
[GridC] + 5, DeliveryGridY[GridR][GridC],
Text.GetCharacter(GridC + 64)) EndIf
ElseIf (GridC = 0) Then If (GridR <> 0) Then 'row numbers
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(DeliveryGridX[GridR]
[GridC], DeliveryGridY[GridR][GridC], GridR)
EndIf
Else
DeliveryGridColor[GridR][GridC] = "White"
DeliveryGridText[GridR][GridC] = ""
DrawGridSquare() EndIf
EndFor
EndFor
EndSub

Sub DrawGridSquare GraphicsWindow.BrushColor =


DeliveryGridColor[GridR][GridC]
GraphicsWindow.FillRectangle(DeliveryGridX[GridR][GridC],
DeliveryGridY[GridR][GridC], GridW, GridW)
GraphicsWindow.PenWidth = 1
GraphicsWindow.PenColor = "Black"
GraphicsWindow.DrawRectangle(DeliveryGridX[GridR][GridC],
DeliveryGridY[GridR][GridC], GridW, GridW)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 16
GraphicsWindow.DrawText(DeliveryGridX[GridR][GridC] + 6,
DeliveryGridY[GridR][GridC] + 1, DeliveryGridText[GridR]
[GridC]) EndSub

The first line of code calls a subroutine InitializeProgram where we will


put all code needed to set up the program for use. This code builds the grid,
one row at a time in the subroutine DrawGrid. Each control is first
declared, and assigned a GridX and GridY value. Each rectangle is a
square (GridW pixels on each side). We start at the upper left corner,
working our way to the right. Once a row is finished, the GridY value is
incremented down one row and the GridX value returned to the left
“margin” (10 pixels). Other values are assigned based on locations.
Controls with column labels (GridR = 0) and row labels (GridC = 0) have
no border and are given an appropriate letter or number. Internal labels
(GridR = 1 to 20, GridC = 1 to 20) have a black border and white
background to give a grid effect. Each rectangle in the grid is drawn using
the subroutine DrawGridSquare. Now, let’s give it a try.

Save and Run the program. Like magic, you should see the grid:

We will now begin writing the remaining code for the game. We will write
the code in several steps. As a first step, we will finish writing the code
draws the window.
Window Design – Clock and Sales Display

The first elements on the right side of the window are the display areas for
the clock and sales information. Add this code to the InitializeProgram
subroutine: 'draw clock and sales
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 5, 100, 60)
GraphicsWindow.FillRectangle(610, 5, 100, 60)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
GraphicsWindow.DrawText(510, 5, "Time")
GraphicsWindow.DrawText(615, 5, "Sales") ClockTime = "6:00"
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
TimeDisplay = Shapes.AddText(ClockTime) Shapes.Move(TimeDisplay,
535, 30) TotalSales = 0
'format as $0.00
Amount = TotalSales FormatAmount() SalesDisplay =
Shapes.AddText(AmountText) Shapes.Move(SalesDisplay, 620, 30) We
draw the headings, initialize a couple of variables (ClockTime and
TotalSales) and display them using the two Shapes objects TimeDisplay
and SalesDisplay.

The code for displaying sales use a subroutine (FormatAmount) that


makes sure any sales display in $0.00 format: Sub FormatAmount Dollars
= Math.Floor(Amount) Cents = Math.Floor(100 * (Amount ‐ Dollars))
AmountText = "$" + Dollars + "."
If (Cents = 0) Then AmountText = AmountText + "00"
ElseIf (Cents < 10) Then AmountText = AmountText + "0" + Cents
Else
AmountText = AmountText + Cents EndIf
EndSub

Notice how we separate an Amount into its Dollars and Cents, then
properly display them in a text variable (AmountText).

Save and Run the program. You will now see the Time and Sales
displayed:
Window Design – Message Area

Under the Time and Sales displays are two boxes that will be used to
display orders and messages about car location. Initially, they are just blank
rectangles. Add this code to InitializeProgram: 'draw message area
GraphicsWindow.BrushColor = "LightYellow"
GraphicsWindow.FillRectangle(505, 190, 205, 50)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(505, 190, 205, 50)
GraphicsWindow.DrawRectangle(505, 70, 205, 120) Save and Run to
see the message area:
Window Design – Pizza Oven

The pizza oven is used to manage the pizza baking process. It is rectangular
and has two buttons to control adding pizzas and baking pizzas. Add this
code to InitializeProgram: 'draw pizza oven
DrawBlueOven() 'add pizza button
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
AddPizzaButton = Controls.AddButton("Add Pizza", 510, 380)
Controls.SetSize(AddPizzaButton, 95, 33) 'bake pizza button
BakePizzaButton = Controls.AddButton("Bake Pizza", 610, 380)
Controls.SetSize(BakePizzaButton, 95, 33) The oven is drawn in its
initial condition (off and blue in color) using DrawBlueOven: Sub
DrawBlueOven 'draw pizza oven
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 245, 205, 170)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(510, 245, "Oven Off") EndSub

Save and Run to see the cold oven with its two buttons (AddPizzaButton
and BakePizzaButton):
Window Design – Pizza Loading Boxes

Under the oven are two message areas that inform the player of how many
pizzas are baked and how many are in the car. The car box also has a button
control for loading the car. Add this code to InitializeProgram: 'draw pizza
loading boxes
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 420, 70, 60)
GraphicsWindow.FillRectangle(580, 420, 130, 60)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(510, 420, "Baked")
GraphicsWindow.DrawText(585, 420, "Pizzas in Car") PizzasReady = 0
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = 20
PizzasReadyDisplay = Shapes.AddText(PizzasReady)
Shapes.Move(PizzasReadyDisplay, 535, 445) PizzasInCar = 0
PizzasInCarDisplay = Shapes.AddText(PizzasInCar)
Shapes.Move(PizzasInCarDisplay, 615, 445) 'load button
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
LoadButton = Controls.AddButton("Load", 660, 445)
Controls.SetSize(LoadButton, 45, 33) This code initializes a couple of
variables (PizzasReady and PizzasInCar) and displays them using
PizzasReadyDisplay and PizzasInCarDisplay: Save and Run the
program. The new information (with the new button, LoadButton)
displays appear:
Window Design – Remaining Buttons

The Pizza Delivery game uses several buttons. We have already added the
two used in the pizza oven and the button used to load the car. There is also
a button to start, pause, and restart the game, and one to stop the game and
exit the program. Let’s add these.

Add this code to InitializeProgram: 'start/pause button


StartPauseButton = Controls.AddButton("Start Game", 505, 485)
Controls.SetSize(StartPauseButton, 110, 33) 'exit/stop button
ExitStopButton = Controls.AddButton("Exit", 620, 485)
Controls.SetSize(ExitStopButton, 90, 33) Save and Run the program.
The final window (with the two new buttons, StartPauseButton and
ExitStopButton ) is seen:
Code Design – Initializing Stopped State

Any time we start a program, there are certain initializations that must take
place. We have already initialized a few variables (ClockTime, TotalSales,
PizzasReady, PizzasInCar) while building the window. Let’s look at
additional initializations needed in the Pizza Delivery game. All
initializations are done in the first part of the program code (before any
subroutines).

When initialized, we need to make sure the only thing a user can do is click
on Start Game or Exit. They should not be able to operate the pizza oven
or load the car. Add these lines of code to InitializeProgram (after code
creating buttons) to hide the pizza oven buttons and the button to load the
car. We also set GameStatus is set to “Stopped”:
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) GameStatus = "Stopped"

Save and Run the program making sure the oven and car loading buttons
are hidden:
We now begin adding other elements to our simulation, one at a time. We
add code for running the clock, accepting phone orders, running the pizza
oven, loading the car, moving the car and evaluating the deliveries. Each
element will require certain “tuning” parameters – values that define how
the simulation works. Every simulation has such parameters. These are
constants you adjust as you define the program. In the code here, we give
you values of such constants we use. Feel free to change them as you
choose.
Code Design – Clock

The first element we add to the Pizza Delivery program is the clock that
keeps track of time. Recall the clock starts at 6:00 and stops at 11:00. We
don’t want the game to actually last five hours, so we speed things up a bit.
We need to decide how fast we want the five hours to really go by and still
be able to play the game. This is one of the tuning parameters we discussed.

The clock is controlled by the Timer object. Recall this object generates a
Tick event every Interval (a Timer property) milliseconds. We want to
determine how many milliseconds should elapse for each minute on the
clock. We chose to take approximately 15 minutes to play a complete game,
or to simulate 300 minutes (5 hours x 60 minutes/hour) of pizza deliveries.
So, we need invoke the Tick event 300 times in 900000 milliseconds (15
minutes x 60 seconds/minute x 1000 milliseconds/second). So we should
set Interval to 3000 (900000 / 300). Or should we?

In the Pizza Delivery game, the Timer object will be used to control more
than just the clock. It will also be used to monitor the orders phoned in, the
oven baking the pizzas, and the motion of the car. When multiple events are
controlled by a single Timer, we need to choose a value for Interval that
handles the ‘fastest’ event, or the one that needs to be updated most often.
Then, the slower events are updated at a rate that is some multiple of the
fastest event. In this game, the car motion is the fastest event. We choose to
update car motion every 0.5 seconds or use an Interval value of 500
milliseconds. With such a value, the clock is updated every six updates of
the car motion, giving it a ‘perceived interval’ of 3000.

Let’s implement the clock update logic, but first you may wonder how did
we come up with all these timing numbers? They were developed as the
game was built. Recognizing there were multiple events to be handled by a
single Timer, we defined variables that could be easily changed as the
game was tested and built. The numbers used here are the final values we
chose to make Pizza Delivery a workable game. You may find values that
better suit your needs. Feel free to change anything.
Add this code at the end of InitializeProgram: Timer.Interval = 500
Timer.Pause() Timer.Tick = TimerTickSub ClockTicksMax = 6

This establishes the Interval, assigns the TimerTickSub subroutine to the


Tick event and turns off the Timer initially. It also sets a value for
ClockTicksMax (the number of Tick events that need to occur for an
update of the clock display).

Add the TimerTickSub subroutine: Sub TimerTickSub 'clock


ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
EndIf
ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If
(ClockMinute < 10) Then ClockTime = ClockTime + ":0" +
ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime) EndIf
EndSub

We use ClockTicks to keep track of how many times the TimerTickSub


subroutine has been called. Once ClockTicks is equal to ClockTicksMax,
we update the clock display (set by ClockHour and ClockMinute). It’s all
pretty straightforward.

Now, we’ll write the code that starts, pauses, restarts and stops the clock in
Pizza Delivery. We also add code that exits the game. Two buttons control
the game, StartPauseButton and ExitStopButton. These buttons have
certain interactions. The StartPauseButton can have one of three possible
actions based on GameStatus. If the GameStatus is “Stopped” when the
button is clicked, the game is initialized and put in playing mode using:
➢ Change GameStatus to “Playing”
➢ Change caption to Pause Game.
➢ Change caption of ExitStopButton to Stop Game.
➢ Initialize time to 6:00.
➢ Initialize ClockTicks to 0.
➢ Start Timer.

When GameStatus is “Playing” and the button is clicked, we enter pause


mode:

➢ Change GameStatus to “Paused”


➢ Pause Timer.
➢ Change caption to Restart Game.
➢ Hide ExitStopButton.

When Game Status is “Paused” and the button is clicked, we re-enter


playing mode:

➢ Change GameStatus to “Playing”


➢ Change caption to Pause Game.
➢ Show ExitStopButton.
➢ Start Timer.

To enable detecting button clicks, add this line at the end of


InitializeProgram: Controls.ButtonClicked = ButtonClickedSub With this,
each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.

Add ButtonClickedSub subroutine: Sub ButtonClickedSub B =


Controls.LastClickedButton If (B = StartPauseButton) Then ' start, stop,
pause button
StartPauseButtonClick() EndIf
EndSub
Finally, the code that covers the listed steps to start, pause and restart the
clock is in the StartPauseButtonClick subroutine: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
'initialize clock
ClockHour = 6
ClockMinute = 0
ClockTime = "6:00"
Shapes.SetText(TimeDisplay, ClockTime) ClockTicks = 0
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) Timer.Resume() EndIf
EndSub

Save and Run the program. Click Start Game and the clock should begin
counting up the minutes. Try the pause and restart features. How long does
it take one hour to go by? It should take about 3 minutes based on our
values of Interval and ClockTicksMax. Here’s the window after running a
little over one hour of game time:

The Stop Game button doesn’t work yet – let’s fix that.

When a player clicks Stop Game (the ExitStopButton in “Playing”


mode), the following should happen:

➢ Change GameStatus to “Stopped”


➢ Stop Timer.
➢ Play game over sound.
➢ Change caption to Exit.
➢ Change caption of StartPauseButton to Start Game.

If the ExitStopButton is clicked when GameStatus is “Stopped”, the


program stops.
We use the tada.wav file for the game over sound. It is in the
KidGamesSB\KidGamesSB Programs\PizzaDelivery folder. Copy the
file to your program’s folder.

Modify the ButtonClickSub routine with the shaded code to detect clicks
on the ExitStopButton: Sub ButtonClickedSub B =
Controls.LastClickedButton If (B = StartPauseButton) Then ' start, stop,
pause button
StartPauseButtonClick()
ElseIf (B = ExitStopButton) Then 'exit, stop button
ExitStopButtonClick()
EndIf
EndSub

The ExitStopButtonClick subroutine is: Sub ExitStopButtonClick If


(GameStatus = "Playing") Then StopGame()
Else
Program.End() EndIf
EndSub

which uses the StopGame subroutine that implements the listed steps for
stopping: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") EndSub

Save and Run Pizza Delivery. You should now be able to start the game,
pause the game, restart the game and stop the game. You can also stop the
program. Make sure everything works as desired. Make sure you hear a
‘tada’ sound when the game is ended.

Before leaving the clock, let’s make one last change. Recall the game lasts
from 6:00 to 11:00. As coded, the program will continue forever! We need
logic to stop at 11:00. Add the shaded code to the TimerTickSub to
accomplish this: Sub TimerTickSub 'Clock Update
ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If
(ClockMinute < 10) Then ClockTime = ClockTime + ":0" +
ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime) EndIf
EndSub

Save the program. You should now run the program to make sure it
automatically stops once the clock reaches 11:00. But, you don’t really want
to sit around for 15 minutes to see that happen. To speed things up,
temporarily set the Interval to 100 and ClockTicksMax to 1 (yielding a
clock update every 0.1 seconds). Then, Run the program, click Start Game
and watch time fly by! Once the clock hits 11:00, a sound will be played
and the program should return to stopped state:

We often do this in programming – change parameters (even if the changes


are not realistic) to test out different elements of code. Just remember, after
changing the constant and making sure the clock stops at 11:00, to change
the variables backs to their original values (Interval = 500,
ClockTicksMax = 6). You will know it if you don’t – the pizza simulation
will go very quickly! Next, let’s write the code to get phone orders coming
in.
Code Design – Phone Orders

In Pizza Delivery, orders are phoned in randomly. The orders (time,


location and number of pizzas) are displayed in message area. The number
of pizzas ordered is displayed at the proper location on the delivery grid (a
green background is used). You then use this information to send a car to
deliver the pizzas.

Here’s another place where I just made up some rules for the orders – feel
free to change them if you like. The rules implemented for pizza phone
orders are:

➢ Orders arrive at random times, in 1 to 7 minute increments.


➢ Orders come from random locations on the delivery grid.
➢ Each order is for 1 to 5 pizzas, using these probabilities: ▪ 1 pizza, 30
percent ▪ 2 pizzas, 20 percent ▪ 3 pizzas, 20 percent ▪ 4 pizzas, 15
percent ▪ 5 pizzas, 15 percent ➢ No orders are accepted after 10:30 to
allow car to finish deliveries.

As mentioned, order information will be displayed in the message area. We


use a specific format for that listing. As an example, say an order arrives at
6:20, from grid location 12 G, for 2 pizzas. The order listing will appear as:
6:20 | 12 G -> 2

Two arrays will be used to keep track of order information. Pizzas is a two-
dimensional array that says how many pizzas were ordered at a grid
location and PizzaTime is a two-dimensional array holding the
corresponding order time (in minutes).

The Timer object will govern how often orders arrive. Since we assume
phone orders arrive in random 1 to 7 minute intervals, we define a
PhoneTicksMax variable that is a multiple of the ClockTicksMax
variable: PhoneTicksMax = Math.GetRandomNumber(7) * ClockTicksMax
Then, with each call to the TimerTickSub, we will increment a
PhoneTicks variable. When its value equals PhoneTicksMax, a new order
will be generated.

We need to make certain initializations for the order process. Make the
shaded modifications to the StartPauseButtonClick subroutine to set the
initial PhoneTicksMax (1 to 7) and to clear any past orders from the grid:
Sub StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus
= "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
'initialize clock
ClockHour = 6
ClockMinute = 0
ClockTime = "6:00"
Shapes.SetText(TimeDisplay, ClockTime) ClockTicks = 0
'initialize phone
PhoneTicks = 0
PhoneTicksMax = Math.GetRandomNumber(7) *
ClockTicksMax 'new grid
DrawGrid()
'clear order area
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110)
NumberOrders = 0
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) Timer.Resume() EndIf
EndSub
Add the two shaded lines to the DrawGrid subroutine to initialize the two
added variables: Sub DrawGrid GraphicsWindow.BrushColor =
"SteelBlue"
GraphicsWindow.FillRectangle(0, 0, 500, 520) 'GridR is row, GridC
is column; build one row at a time GridW = 22
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
For GridR = 0 To 20
For GridC = 0 To 20
DeliveryGridX[GridR][GridC] = 10 + GridC * GridW
DeliveryGridY[GridR][GridC] = 20 + GridR * GridW
Pizzas[GridR][GridC] = 0
PizzaTime[GridR][GridC] = 0
If (GridR = 0) Then If (GridC <> 0) Then 'column letters
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(DeliveryGridX[GridR]
[GridC] + 5, DeliveryGridY[GridR][GridC],
Text.GetCharacter(GridC + 64)) EndIf
ElseIf (GridC = 0) Then If (GridR <> 0) Then 'row numbers
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(DeliveryGridX[GridR]
[GridC], DeliveryGridY[GridR][GridC], GridR)
EndIf
Else
DeliveryGridColor[GridR][GridC] = "White"
DeliveryGridText[GridR][GridC] = ""
DrawGridSquare() EndIf
EndFor
EndFor
EndSub
When an order comes in, we will play a phone sound. We use the
phone.wav file for this sound. It is in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder. Copy the file to your program’s folder.

Now, add the shaded code to the TimerTickSub subroutine. This


incorporates the previously listed rules for phone orders and plays the
phone sound: Sub TimerTickSub 'Clock Update
ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf
ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If
(ClockMinute < 10) Then ClockTime = ClockTime + ":0" +
ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime) EndIf
'Phone Update
PhoneTicks = PhoneTicks + 1
If (PhoneTicks >= PhoneTicksMax) Then PhoneTicks = 0
Sound.Stop(Program.Directory + "\phone.wav")
Sound.Play(Program.Directory + "\phone.wav") If (ClockHour =
10 and ClockMinute >= 30) Then Goto LeavePhone EndIf
GetLocation: GridR = Math.GetRandomNumber(20) GridC =
Math.GetRandomNumber(20) If (Pizzas[GridR][GridC] <> 0) Then
Goto GetLocation EndIf
P = Math.GetRandomNumber(100) If (P >= 1 And P <= 30)
Then Pizzas[GridR][GridC] = 1
ElseIf (P >= 31 And P <= 50) Then Pizzas[GridR][GridC] = 2
ElseIf (P >= 51 And P <= 70) Then Pizzas[GridR][GridC] = 2
ElseIf (P >= 71 And P <= 85) Then Pizzas[GridR][GridC] = 2
Else
Pizzas[GridR][GridC] = 5
EndIf
PizzaTime[GridR][GridC] = ClockMinute + 60 * ClockHour
'print new order on grid
DeliveryGridColor[GridR][GridC] = "DarkGreen"
DeliveryGridText[GridR][GridC] = Pizzas[GridR][GridC]
DrawGridSquare() PhoneTicksMax =
Math.GetRandomNumber(7) * ClockTicksMax EndIf
LeavePhone:
EndSub

In this code, we play the phone sound. If it is past 10:30, the routine is
exited. Next, we select a random unselected row (GridR) and a random
column (GridC) for the order. Using the specified percentages, the number
of pizzas ordered is stored in the Pizzas array. Likewise, the order time is
stored in the PizzaTime array. The corresponding grid location is marked
with a dark green background and the number of pizzas ordered. Before
leaving the subroutine, a new random PhoneTicksMax value is computed.
This gives us the delay (between 1 and 7 minutes) until the next order is
phoned in.

Save and Run the program. Click Start Game and the phone should start
ringing, with orders shown in the delivery grid area. Here’s what my
window looked like after 10 orders or so:

Check that you can pause, restart and stop the game. The current code does
not list the orders in the message area. Let’s correct that. One problem is
that the message area is limited in size, holding only five orders. What if
there are more than five orders? We choose to list the five “oldest” orders.
These are the orders requiring the more immediate attention.

Add the shaded code to TimerTickSub to form the text string representing
the order and displaying it: Sub TimerTickSub 'Clock Update
ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf
ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If
(ClockMinute < 10) Then ClockTime = ClockTime + ":0" +
ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime) EndIf
'Phone Update
PhoneTicks = PhoneTicks + 1
If (PhoneTicks >= PhoneTicksMax) Then PhoneTicks = 0
Sound.Stop(Program.Directory + "\phone.wav")
Sound.Play(Program.Directory + "\phone.wav") If (ClockHour =
10 and ClockMinute >= 30) Then Goto LeavePhone EndIf
GetLocation: GridR = Math.GetRandomNumber(20) GridC =
Math.GetRandomNumber(20) If (Pizzas[GridR][GridC] <> 0) Then
Goto GetLocation EndIf
P = Math.GetRandomNumber(100) If (P >= 1 And P <= 30)
Then Pizzas[GridR][GridC] = 1
ElseIf (P >= 31 And P <= 50) Then Pizzas[GridR][GridC] = 2
ElseIf (P >= 51 And P <= 70) Then Pizzas[GridR][GridC] = 2
ElseIf (P >= 71 And P <= 85) Then Pizzas[GridR][GridC] = 2
Else
Pizzas[GridR][GridC] = 5
EndIf
PizzaTime[GridR][GridC] = ClockMinute + 60 * ClockHour
'build string listing order
NumberOrders = NumberOrders + 1
OrderString = ClockTime + " | "
If (ClockHour < 10) Then OrderString = " " + OrderString EndIf
If (GridR < 10) Then OrderString = OrderString + " "
EndIf
OrderString = OrderString + GridR + " "
OrderString = OrderString + Text.GetCharacter(GridC + 64) + "
‐> " + Pizzas[GridR][GridC] + " pizza(s)"
Order[NumberOrders] = OrderString DisplayOrders()
'print new order on grid
DeliveryGridColor[GridR][GridC] = "DarkGreen"
DeliveryGridText[GridR][GridC] = Pizzas[GridR][GridC]
DrawGridSquare() PhoneTicksMax =
Math.GetRandomNumber(7) * ClockTicksMax EndIf
LeavePhone:
EndSub

Notice how the grid column (GridC) is converted to a letter using the
GetCharacter method. The NumberOrders variable tells us how many
orders we have. The Order array holds the order strings. We put the newest
orders at the end of the array, hence the first five elements hold the five
oldest orders.

These oldest orders are listed in the message area using the DisplayOrders
subroutine: Sub DisplayOrders 'Display oldest five orders
'print orders ‐ clear first
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110) y = 80
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 14
For K = 1 To 5
If (K <= NumberOrders) Then GraphicsWindow.DrawText(525,
y, Order[K]) y = y + 20
EndIf
EndFor
EndSub
Save and Run the program again. Each order (up to five maximum) will
now show in the message area. Here’s a run with about 10 orders:

Next, we look at how to get the pizzas ready for delivery.


Code Design – Pizza Oven

Now that we know where the orders are coming from, we need to get some
pizzas baked. The rectangle under message area holds the oven. We can
bake, at most, eight pizzas at a time. This is another one of those rules we
chose – you can change it if you like. You would need to resize the pizza
graphic file -pizza.jpg. It is in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder. Copy the file to your program’s folder.

Once the pizzas are done baking (taking 10 minutes), they are placed in the
Baked area for storage. Up to 20 pizzas can be stored. Any pizzas baked
that cannot fit in this area are thrown out, costing you money. Add these
lines (in InitializeProgram) to set these rules and to load the pizza graphic:
'game variables
PizzasReadyMax = 20
PizzasBakingMax = 8
BakingTime = 10
PizzaImage = ImageList.LoadImage(Program.Directory + "\pizza.jpg")
We use one variable (PizzasBaking) to keep track of pizzas in the oven
and another (PizzasReady) to specify the number of pizzas baked and
stored. TotalPizzasBaked will keep track of all pizzas baked during a
single game. BakingMinutesLeft is used to tell us how many minutes
are left in the baking process.

Make the shaded modifications to the StartPauseButtonClick subroutine


to clear the pizza oven and to initialize variables (we assume we have baked
one oven load prior to opening the store) and buttons in “Stopped” state
and properly switch from “Playing” to “Paused” and back: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
'initialize clock
ClockHour = 6
ClockMinute = 0
ClockTime = "6:00"
Shapes.SetText(TimeDisplay, ClockTime) ClockTicks = 0
'initialize phone
PhoneTicks = 0
PhoneTicksMax = Math.GetRandomNumber(7) *
ClockTicksMax 'new grid
DrawGrid()
'clear order area
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110) NumberOrders
=0
'clear pizza oven
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(507, 270, 200, 100)
PizzasBaking = 0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible =
"true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible =
"true"
PizzasReady = PizzasBakingMax TotalPizzasBaked =
PizzasReady Shapes.SetText(PizzasReadyDisplay, PizzasReady)
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton)
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) 'show other buttons if
they were showing before If (AddPizzaVisible) Then
Controls.ShowControl(AddPizzaButton) EndIf
If (BakePizzaVisible) Then
Controls.ShowControl(BakePizzaButton) EndIf
Timer.Resume() EndIf
EndSub

When we start a game, we make sure the Add Pizza and Bake Pizza
buttons appear so pizzas can be baked. We also initialize two variables
(AddPizzaVisible and BakePizzaVisible) to know if either or both buttons
are visible. These values are used when switching from “Playing” mode to
“Paused” mode and back. When we go to “Paused” mode, we want the
buttons to be hidden so they cannot be clicked. Then, when we return to
“Playing” mode, we use these variables to return the buttons to their pre-
paused mode, visible or not.

We make the shaded changes to the StopGame subroutine to hide the oven
buttons when the game is stopped: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
'hide other buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
EndSub

Save and Run the program. Make sure the oven buttons appear when the
game starts, disappear when it is paused and reappear when the game is
restarted. Let’s add functionality to the buttons Pizzas are added to the oven
by clicking the Add Pizza button (AddPizzaButton) in the oven. With
each click of the button, we follow these steps:
➢ Increment PizzasBaking.
➢ Add a PizzaImage to the display.
➢ If maximum number of pizzas reached, hide AddPizzaButton.

Note once a pizza is placed in the oven, it cannot be removed.

Add shaded code to the ButtonClickSub subroutine to detect clicks on the


AddPizzaButton: Sub ButtonClickedSub B = Controls.LastClickedButton
If (B = StartPauseButton) Then ' start, stop, pause button
StartPauseButtonClick() ElseIf (B = ExitStopButton) Then 'exit,
stop button
ExitStopButtonClick()
ElseIf (B = AddPizzaButton) Then 'add pizza button
AddPizzaButtonClick()
EndIf
EndSub

Then, add the AddPizzaButtonClick subroutine that implement the needed


steps is: Sub AddPizzaButtonClick PizzasBaking = PizzasBaking + 1
If (PizzasBaking < 5) Then PizzaX = 507 + (PizzasBaking ‐ 1) * 50
PizzaY = 270
Else
PizzaX = 507 + (PizzasBaking ‐ 5) * 50
PizzaY = 320
EndIf
GraphicsWindow.DrawResizedImage(PizzaImage, PizzaX, PizzaY,
50, 50) If (PizzasBaking = PizzasBakingMax) Then
Controls.HideControl(AddPizzaButton) AddPizzaVisible = "false"
EndIf
EndSub

Save and Run the program. Click Start Game, then click Add Pizza a few
times. You should now be able to load the oven. Here I’ve put six pizzas in:
Make sure the Add Pizza button disappears when you reach eight pizzas in
the oven. Notice, too, that the Baked area reflects the initial load of eight
pizzas.

Once the oven is loaded, baking begins by clicking the Bake Pizza button.
The steps to follow once this button is clicked are:

➢ Change oven background color to red.


➢ Hide button controls.
➢ Display time pizzas will be done baking.
➢ Initialize BakingMinutesLeft.
➢ Set OvenGoing variable to “true”

We use a variable (OvenGoing) to know whether the oven is on or not.


Add shaded code to the ButtonClickSub subroutine to detect clicks on the
BakePizzaButton: Sub ButtonClickedSub B = Controls.LastClickedButton
If (B = StartPauseButton) Then ' start, stop, pause button
StartPauseButtonClick() ElseIf (B = ExitStopButton) Then 'exit,
stop button
ExitStopButtonClick() ElseIf (B = AddPizzaButton) Then 'add
pizza button
AddPizzaButtonClick()
ElseIf (B = BakePizzaButton) Then 'bake pizza button
BakePizzaButtonClick()
EndIf
EndSub

The corresponding BakePizzaButtonClick subroutine is: Sub


BakePizzaButtonClick If (PizzasBaking = 0) Then Goto
LeaveBakePizzaButton EndIf
'redraw red oven
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.FillRectangle(505, 245, 205, 170) For I = 1 To
PizzasBaking If (I < 5) Then PizzaX = 507 + (I ‐ 1) * 50
PizzaY = 270
Else
PizzaX = 507 + (I ‐ 5) * 50
PizzaY = 320
EndIf
GraphicsWindow.DrawResizedImage(PizzaImage, PizzaX,
PizzaY, 50, 50) EndFor
Controls.HideControl(AddPizzaButton) AddPizzaVisible = "false"
Controls.HideControl(BakePizzaButton) BakePizzaVisible = "false"
HOut = ClockHour MOut = ClockMinute + BakingTime If (MOut >
59) Then MOut = MOut ‐ 60
HOut = HOut + 1
EndIf
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 20
OvenText = "Pizza(s) Out At " + HOut + ":"
If (MOut < 10) Then OvenText = OvenText + "0"
EndIf
OvenText = OvenText + MOut GraphicsWindow.DrawText(510, 245,
OvenText) BakingMinutesLeft = BakingTime OvenGoing = "true"
LeaveBakePizzaButton: EndSub

In this code, we redraw the pizza oven (and pizzas) with a red background
and hide the buttons. Notice how we use various time variables to
determine and format the time the pizzas will leave the oven Save and Run
the program again. You should now be able load the oven and start the
baking process. Here’s my six pizzas baking:
Always remember, a red oven is a baking oven; a blue oven is a cold oven.
Sometimes when playing the game, you forget to start the baking process.

The Timer object will be used to time the baking process. We will check
this process every minute (the same as the clock), so all code for the baking
will be within the “clock loop” in the TimerTickSub subroutine. If
OvenGoing is “true”:

➢ Decrement BakingMinutesLeft. If BakingMinutesLeft = 0,


continue with next step.
➢ Play ding sound.
➢ Turn oven off.
➢ Increment PizzasReady and TotalPizzasBaked, check limit against
PizzasReadyMax.
➢ Set oven heading to Oven Off; change background color to blue.
➢ Remove all pizza images.
➢ Set PizzasBaking to 0.
➢ Show Add Pizza and Bake Pizza buttons.

Notice, when the baking is done, we will play a ding sound. We use the
ding.wav file for this sound. It is in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder. Copy the file to your program’s folder.

Add the shaded code to the ‘Clock Update’ section of the TimerTickSub
subroutine (we don’t show the entire subroutine – it’s getting very long!):
'Clock Update
ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf
ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If (ClockMinute
< 10) Then ClockTime = ClockTime + ":0" + ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime)
'pizzas in oven
If (OvenGoing) Then BakingMinutesLeft = BakingMinutesLeft ‐ 1
If (BakingMinutesLeft = 0) Then Sound.Stop(Program.Directory
+ "\ding.wav") Sound.Play(Program.Directory + "\ding.wav")
OvenGoing = "false"
PizzasReady = PizzasReady + PizzasBaking
TotalPizzasBaked = TotalPizzasBaked + PizzasBaking If
(PizzasReady > PizzasReadyMax) Then PizzasReady =
PizzasReadyMax EndIf
Shapes.SetText(PizzasReadyDisplay, PizzasReady)
DrawBlueOven() PizzasBaking = 0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible =
"true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible =
"true"
EndIf
EndIf
EndIf

We are almost ready to test everything, but need one more change. Notice if
we stop the game while the oven is running, the oven will still be red with
pizzas in it. Make the shaded changes in the StopGame subroutine to
handle this possibility: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") 'hide other
buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
OvenGoing = "false"
DrawBlueOven()
EndSub

Save and Run the program. Click Start Game, then click Add Pizza some
number of times. Click Bake Pizza and wait. After 10 minutes elapse (may
be 11 minutes depending on just when you click Bake Pizza), you will hear
a ding sound and the pizzas you baked will be moved to the Baked area.
Here’s my screen after baking six pizzas (the Baked area now shows 14);
notice, too, a few orders have come in:

Continue baking pizzas if you like – remember you can only store 20
pizzas. Make sure you can pause, restart and stop the game. Next, we see
how to move pizzas into the car and start delivering them.
Code Design – Load Car

A delivery car is available to take pizzas from the pizza parlor to the order
locations on the grid. A first step in the delivery process is to load pizzas
from the Baked area into the car. This is done by clicking Load button in
the Pizzas In Car box. We use a variable PizzasInCar to keep track of how
many pizzas are in the car. We assume a maximum of 10 pizzas can fit in
the car. Add this line (in InitializeProgram) with other program variables:
PizzasInCarMax = 10

Add the shaded code to the StartPauseButtonClick event to initialize the


car variable and to hide and show the Load button at proper times
(LoadVisible variable saves the status): Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
'initialize clock
ClockHour = 6
ClockMinute = 0
ClockTime = "6:00"
Shapes.SetText(TimeDisplay, ClockTime) ClockTicks = 0
'initialize phone
PhoneTicks = 0
PhoneTicksMax = Math.GetRandomNumber(7) *
ClockTicksMax 'new grid
DrawGrid()
'clear order area
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110) NumberOrders
=0
'clear pizza oven
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(507, 270, 200, 100) PizzasBaking
=0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible =
"true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible =
"true"
PizzasReady = PizzasBakingMax TotalPizzasBaked =
PizzasReady Shapes.SetText(PizzasReadyDisplay, PizzasReady)
PizzasInCar = 0
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.ShowControl(LoadButton) LoadVisible = "true"
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton)
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton)
Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) 'show other buttons if
they were showing before If (AddPizzaVisible) Then
Controls.ShowControl(AddPizzaButton) EndIf
If (BakePizzaVisible) Then
Controls.ShowControl(BakePizzaButton) EndIf
If (LoadVisible) Then Controls.ShowControl(LoadButton)
EndIf
Timer.Resume() EndIf
EndSub
Make the shaded change to the StopGame subroutine to hide the Load
button when the game is stopped: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") 'hide other
buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton)
OvenGoing = "false"
DrawBlueOven() EndSub

As stated, to load the car, you click the Load button in the box Pizzas In
Car. The steps followed (assuming there are pizzas to load) are simple. If
the maximum number of pizzas to load are available, load that number in
the car, otherwise load all the ready pizzas. Add shaded code to the
ButtonClickSub subroutine to detect clicks on the LoadButton: Sub
ButtonClickedSub B = Controls.LastClickedButton If (B =
StartPauseButton) Then ' start, stop, pause button
StartPauseButtonClick() ElseIf (B = ExitStopButton) Then 'exit,
stop button
ExitStopButtonClick() ElseIf (B = AddPizzaButton) Then 'add
pizza button
AddPizzaButtonClick() ElseIf (B = BakePizzaButton) Then
'bake pizza button
BakePizzaButtonClick()
ElseIf (B = LoadButton) Then 'load car button
LoadButtonClick()
EndIf
EndSub

The corresponding LoadButtonClick subroutine is: Sub LoadButtonClick


If (PizzasReady = 0) Then Goto LeaveLoadCarButton EndIf
If (PizzasReady > PizzasInCarMax) Then PizzasInCar = PizzasInCar
+ PizzasInCarMax PizzasReady = PizzasReady ‐ PizzasInCarMax
Else
PizzasInCar = PizzasInCar + PizzasReady PizzasReady = 0
EndIf
Shapes.SetText(PizzasReadyDisplay, PizzasReady)
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.HideControl(LoadButton) LoadVisible = "false"
LeaveLoadCarButton: EndSub

Notice we hide the Load button once the pizzas are loaded. In the motion
code, we use the LoadVisible status of this button to tell us whether the car
has pizzas available for delivery.

Save and Run the program. Start the game, bake some pizzas and load the
car. In this screen, I baked six pizzas, giving me 14 baked pizzas. I then
clicked the Load button. The car now has the maximum of 10 pizzas and
there are 4 pizzas remaining in the Baked area:
Next, let’s start delivering pizzas by driving the car around the delivery
grid.
Code Design – Move Car

Once there are pizzas in the car, we’re ready to start deliveries. Click on a
location on the delivery grid and the car (represented by a little yellow
image) travels from the pizza parlor to that location. You follow the same
process to have the car return to the pizza parlor when you need more
pizzas. There are lots of things to do here: define the pizza parlor location
(randomly set), detect clicks on the delivery grid, identify the clicked grid
location, and then move the car to the clicked location.

We need several variables to keep track of the car. PizzaR and PizzaC are
the row and column numbers for the pizza parlor location in the delivery
grid (marked by an X). DeliveryR and DeliveryC are the row and column
numbers for the delivery (the clicked location). CarR and CarC are the
row and column numbers for the current car location. DeltaR and DeltaC
are the difference between the car and delivery rows and columns. Lastly,
Mileage is the number of grid locations the car has moved through and
CarMoving indicates if the car is currently moving.

Make the shaded modifications to the StartPauseButtonClick subroutine


to initialize the pizza parlor location (also the initial car location), and
display a message for car location: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
'initialize clock
ClockHour = 6
ClockMinute = 0
ClockTime = "6:00"
Shapes.SetText(TimeDisplay, ClockTime) ClockTicks = 0
'initialize phone
PhoneTicks = 0
PhoneTicksMax = Math.GetRandomNumber(7) *
ClockTicksMax 'new grid
DrawGrid()
'clear order area
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110) NumberOrders
=0
'clear pizza oven
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(507, 270, 200, 100) PizzasBaking
=0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible =
"true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible =
"true"
PizzasReady = PizzasBakingMax TotalPizzasBaked =
PizzasReady Shapes.SetText(PizzasReadyDisplay, PizzasReady)
PizzasInCar = 0
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.ShowControl(LoadButton) LoadVisible = "true"
'initialize pizza parlor and car location
PizzaR = 1 + Math.GetRandomNumber(18) PizzaC = 1 +
Math.GetRandomNumber(18) DeliveryGridColor[PizzaR]
[PizzaC] = "Black"
DeliveryGridText[PizzaR][PizzaC] = "X"
Pizzas[PizzaR][PizzaC] = ‐1
GridRGridR == PizzaR GridR = PizzaR
GridC = PizzaC
DrawGridSquare() CarR = PizzaR
CarC = PizzaC
Mileage = 0
Message1 = "Car at Pizza Parlor:"
Message2 = CarR + " " + Text.GetCharacter(CarC + 64)
DisplayMessage() CarMoving = "false"
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton)
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) 'show other buttons if
they were showing before If (AddPizzaVisible) Then
Controls.ShowControl(AddPizzaButton) EndIf
If (BakePizzaVisible) Then
Controls.ShowControl(BakePizzaButton) EndIf
If (LoadVisible) Then Controls.ShowControl(LoadButton) EndIf
Timer.Resume() EndIf
EndSub

The pizza parlor is placed somewhere on the interior of the grid and marked
by an X (the corresponding Pizzas array element is set to -1 to mark this as
the pizza parlor). The car is positioned at this location and the mileage
initialized. A message is posted announcing the car is at the pizza parlor.
The two-lined message is displayed with this subroutine: Sub
DisplayMessage 'clear first
GraphicsWindow.BrushColor = "LightYellow"
GraphicsWindow.FillRectangle(505, 190, 205, 50)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 14
GraphicsWindow.DrawText(510, 195, Message1)
GraphicsWindow.DrawText(510, 215, Message2) EndSub

We make a shaded change to the StopGame subroutine to stop the car


when the game is stopped: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") 'hide other
buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) OvenGoing = "false"
DrawBlueOven()
CarMoving = "false"
EndSub

Save and Run the program. Click Start Game to make sure the pizza
parlor is marked and the proper message appears. Here’s my form:

The parlor is at location 18 P. That is also the car’s initial location (see the
displayed message). Let’s see how to indicate where we want the car to go
to and how to move the car.
Once orders come in and there are pizzas in the car, we can start making
deliveries. To move the car to a desired location on the delivery grid, we
simply click that location. When a grid location is clicked, we follow these
steps:

➢ Deliveries can only be made if the car is not already moving


(CarMoving is “false”), GameStatus is “Playing” and LoadVisible
is “false” (pizzas have been loaded in the car). If this is not the case,
exit; else continue.
➢ Determine row (DeliveryR) and column (DeliveryC) of clicked grid
square.
➢ Compute DeltaR and DeltaC. If DeltaR = 0 and DeltaC = 0, exit.
➢ Display message saying where the car is going.
➢ Set CarMoving to “true”.

To detect mouse clicks, we need this line at the end of InitializeProgram:


GraphicsWindow.MouseDown = MouseDownSub With this, each time a
MouseDown event occurs, the subroutine named MouseDownSub is
called. The code to perform the steps above will be in this subroutine.

Add this subroutine (MouseDownSub) to your program (this implements


all the above steps): Sub MouseDownSub x = GraphicsWindow.MouseX
y = GraphicsWindow.MouseY
If (GameStatus = "Playing") Then If (CarMoving = "false" And
LoadVisible = "false") Then DeliveryR = 1 + Math.Floor((y ‐
DeliveryGridY[1][1]) / GridW) DeliveryC = 1 + Math.Floor((x ‐
DeliveryGridX[1][1]) / GridW) If (DeliveryR < 1 Or DeliveryR > 20
Or DeliveryC < 1 Or DeliveryC > 20) Then Goto
LeaveMouseDownSub EndIf
DeltaR = DeliveryR ‐ CarR
DeltaC = DeliveryC ‐ CarC
If (DeltaR <> 0 Or DeltaC <> 0) Then Message1 = "Car
Going To:"
Message2 = DeliveryR + " " +
Text.GetCharacter(DeliveryC + 64) DisplayMessage()
CarMoving = "true"
EndIf
EndIf
EndIf
LeaveMouseDownSub: EndSub

Look at the math that converts a clicked (x, y) coordinate to row and
column values. We simply determine the distance of the clicked point from
the grid border in each direction and divide that by the width of a grid
square. The Math.Floor method knocks off any decimal result to give us a
whole number result. It’s pretty cool!

Save and Run the game. Click Start Game, click Load. You should now
be able to click the grid and have the clicked location appear in the message
area. Here’s my window after I clicked the square in Row 14, Column R:

Let’s see how to make the car travel to a selected location.


We will use two graphics files to represent the moving car. The files are
hcar.bmp (a horizontal car) and vcar.bmp (a vertical car). These are in the
KidGamesSB\KidGamesSB Programs\PizzaDelivery folder. Copy the
files to your program’s folder. Add these lines in InitializeProgram (after
code loading the pizza image file) to load the image files: HCarImage =
ImageList.LoadImage(Program.Directory + "\hcar.bmp") VCarImage =
ImageList.LoadImage(Program.Directory + "\vcar.bmp") The Timer object
will be used to move the car (recall long ago we set the Interval to 500 for
car motion). Clicking a grid location starts the process (sets CarMoving to
“true”). With each Tick event on the timer, we move the car one square.
We do vertical movements first, then horizontal movements. The steps to
accomplish this are:

➢ Erase car image in current position.


➢ If DeltaR <> 0: o Increment Mileage by 1.
o Set car image to VCarImage.
o Recompute CarR.
o Recompute DeltaR.
➢ If DeltaC <> 0: o Increment Mileage by 1.
o Set car image to HCarImage.
o Recompute CarC.
o Recompute DeltaC.
➢ Draw car at new location.
➢ If CarR = DeliveryR and CarC = DeliveryC: o Play beep sound.
o Set CarMoving to “false”
o If CarR = PizzaR and CarC = PizzaC, we’re back at the pizza
parlor, so: ➢ Establish message.
➢ Erase car image.
➢ Set PizzasInCar to 0 (must throw extras out due to health
department rules).
➢ Show LoadButton.
o If not at pizza parlor, we’re at the clicked location: ➢ Establish
message.
➢ Check delivery status.

This may seem like a lot of steps, but they are straightforward. Notice, in
particular, we display LoadButton when we return to the pizza parlor to
allow reloading of the car.

Notice, when the car stops, we will play a beep sound. We use the
carbeep.wav file for this sound. It is in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder. Copy the file to your program’s folder.

Add this ‘Car Update’ code at the end of the TimerTickSub subroutine
after the labeled LeavePhone: line(again, we don’t show the entire
subroutine). This code implements the above steps: 'Car Update ‐ updated
each tick
If (CarMoving) Then ''replace what is there
GridR = CarR
GridC = CarC
DrawGridSquare() 'move vertically first
If (DeltaR <> 0) Then Mileage = Mileage + 1
CarImage = VCarImage If (DeltaR > 0) Then CarR = CarR + 1
Else
CarR = CarR ‐ 1
EndIf
DeltaR = DeliveryR ‐ CarR
Else
Mileage = Mileage + 1
CarImage = HCarImage If (DeltaC > 0) Then CarC = CarC + 1
Else
CarC = CarC ‐ 1
EndIf
DeltaC = DeliveryC ‐ CarC
EndIf
GraphicsWindow.DrawImage(CarImage, DeliveryGridX[CarR]
[CarC] + 3, DeliveryGridY[CarR][CarC] + 3) If (CarR = DeliveryR
And CarC = DeliveryC) Then CarMoving = "false"
Sound.Stop(Program.Directory + "\carbeep.wav")
Sound.Play(Program.Directory + "\carbeep.wav") If (CarR =
PizzaR And CarC = PizzaC) Then Message1 = "Car at Pizza
Parlor:"
Message2 = CarR + " " + Text.GetCharacter(CarC + 64)
DisplayMessage() GridR = CarR
GridC = CarC
DrawGridSquare() PizzasInCar = 0
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.ShowControl(LoadButton) LoadVisible = "true"
Else
'check delivery status
EndIf
EndIf
EndIf

Notice once the car starts moving, it doesn’t stop until it reaches the clicked
location.

Save and Run the program. Click Start Game, then click Load to put
some pizzas in the car. Now, click a location on the grid and watch the car
go there. Here’s my window as the car is on its way to an order for 2 pizzas
at Row 5, Column A:
And, once the car arrives, I hear a beep and the window shows:

Now, click the pizza parlor (marked by an X) – you need to do this when
you need more pizzas to deliver. The car will return and disappear from the
screen. The message will indicate the car is at the pizza parlor. The Load
button will be visible and you will have zero pizzas in the car. As
mentioned, if the car returns with any pizzas, they must be thrown away due
to health department rules. At this point, you need to bake more pizzas and
reload the car if you want to go back on the road.

We’re getting close to being done. Just two more steps. We need to check
the status of any deliveries made and, lastly, we need to present the final
sales results when a game is stopped.
Code Design - Deliveries

Once the car arrives at a selected location, we need check the status of the
delivery at that location. We’ll also determine how the delivery affects our
earnings. The rules used for deliveries are:

➢ An on-time delivery is within 30 minutes. On-time deliveries net $10


for each pizza delivered. On-time deliveries will have green
backgrounds in the grid.
➢ A late delivery is between 30 and 60 minutes. Late deliveries net $5
for each pizza delivered. Late deliveries will have red backgrounds in
the grid.
➢ After 60 minutes, the order is cancelled and there is a $1 penalty for
each pizza not delivered.
➢ It costs $3 to bake each pizza.
➢ It costs $0.10 for each square the car travels through as it moves
around.

The above rules are implemented in several variables. Add these lines in
InitializeProgram with the other variable definitions: OrderMaxTime = 60
OrderLateTime = 30
NetSoldPizza = 10
NetLatePizza = 5
CostMissedPizza = 1
PizzaCost = 3
MileageCost = 0.1

We need variables to keep track of the various delivery quantities.


PizzasOnTime is the number of on-time deliveries, PizzasLate is the
number of late deliveries, MissedDeliveries is the number of missed
deliveries and TotalSales is the sum of all moneys taken in during
deliveries.
Make the shaded changes to the StartPauseButtonClick subroutine to
initialize the new variables: Sub StartPauseButtonClick If (GameStatus =
"Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
'initialize clock
ClockHour = 6
ClockMinute = 0
ClockTime = "6:00"
Shapes.SetText(TimeDisplay, ClockTime) ClockTicks = 0
'initialize phone
PhoneTicks = 0
PhoneTicksMax = Math.GetRandomNumber(7) *
ClockTicksMax 'new grid
DrawGrid()
'clear order area
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110) NumberOrders
=0
'clear pizza oven
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(507, 270, 200, 100) PizzasBaking
=0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible =
"true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible =
"true"
PizzasReady = PizzasBakingMax TotalPizzasBaked =
PizzasReady Shapes.SetText(PizzasReadyDisplay, PizzasReady)
PizzasInCar = 0
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.ShowControl(LoadButton) LoadVisible = "true"
'initialize pizza parlor and car location
PizzaR = 1 + Math.GetRandomNumber(18) PizzaC = 1 +
Math.GetRandomNumber(18) DeliveryGridColor[PizzaR]
[PizzaC] = "Black"
DeliveryGridText[PizzaR][PizzaC] = "X"
Pizzas[PizzaR][PizzaC] = ‐1
GridRGridR == PizzaR GridR = PizzaR
GridC = PizzaC
DrawGridSquare() CarR = PizzaR
CarC = PizzaC
Mileage = 0
Message1 = "Car at Pizza Parlor:"
Message2 = CarR + " " + Text.GetCharacter(CarC + 64)
DisplayMessage() CarMoving = "false"
PizzasOnTime = 0
PizzasLate = 0
MissedDeliveries = 0
TotalSales = 0
Amount = TotalSales FormatAmount()
Shapes.SetText(SalesDisplay, AmountText)
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton)
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) 'show other buttons if
they were showing before If (AddPizzaVisible) Then
Controls.ShowControl(AddPizzaButton) EndIf
If (BakePizzaVisible) Then
Controls.ShowControl(BakePizzaButton) EndIf
If (LoadVisible) Then Controls.ShowControl(LoadButton) EndIf
Timer.Resume() EndIf
EndSub

Notice we indicate on-time deliveries by green backgrounds in the grid and


late deliveries will have red backgrounds. The backgrounds are initialized at
green. Once 30 minutes elapse after an order is placed, we need to change
the corresponding display grid background to red. And, once 60 minutes
elapse for an order, it is removed from the grid with penalty costs incurred.
All of this is done in the TimerTickSub subroutine in the ‘Clock Update’
section. At each update, we follow these steps:

➢ Check to see if 60 minutes have elapsed for the first item in the
Order array. This is the oldest order and the only candidate for
removal. If 60 minutes have elapsed, increment MissedDeliveries by
the proper number of pizzas and remove the order from the delivery
grid and array.
➢ For all remaining array items, check to see if 30 minutes have
elapsed. If so, and the background isn’t already red, change it to red.

Make the shaded changes to the ‘Clock Update’ section of TimerTickSub


to implement these steps: 'Clock Update
ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf
ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If (ClockMinute
< 10) Then ClockTime = ClockTime + ":0" + ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime) 'pizzas in oven
If (OvenGoing) Then BakingMinutesLeft = BakingMinutesLeft ‐ 1
If (BakingMinutesLeft = 0) Then Sound.Stop(Program.Directory
+ "\ding.wav") Sound.Play(Program.Directory + "\ding.wav")
OvenGoing = "false"
PizzasReady = PizzasReady + PizzasBaking
TotalPizzasBaked = TotalPizzasBaked + PizzasBaking If
(PizzasReady > PizzasReadyMax) Then PizzasReady =
PizzasReadyMax EndIf
Shapes.SetText(PizzasReadyDisplay, PizzasReady)
DrawBlueOven() PizzasBaking = 0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible =
"true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible =
"true"
EndIf
EndIf
'check for late orders ‐ check to if first is expired ClockMinutes =
ClockMinute + 60 * ClockHour If (NumberOrders <> 0) Then For I
= 1 To NumberOrders S = Order[I]
GridR = Text.GetSubText(S, 9, 2) If
(Text.GetSubText(GridR, 1, 1) = " ") Then GridR =
Text.GetSubTextToEnd(GridR, 2) EndIf
GridC = text.GetCharacterCode(Text.GetSubText(S, 12, 1)) ‐
64
If (I = 1 And (ClockMinutes ‐ PizzaTime[GridR][GridC]) >=
OrderMaxTime) Then DeliveryGridColor[GridR][GridC] =
"White"
DeliveryGridText[GridR][GridC] = ""
DrawGridSquare() MissedDeliveries = MissedDeliveries
+ Pizzas[GridR][GridC]
Pizzas[GridR][GridC] = 0
'remove top item
ItemToRemove = 1
RemoveItem() ElseIf (ClockMinutes ‐ PizzaTime[GridR]
[GridC] >= OrderLateTime) Then
DeliveryGridColor[GridR][GridC] = "DarkRed"
DrawGridSquare() EndIf
EndFor
EndIf
EndIf

Note how we extract the row (GridR) and column (GridC) information
from the array item Order[I]. In the code, we use the previously defined
variables for on-time and late delivery times. The top item (ItemToRemove
= 1) is removed from the Order array using: Sub RemoveItem 'remove
ItemToRemove from Orders
If (ItemToRemove <> NumberOrders And NumberOrders <> 1)
Then For J = ItemToRemove To NumberOrders ‐ 1
Order[J] = Order[J + 1]
EndFor
EndIf
NumberOrders = NumberOrders ‐ 1
DisplayOrders() EndSub

This simply removes ItemToRemove from the Order array and moves the
rest of the array up one position. We will also use this routine when
processing orders.

Save and Run the game. Click Start Game. Watch as orders start out
green. After 30 minutes, they should turn red. After 60 minutes, they should
disappear from the grid. Make sure the program is working as desired. You
might like to change the ClockTicksMax value (temporarily) to a smaller
number to speed things up. Here’s my window after an hour and a half of
running time showing several ‘red’ orders (making no deliveries):

Any orders received between 6:00 and 6:30 have been removed from the
order list since they are older than one hour.

As seen previously, once the car reaches a delivery location, a check on the
delivery status is done. This check is completed in the ‘Car Update’
section of the TImerTickSub subroutine (we left a “hook” for this code).
Using our rules, the steps followed are:

➢ If the delivery location did not order any pizzas, post message and
exit.
➢ If the delivery location needs more pizza than is available, post
message and exit.
➢ If on-time delivery, increment PizzasOnTime by number of pizzas
ordered. Increment TotalSales accordingly.
➢ If late delivery, increment PizzasLate by number of pizzas ordered.
Increment TotalSales accordingly.
➢ If successful delivery (whether on-time or late), decrement
PizzasInCar and remove order from delivery grid and Order array.

Add the shaded code to ‘Car Update’ section of the TimerTickSub


subroutine to implement these steps: 'Car Update ‐ updated each tick
If (CarMoving) Then ''replace what is there
GridR = CarR
GridC = CarC
DrawGridSquare() 'move vertically first
If (DeltaR <> 0) Then Mileage = Mileage + 1
CarImage = VCarImage If (DeltaR > 0) Then CarR = CarR + 1
Else
CarR = CarR ‐ 1
EndIf
DeltaR = DeliveryR ‐ CarR
Else
Mileage = Mileage + 1
CarImage = HCarImage If (DeltaC > 0) Then CarC = CarC + 1
Else
CarC = CarC ‐ 1
EndIf
DeltaC = DeliveryC ‐ CarC
EndIf
GraphicsWindow.DrawImage(CarImage, DeliveryGridX[CarR]
[CarC] + 3, DeliveryGridY[CarR][CarC] + 3) If (CarR = DeliveryR
And CarC = DeliveryC) Then CarMoving = "false"
Sound.Stop(Program.Directory + "\carbeep.wav")
Sound.Play(Program.Directory + "\carbeep.wav") If (CarR =
PizzaR And CarC = PizzaC) Then Message1 = "Car at Pizza
Parlor:"
Message2 = CarR + " " + Text.GetCharacter(CarC + 64)
DisplayMessage() GridR = CarR
GridC = CarC
DrawGridSquare() PizzasInCar = 0
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.ShowControl(LoadButton) LoadVisible = "true"
Else
'check delivery status
Message1 = "Car at " + CarR + " " + Text.GetCharacter(CarC
+ 64) If (Pizzas[CarR][CarC] = 0) Then Message2 = "No
Pizza Wanted"
DisplayMessage() Else
If (Pizzas[CarR][CarC] > PizzasInCar) Then Message2 =
"Not Enough Pizzas"
DisplayMessage() Else
Message2 = "Delivered " + Pizzas[CarR][CarC] + "
Pizza(s)"
'see if on‐time
If ((ClockMinute + 60 * ClockHour) ‐
PizzaTime[CarR][CarC] <= OrderLateTime) Then
Message2 = Message2 + ": On‐Time" TotalSales =
TotalSales + Pizzas[CarR][CarC] * NetSoldPizza
PizzasOnTime = PizzasOnTime + Pizzas[CarR]
[CarC]
Else
Message2 = Message2 + ": Late!" TotalSales =
TotalSales + Pizzas[CarR][CarC] * NetLatePizza
PizzasLate = PizzasLate + Pizzas[CarR][CarC]
EndIf
DisplayMessage() Amount = TotalSales
FormatAmount() Shapes.SetText(SalesDisplay,
AmountText) PizzasInCar = PizzasInCar ‐
Pizzas[CarR][CarC]
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Pizzas[CarR][CarC] = 0
DeliveryGridColor[CarR][CarC] = "White"
DeliveryGridText[CarR][CarC] = ""
GridR = CarR
GridC = CarC
DrawGridSquare()
GraphicsWindow.DrawImage(CarImage,
DeliveryGridX[CarR][CarC] + 3,
DeliveryGridY[CarR][CarC] + 3) 'remove from list
For ItemToRemove = 1 To NumberOrders S =
Order[ItemToRemove]
R = Text.GetSubText(S, 9, 2) If
(Text.GetSubText(R, 1, 1) = " ") Then R =
Text.GetSubTextToEnd(R, 2) EndIf
C = Text.GetCharacterCode(Text.GetSubText(S,
12, 1)) ‐ 64
If (R = DeliveryR And C = DeliveryC) Then Goto
FoundOrder EndIf
EndFor
FoundOrder:
'remove ItemToRemove from orders
RemoveItem() EndIf
EndIf
EndIf
EndIf
EndIf

Notice how we search through the Order array to find the item
corresponding (matching row and column) to remove.

Run and Save the program. At long last, you can run the entire simulation.
You can accept orders, bake pizzas, load the car and direct the car to orders.
You can return to the pizza parlor when you need more pizzas. Try playing
for a while. Here’s my window after delivering pizzas for a little over an

hour:

Stop the game and program when you’re ready to go on. When you stop the
game, the only results currently shown are the total sales. A total financial
analysis should include costs to determine net profits. We’ll use a separate
window (a text window) to present this analysis.
Window Design – Sales Results

We will use a text window to display the sales results. Like the graphics
window, it helps to first make a sketch of the desired layout. Here is the
sketch for the Sales Results window:

At the top, we display the start and stop times. The left side of the window
displays sales information and the right side displays cost information.
Profits are displayed at the bottom.
Code Design – Sales Results

Add the shaded line to the StopGame subroutine to display the sales result
window: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") 'hide other
buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) OvenGoing = "false"
DrawBlueOven() CarMoving = "false"
SalesResults()
EndSub

We will build the SalesResults subroutine in stage. First, let’s just display
the header information: Sub SalesResults GraphicsWindow.Hide()
TextWindow.Show() TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Clear() TextWindow.Title = "Pizza Delivery Sales
Results"
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 2
TextWindow.WriteLine("PIZZA DELIVERY SALES RESULTS:")
TextWindow.WriteLine("") TextWindow.CursorLeft = 2
TextWindow.WriteLine("Start Time: 6:00 Stop Time: " + ClockTime)
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("")
TextWindowTextWindow..CursorLeftCursorLeft == 2
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 23
TextWindow.Write("Press Enter to Return to Pizza Delivery") T =
TextWindow.Read() TextWindow.Hide() GraphicsWindow.Show()
EndSub

We hide the graphics window and show the text window. Using the
CursorLeft and CursorTop properties, we position text in the window.
When done, we display ‘Press Enter to Return to Pizza Delivery’.

Save and Run the program. Click Start Game. Let the game run for a bit.
Then, click Stop Game. The results window with times will display:

As indicated, press Enter to return to the game.

Add the shaded code to SaleResults to compute and print sales information:
Sub SalesResults GraphicsWindow.Hide() TextWindow.Show()
TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Clear() TextWindow.Title = "Pizza Delivery Sales
Results"
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 2
TextWindow.WriteLine("PIZZA DELIVERY SALES RESULTS:")
TextWindow.WriteLine("") TextWindow.CursorLeft = 2
TextWindow.WriteLine("Start Time: 6:00 Stop Time: " + ClockTime)
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("")
'sales
TextWindow.CursorLeft = 2
TextWindow.WriteLine("Sales:") TextWindow.WriteLine("") 'on‐time
pizzas
T = PizzasOnTime + " On‐Time Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = PizzasOnTime * NetSoldPizza
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'late pizzas
T = PizzasLate + " Late Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = PizzasLate * NetLatePizza
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'total sales
TextWindow.WriteLine("") TextWindow.CursorLeft = 14
TextWindow.Write("Total Sales") Amount = TotalSales
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 23
TextWindow.Write("Press Enter to Return to Pizza Delivery") T =
TextWindow.Read() TextWindow.Hide() GraphicsWindow.Show()
EndSub

Save and Run. Play the game for a bit until you make a few deliveries.
Click Stop Game to see the added Sales:
Note how the dollar amounts are right justified to column 35.

Lastly, add the shaded code to SaleResults to display cost and profit
information: Sub SalesResults GraphicsWindow.Hide()
TextWindow.Show() TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Clear() TextWindow.Title = "Pizza Delivery Sales
Results"
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 2
TextWindow.WriteLine("PIZZA DELIVERY SALES RESULTS:")
TextWindow.WriteLine("") TextWindow.CursorLeft = 2
TextWindow.WriteLine("Start Time: 6:00 Stop Time: " + ClockTime)
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("") 'sales
TextWindow.CursorLeft = 2
TextWindow.WriteLine("Sales:") TextWindow.WriteLine("") 'on‐time
pizzas
T = PizzasOnTime + " On‐Time Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = PizzasOnTime * NetSoldPizza
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'late pizzas
T = PizzasLate + " Late Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = PizzasLate * NetLatePizza
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'total sales
TextWindow.WriteLine("") TextWindow.CursorLeft = 14
TextWindow.Write("Total Sales") Amount = TotalSales
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'costs
TextWindow.CursorLeft = 40
TextWindow.CursorTop = 7
TextWindow.WriteLine("Costs:") TextWindow.WriteLine("") 'pizzas
baked
T = TotalPizzasBaked + " Pizzas Baked"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = TotalPizzasBaked * PizzaCost
FormatAmount() TextWindow.CursorLeft = 70 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'mileage
T = Mileage + " Units Driven"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = Mileage * MileageCost
FormatAmount() TextWindow.CursorLeft = 70 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'missed deliveries
T = MissedDeliveries + " Missed Deliveries"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = MissedDeliveries *
CostMissedPizza FormatAmount() TextWindow.CursorLeft = 70 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'total costs
TextWindow.WriteLine("") TextWindow.CursorLeft = 49
TextWindow.Write("Total Costs") Costs = TotalPizzasBaked *
PizzaCost + Mileage * MileageCost + MissedDeliveries *
CostMissedPizza Amount = Costs FormatAmount()
TextWindow.CursorLeft = 70 ‐ Text.GetLength(AmountText)
TextWindow.WriteLine(AmountText) TextWindow.WriteLine("")
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("") Amount =
TotalSales ‐ Costs FormatAmount() TextWindow.CursorLeft = 10
TextWindow.Write("Total Profits: " + AmountText) If (ClockHour) >
6 Then 'only show hourly profits if been selling for more than one
hour Amount = (TotalSales ‐ Costs) / (ClockHour ‐ 6 + ClockMinute
/ 60) FormatAmount() TextWindow.CursorLeft = 40
TextWindow.Write("Hourly Profits: " + AmountText) EndIf
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 23
TextWindow.Write("Press Enter to Return to Pizza Delivery") T =
TextWindow.Read() TextWindow.Hide() GraphicsWindow.Show()
EndSub

Save and Run the program one last time. It is now complete. You should be
able to play a full game of Pizza Delivery and receive a sales report. Here’s
my window after a couple of orders have come in:

At 6:06, an order for 1 pizza was taken for delivery to Row 6, Column N
(also marked on grid). At 6:09, 5 pizzas were ordered at 12 H. I click Load
to get some pizzas. Then, I click 6 N on the grid.
My car goes there, beeps and makes a delivery. Then, I see:

The pizza was delivered on-time and I made $10. Next, I deliver 5 pizzas to
12 H, followed by 2 pizzas at 10 J. At that point, I am out of pizzas. I click
the X mark at 19 D to return to the pizza parlor.

I click the Add Pizza button 8 times to load the oven, then click Bake
Pizza to start the oven:
I could have started the baking process while I was out on the road,
speeding things up a bit. Now, I’m forced to wait several minutes while the
pizzas bake.
After playing for a little over an hour, my window looks like this:

I’ve got lots of orders and lots of pizzas going. The customer at 10 S has
been waiting a while (noted by the red grid background). I need to rush
those pizzas out.

I ran Pizza Delivery to 9:00 (closing before the usual 11:00). At that point,
I clicked Stop Game and the sales results window appears:
I did okay, making $200.30.
Pizza Delivery Program Listing

Here is the complete listing of the Pizza Delivery Small Basic program: '
Pizza Delivery
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 715
GraphicsWindow.Height = 520
GraphicsWindow.Title = "Pizza Delivery"
'draw new delivery grid
DrawGrid()
'draw clock and sales
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 5, 100, 60)
GraphicsWindow.FillRectangle(610, 5, 100, 60)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
GraphicsWindow.DrawText(510, 5, "Time")
GraphicsWindow.DrawText(615, 5, "Sales") ClockTime = "6:00"
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
TimeDisplay = Shapes.AddText(ClockTime) Shapes.Move(TimeDisplay,
535, 30) TotalSales = 0
'format as $0.00
Amount = TotalSales FormatAmount() SalesDisplay =
Shapes.AddText(AmountText) Shapes.Move(SalesDisplay, 620, 30)
'draw message area
GraphicsWindow.BrushColor = "LightYellow"
GraphicsWindow.FillRectangle(505, 190, 205, 50)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(505, 190, 205, 50)
GraphicsWindow.DrawRectangle(505, 70, 205, 120) 'draw pizza oven
DrawBlueOven() 'add pizza button
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
AddPizzaButton = Controls.AddButton("Add Pizza", 510, 380)
Controls.SetSize(AddPizzaButton, 95, 33) 'bake pizza button
BakePizzaButton = Controls.AddButton("Bake Pizza", 610, 380)
Controls.SetSize(BakePizzaButton, 95, 33) 'draw pizza loading boxes
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 420, 70, 60)
GraphicsWindow.FillRectangle(580, 420, 130, 60)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(510, 420, "Baked")
GraphicsWindow.DrawText(585, 420, "Pizzas in Car") PizzasReady = 0
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = 20
PizzasReadyDisplay = Shapes.AddText(PizzasReady)
Shapes.Move(PizzasReadyDisplay, 535, 445) PizzasInCar = 0
PizzasInCarDisplay = Shapes.AddText(PizzasInCar)
Shapes.Move(PizzasInCarDisplay, 615, 445) 'load button
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
LoadButton = Controls.AddButton("Load", 660, 445)
Controls.SetSize(LoadButton, 45, 33) 'start/pause button
StartPauseButton = Controls.AddButton("Start Game", 505, 485)
Controls.SetSize(StartPauseButton, 110, 33) 'exit/stop button
ExitStopButton = Controls.AddButton("Exit", 620, 485)
Controls.SetSize(ExitStopButton, 90, 33)
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) GameStatus = "Stopped"
'game variables
PizzasReadyMax = 20
PizzasBakingMax = 8
BakingTime = 10
PizzaImage = ImageList.LoadImage(Program.Directory + "\pizza.jpg")
PizzasInCarMax = 10
HCarImage = ImageList.LoadImage(Program.Directory + "\hcar.bmp")
VCarImage = ImageList.LoadImage(Program.Directory + "\vcar.bmp")
OrderMaxTime = 60
OrderLateTime = 30
NetSoldPizza = 10
NetLatePizza = 5
CostMissedPizza = 1
PizzaCost = 3
MileageCost = 0.1
Timer.Interval = 500
Timer.Pause() Timer.Tick = TimerTickSub ClockTicksMax = 6
Controls.ButtonClicked = ButtonClickedSub
GraphicsWindow.MouseDown = MouseDownSub EndSub

Sub DrawGrid GraphicsWindow.BrushColor = "SteelBlue"


GraphicsWindow.FillRectangle(0, 0, 500, 520) 'GridR is row, GridC is
column; build one row at a time GridW = 22
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
For GridR = 0 To 20
For GridC = 0 To 20
DeliveryGridX[GridR][GridC] = 10 + GridC * GridW
DeliveryGridY[GridR][GridC] = 20 + GridR * GridW
Pizzas[GridR][GridC] = 0
PizzaTime[GridR][GridC] = 0
If (GridR = 0) Then If (GridC <> 0) Then 'column letters
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(DeliveryGridX[GridR]
[GridC] + 5, DeliveryGridY[GridR][GridC],
Text.GetCharacter(GridC + 64)) EndIf
ElseIf (GridC = 0) Then If (GridR <> 0) Then 'row numbers
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(DeliveryGridX[GridR]
[GridC], DeliveryGridY[GridR][GridC], GridR) EndIf
Else
DeliveryGridColor[GridR][GridC] = "White"
DeliveryGridText[GridR][GridC] = ""
DrawGridSquare() EndIf
EndFor
EndFor
EndSub

Sub DrawGridSquare GraphicsWindow.BrushColor =


DeliveryGridColor[GridR][GridC]
GraphicsWindow.FillRectangle(DeliveryGridX[GridR][GridC],
DeliveryGridY[GridR][GridC], GridW, GridW)
GraphicsWindow.PenWidth = 1
GraphicsWindow.PenColor = "Black"
GraphicsWindow.DrawRectangle(DeliveryGridX[GridR][GridC],
DeliveryGridY[GridR][GridC], GridW, GridW)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 16
GraphicsWindow.DrawText(DeliveryGridX[GridR][GridC] + 6,
DeliveryGridY[GridR][GridC] + 1, DeliveryGridText[GridR][GridC])
EndSub

Sub FormatAmount Dollars = Math.Floor(Amount) Cents =


Math.Floor(100 * (Amount ‐ Dollars)) AmountText = "$" + Dollars + "."
If (Cents = 0) Then AmountText = AmountText + "00"
ElseIf (Cents < 10) Then AmountText = AmountText + "0" + Cents Else
AmountText = AmountText + Cents EndIf
EndSub

Sub DrawBlueOven 'draw pizza oven


GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 245, 205, 170)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(510, 245, "Oven Off") EndSub

Sub TimerTickSub 'Clock Update


ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf
ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If (ClockMinute
< 10) Then ClockTime = ClockTime + ":0" + ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime) 'pizzas in oven
If (OvenGoing) Then BakingMinutesLeft = BakingMinutesLeft ‐ 1
If (BakingMinutesLeft = 0) Then Sound.Stop(Program.Directory
+ "\ding.wav") Sound.Play(Program.Directory + "\ding.wav")
OvenGoing = "false"
PizzasReady = PizzasReady + PizzasBaking
TotalPizzasBaked = TotalPizzasBaked + PizzasBaking If
(PizzasReady > PizzasReadyMax) Then PizzasReady =
PizzasReadyMax EndIf
Shapes.SetText(PizzasReadyDisplay, PizzasReady)
DrawBlueOven() PizzasBaking = 0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible =
"true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible =
"true"
EndIf
EndIf
'check for late orders ‐ check to if first is expired ClockMinutes =
ClockMinute + 60 * ClockHour If (NumberOrders <> 0) Then For I
= 1 To NumberOrders S = Order[I]
GridR = Text.GetSubText(S, 9, 2) If (Text.GetSubText(GridR,
1, 1) = " ") Then GridR = Text.GetSubTextToEnd(GridR, 2)
EndIf
GridC = text.GetCharacterCode(Text.GetSubText(S, 12, 1)) ‐
64
If (I = 1 And (ClockMinutes ‐ PizzaTime[GridR][GridC]) >=
OrderMaxTime) Then DeliveryGridColor[GridR][GridC] =
"White"
DeliveryGridText[GridR][GridC] = ""
DrawGridSquare() MissedDeliveries = MissedDeliveries
+ Pizzas[GridR][GridC]
Pizzas[GridR][GridC] = 0
'remove top item
ItemToRemove = 1
RemoveItem() ElseIf (ClockMinutes ‐ PizzaTime[GridR]
[GridC] >= OrderLateTime) Then
DeliveryGridColor[GridR][GridC] = "DarkRed"
DrawGridSquare() EndIf
EndFor
EndIf
EndIf
'Phone update
PhoneTicks = PhoneTicks + 1
If (PhoneTicks >= PhoneTicksMax) Then PhoneTicks = 0
Sound.Stop(Program.Directory + "\phone.wav")
Sound.Play(Program.Directory + "\phone.wav") If (ClockHour = 10
and ClockMinute >= 30) Then Goto LeavePhone EndIf
GetLocation: GridR = Math.GetRandomNumber(20) GridC =
Math.GetRandomNumber(20) If (Pizzas[GridR][GridC] <> 0) Then Goto
GetLocation EndIf
P = Math.GetRandomNumber(100) If (P >= 1 And P <= 30) Then
Pizzas[GridR][GridC] = 1
ElseIf (P >= 31 And P <= 50) Then Pizzas[GridR][GridC] = 2
ElseIf (P >= 51 And P <= 70) Then Pizzas[GridR][GridC] = 2
ElseIf (P >= 71 And P <= 85) Then Pizzas[GridR][GridC] = 2
Else
Pizzas[GridR][GridC] = 5
EndIf
PizzaTime[GridR][GridC] = ClockMinute + 60 * ClockHour 'build
string listing order
NumberOrders = NumberOrders + 1
OrderString = ClockTime + " | "
If (ClockHour < 10) Then OrderString = " " + OrderString EndIf
If (GridR < 10) Then OrderString = OrderString + " "
EndIf
OrderString = OrderString + GridR + " "
OrderString = OrderString + Text.GetCharacter(GridC + 64) + " ‐> "
+ Pizzas[GridR][GridC] + " pizza(s)"
Order[NumberOrders] = OrderString DisplayOrders() 'print new
order on grid
DeliveryGridColor[GridR][GridC] = "DarkGreen"
DeliveryGridText[GridR][GridC] = Pizzas[GridR][GridC]
DrawGridSquare() PhoneTicksMax = Math.GetRandomNumber(7) *
ClockTicksMax EndIf
LeavePhone:
'Car Update ‐ updated each tick
If (CarMoving) Then ''replace what is there
GridR = CarR
GridC = CarC
DrawGridSquare() 'move vertically first
If (DeltaR <> 0) Then Mileage = Mileage + 1
CarImage = VCarImage If (DeltaR > 0) Then CarR = CarR + 1
Else
CarR = CarR ‐ 1
EndIf
DeltaR = DeliveryR ‐ CarR
Else
Mileage = Mileage + 1
CarImage = HCarImage If (DeltaC > 0) Then CarC = CarC + 1
Else
CarC = CarC ‐ 1
EndIf
DeltaC = DeliveryC ‐ CarC
EndIf
GraphicsWindow.DrawImage(CarImage, DeliveryGridX[CarR]
[CarC] + 3, DeliveryGridY[CarR][CarC] + 3) If (CarR = DeliveryR
And CarC = DeliveryC) Then CarMoving = "false"
Sound.Stop(Program.Directory + "\carbeep.wav")
Sound.Play(Program.Directory + "\carbeep.wav") If (CarR =
PizzaR And CarC = PizzaC) Then Message1 = "Car at Pizza
Parlor:"
Message2 = CarR + " " + Text.GetCharacter(CarC + 64)
DisplayMessage() GridR = CarR
GridC = CarC
DrawGridSquare() PizzasInCar = 0
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.ShowControl(LoadButton) LoadVisible = "true"
Else
'check delivery status
Message1 = "Car at " + CarR + " " + Text.GetCharacter(CarC
+ 64) If (Pizzas[CarR][CarC] = 0) Then Message2 = "No
Pizza Wanted"
DisplayMessage() Else
If (Pizzas[CarR][CarC] > PizzasInCar) Then Message2 =
"Not Enough Pizzas"
DisplayMessage() Else
Message2 = "Delivered " + Pizzas[CarR][CarC] + "
Pizza(s)"
'see if on‐time
If ((ClockMinute + 60 * ClockHour) ‐ PizzaTime[CarR]
[CarC] <= OrderLateTime) Then Message2 = Message2 + ":
On‐Time"
TotalSales = TotalSales + Pizzas[CarR][CarC] *
NetSoldPizza PizzasOnTime = PizzasOnTime +
Pizzas[CarR][CarC]
Else
Message2 = Message2 + ": Late!"
TotalSales = TotalSales + Pizzas[CarR][CarC] *
NetLatePizza PizzasLate = PizzasLate +
Pizzas[CarR][CarC]
EndIf
Amount = TotalSales FormatAmount()
Shapes.SetText(SalesDisplay, AmountText)
DisplayMessage() PizzasInCar = PizzasInCar ‐
Pizzas[CarR][CarC]
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Pizzas[CarR][CarC] = 0
DeliveryGridColor[CarR][CarC] = "White"
DeliveryGridText[CarR][CarC] = ""
GridR = CarR
GridC = CarC
DrawGridSquare()
GraphicsWindow.DrawImage(CarImage,
DeliveryGridX[CarR][CarC] + 3,
DeliveryGridY[CarR][CarC] + 3) 'remove from list
For ItemToRemove = 1 To NumberOrders S =
Order[ItemToRemove]
R = Text.GetSubText(S, 9, 2) If
(Text.GetSubText(R, 1, 1) = " ") Then R =
Text.GetSubTextToEnd(R, 2) EndIf
C = Text.GetCharacterCode(Text.GetSubText(S,
12, 1)) ‐ 64
If (R = DeliveryR And C = DeliveryC) Then Goto
FoundOrder EndIf
EndFor
FoundOrder:
'remove ItemToRemove from orders
RemoveItem() EndIf
EndIf
EndIf
EndIf
EndIf
EndSub

Sub ButtonClickedSub B = Controls.LastClickedButton If (B =


StartPauseButton) Then ' start, stop, pause button
StartPauseButtonClick() ElseIf (B = ExitStopButton) Then 'exit, stop
button
ExitStopButtonClick() ElseIf (B = AddPizzaButton) Then 'add pizza
button
AddPizzaButtonClick() ElseIf (B = BakePizzaButton) Then 'bake
pizza button
BakePizzaButtonClick() ElseIf (B = LoadButton) Then 'load car
button
LoadButtonClick() EndIf
EndSub

Sub StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus


= "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game") 'initialize
clock
ClockHour = 6
ClockMinute = 0
ClockTime = "6:00"
Shapes.SetText(TimeDisplay, ClockTime) ClockTicks = 0
'initialize phone
PhoneTicks = 0
PhoneTicksMax = Math.GetRandomNumber(7) * ClockTicksMax
'new grid
DrawGrid()
'clear order area
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110) NumberOrders = 0
'clear pizza oven
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(507, 270, 200, 100) PizzasBaking = 0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible = "true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible = "true"
PizzasReady = PizzasBakingMax TotalPizzasBaked = PizzasReady
Shapes.SetText(PizzasReadyDisplay, PizzasReady) PizzasInCar = 0
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.ShowControl(LoadButton) LoadVisible = "true"
'initialize pizza parlor and car location
PizzaR = 1 + Math.GetRandomNumber(18) PizzaC = 1 +
Math.GetRandomNumber(18) DeliveryGridColor[PizzaR][PizzaC] =
"Black"
DeliveryGridText[PizzaR][PizzaC] = "X"
Pizzas[PizzaR][PizzaC] = ‐1
GridR = PizzaR
GridC = PizzaC
DrawGridSquare() CarR = PizzaR
CarC = PizzaC
Mileage = 0
Message1 = "Car at Pizza Parlor:"
Message2 = CarR + " " + Text.GetCharacter(CarC + 64)
DisplayMessage() CarMoving = "false"
PizzasOnTime = 0
PizzasLate = 0
MissedDeliveries = 0
TotalSales = 0
Amount = TotalSales FormatAmount() Shapes.SetText(SalesDisplay,
AmountText) Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton, "Restart
Game") Controls.HideControl(ExitStopButton)
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) 'show other buttons if they
were showing before If (AddPizzaVisible) Then
Controls.ShowControl(AddPizzaButton) EndIf
If (BakePizzaVisible) Then
Controls.ShowControl(BakePizzaButton) EndIf
If (LoadVisible) Then Controls.ShowControl(LoadButton) EndIf
Timer.Resume() EndIf
EndSub

Sub ExitStopButtonClick If (GameStatus = "Playing") Then StopGame()


Else
Program.End() EndIf
EndSub

Sub StopGame GameStatus = "Stopped"


Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") 'hide other buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) OvenGoing = "false"
DrawBlueOven() CarMoving = "false"
SalesResults() EndSub

Sub DisplayOrders 'Display oldest five orders


'print orders ‐ clear first
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110) y = 80
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 14
For K = 1 To 5
If (K <= NumberOrders) Then GraphicsWindow.DrawText(525, y,
Order[K]) y = y + 20
EndIf
EndFor
EndSub

Sub AddPizzaButtonClick PizzasBaking = PizzasBaking + 1


If (PizzasBaking < 5) Then PizzaX = 507 + (PizzasBaking ‐ 1) * 50
PizzaY = 270
Else
PizzaX = 507 + (PizzasBaking ‐ 5) * 50
PizzaY = 320
EndIf
GraphicsWindow.DrawResizedImage(PizzaImage, PizzaX, PizzaY, 50,
50) If (PizzasBaking = PizzasBakingMax) Then
Controls.HideControl(AddPizzaButton) AddPizzaVisible = "false"
EndIf
EndSub

Sub BakePizzaButtonClick If (PizzasBaking = 0) Then Goto


LeaveBakePizzaButton EndIf
'redraw red oven
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.FillRectangle(505, 245, 205, 170) For I = 1 To
PizzasBaking If (I < 5) Then PizzaX = 507 + (I ‐ 1) * 50
PizzaY = 270
Else
PizzaX = 507 + (I ‐ 5) * 50
PizzaY = 320
EndIf
GraphicsWindow.DrawResizedImage(PizzaImage, PizzaX, PizzaY,
50, 50) EndFor
Controls.HideControl(AddPizzaButton) AddPizzaVisible = "false"
Controls.HideControl(BakePizzaButton) BakePizzaVisible = "false"
HOut = ClockHour MOut = ClockMinute + BakingTime If (MOut > 59)
Then MOut = MOut ‐ 60
HOut = HOut + 1
EndIf
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 20
OvenText = "Pizza(s) Out At " + HOut + ":"
If (MOut < 10) Then OvenText = OvenText + "0"
EndIf
OvenText = OvenText + MOut GraphicsWindow.DrawText(510, 245,
OvenText) BakingMinutesLeft = BakingTime OvenGoing = "true"
LeaveBakePizzaButton: EndSub

Sub LoadButtonClick If (PizzasReady = 0) Then Goto


LeaveLoadCarButton EndIf
If (PizzasReady > PizzasInCarMax) Then PizzasInCar = PizzasInCar +
PizzasInCarMax PizzasReady = PizzasReady ‐ PizzasInCarMax Else
PizzasInCar = PizzasInCar + PizzasReady PizzasReady = 0
EndIf
Shapes.SetText(PizzasReadyDisplay, PizzasReady)
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.HideControl(LoadButton) LoadVisible = "false"
LeaveLoadCarButton: EndSub

Sub DisplayMessage 'clear first


GraphicsWindow.BrushColor = "LightYellow"
GraphicsWindow.FillRectangle(505, 190, 205, 50)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 14
GraphicsWindow.DrawText(510, 195, Message1)
GraphicsWindow.DrawText(510, 215, Message2) EndSub

Sub MouseDownSub x = GraphicsWindow.MouseX


y = GraphicsWindow.MouseY If (GameStatus = "Playing") Then If
(CarMoving = "false" And LoadVisible = "false") Then DeliveryR = 1 +
Math.Floor((y ‐ DeliveryGridY[1][1]) / GridW) DeliveryC = 1 +
Math.Floor((x ‐ DeliveryGridX[1][1]) / GridW) If (DeliveryR < 1 Or
DeliveryR > 20 Or DeliveryC < 1 Or DeliveryC > 20) Then Goto
LeaveMouseDownSub EndIf
DeltaR = DeliveryR ‐ CarR
DeltaC = DeliveryC ‐ CarC
If (DeltaR <> 0 Or DeltaC <> 0) Then Message1 = "Car Going
To:"
Message2 = DeliveryR + " " + Text.GetCharacter(DeliveryC
+ 64) DisplayMessage() CarMoving = "true"
EndIf
EndIf
EndIf
LeaveMouseDownSub: EndSub

Sub RemoveItem 'remove ItemToRemove from Orders


If (ItemToRemove <> NumberOrders And NumberOrders <> 1) Then
For J = ItemToRemove To NumberOrders ‐ 1
Order[J] = Order[J + 1]
EndFor
EndIf
NumberOrders = NumberOrders ‐ 1
DisplayOrders() EndSub

Sub SalesResults GraphicsWindow.Hide() TextWindow.Show()


TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Clear() TextWindow.Title = "Pizza Delivery Sales Results"
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 2
TextWindow.WriteLine("PIZZA DELIVERY SALES RESULTS:")
TextWindow.WriteLine("") TextWindow.CursorLeft = 2
TextWindow.WriteLine("Start Time: 6:00 Stop Time: " + ClockTime)
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("") 'sales
TextWindow.CursorLeft = 2
TextWindow.WriteLine("Sales:") TextWindow.WriteLine("") 'on‐time
pizzas
T = PizzasOnTime + " On‐Time Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T) TextWindow.Write(T)
Amount = PizzasOnTime * NetSoldPizza FormatAmount()
TextWindow.CursorLeft = 35 ‐ Text.GetLength(AmountText)
TextWindow.WriteLine(AmountText) 'late pizzas
T = PizzasLate + " Late Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T) TextWindow.Write(T)
Amount = PizzasLate * NetLatePizza FormatAmount()
TextWindow.CursorLeft = 35 ‐ Text.GetLength(AmountText)
TextWindow.WriteLine(AmountText) 'total sales
TextWindow.WriteLine("") TextWindow.CursorLeft = 14
TextWindow.Write("Total Sales") Amount = TotalSales FormatAmount()
TextWindow.CursorLeft = 35 ‐ Text.GetLength(AmountText)
TextWindow.WriteLine(AmountText) 'costs
TextWindow.CursorLeft = 40
TextWindow.CursorTop = 7
TextWindow.WriteLine("Costs:") TextWindow.WriteLine("") 'pizzas
baked
T = TotalPizzasBaked + " Pizzas Baked"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T) TextWindow.Write(T)
Amount = TotalPizzasBaked * PizzaCost FormatAmount()
TextWindow.CursorLeft = 70 ‐ Text.GetLength(AmountText)
TextWindow.WriteLine(AmountText) 'mileage
T = Mileage + " Units Driven"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T) TextWindow.Write(T)
Amount = Mileage * MileageCost FormatAmount()
TextWindow.CursorLeft = 70 ‐ Text.GetLength(AmountText)
TextWindow.WriteLine(AmountText) 'missed deliveries
T = MissedDeliveries + " Missed Deliveries"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T) TextWindow.Write(T)
Amount = MissedDeliveries * CostMissedPizza FormatAmount()
TextWindow.CursorLeft = 70 ‐ Text.GetLength(AmountText)
TextWindow.WriteLine(AmountText) 'total costs
TextWindow.WriteLine("") TextWindow.CursorLeft = 49
TextWindow.Write("Total Costs") Costs = TotalPizzasBaked * PizzaCost
+ Mileage * MileageCost + MissedDeliveries * CostMissedPizza
Amount = Costs FormatAmount() TextWindow.CursorLeft = 70 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
TextWindow.WriteLine("") TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("") Amount = TotalSales
‐ Costs FormatAmount() TextWindow.CursorLeft = 10
TextWindow.Write("Total Profits: " + AmountText) If (ClockHour) > 6
Then 'only show hourly profits if been selling for more than one hour
Amount = (TotalSales ‐ Costs) / (ClockHour ‐ 6 + ClockMinute / 60)
FormatAmount() TextWindow.CursorLeft = 40
TextWindow.Write("Hourly Profits: " + AmountText) EndIf
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 23
TextWindow.Write("Press Enter to Return to Pizza Delivery") T =
TextWindow.Read() TextWindow.Hide() GraphicsWindow.Show()
EndSub
Pizza Delivery Game Program Review

The Pizza Delivery game program is now complete. Save and Run the
program and make sure it works as promised. Check that all functions work
correctly.

If there are errors in your implementation, go back over the steps of


window and code design. Go over the developed code – make sure you
understand how different parts of the program were coded. As mentioned in
the beginning of this chapter, the completed program is saved as
PizzaDelivery in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder.

While completing this program, new concepts and skills you should have
gained include:

➢ Proper steps in game design and game flow.


➢ How to develop and use simulation rules.
➢ How to add draw and label a grid structure.
➢ Adding to and deleting elements from an array (Order).
Pizza Delivery Game Program Enhancements

There are some ways to change the Pizza Delivery program. Some
possibilities are:

➢ The game difficulty can be adjusted if you like. By varying the time
between phone orders, the size of orders, the time needed to make a
delivery and the speed of the car, you can make the game easier or
harder. You would need some way for the player to select a difficulty.
➢ The current car cannot be re-routed once it starts. Modify the click
logic to re-route the car if desired.
➢ Once business builds, you might need a second car. Think of ways
you might be able to implement and control more than one car.
➢ This particular pizza parlor only makes one kind of pizza. This
simplifies the simulation somewhat. The car can stay out on the road
and deliver whatever pizzas are in the car. The oven can just keep
cranking out pizzas. It would be interesting to make different types of
pizzas available for order. You would have to know how many of
each are ordered, bake different types and load different types into
the car. This would be more like a real pizza delivery process.
9. Moon Landing Program
Review and Preview

The next program we build is a Moon Landing simulation. You are


the pilot of a lunar landing vehicle hovering over the moon. You must
land it safely using your thrusters. The program uses physics and
math to build a realistic simulation. You will learn how to use Small
Basic Shapes objects for animations.
Moon Landing Program Preview

In this chapter, we will build a Moon Landing game. In this simulation,


you control horizontal and vertical thrusters to maneuver your craft over a
landing pad on the surface of the moon. You want to make sure your
landing speed is slow enough that you don’t crash!

The finished program is saved as MoonLanding in the


KidGamesSB\KidGamesSB Programs\MoonLanding folder. Start Small
Basic and open the finished program. Run the program (click the Run
toolbar button or press <F5>). The game will appear in its ‘stopped’ state.
At this point, you can click the Start Game button to start the game, click
Options to change program options or click Exit to exit the program.

Like the Pizza Delivery game in the last chapter, there’s lots going on in the
Moon Landing game. So, before running the game, let’s describe its
operation. Prior to starting your descent to the moon, click Options to
choose your pilot level: Beginner, Novice, Junior, Senior, or Advanced.
Decide if you want Auto-Pilot On. And, select the type of distance units:
Meters or Feet.

The idea under each option is the same. Your vehicle is some height above
the surface of the moon at zero speed. Due to gravity (about one-sixth the
gravity on earth), you begin to accelerate toward the surface with a
corresponding change (goes negative) in your speed (a negative speed
indicates descent -positive speed indicates ascent). The current altitude and
speed are always displayed. You slow your descent by clicking on the
vertical thruster (Down button). This thruster counteracts gravity effects.
You must also adjust the lander’s lateral position relative to the landing pad.
Your current lateral position (- if to the left of the pad, + if to the right) and
lateral speed (- if moving to the left, + if moving to the right) are displayed.
Lateral motion of the lander is controlled using the two thruster controls
with Left and Right. Note the left thruster accelerates the lander to the right
and the right thruster accelerates the lander to the left. All thrusters operate
in ‘impulse’ mode. That is they just fire momentarily, changing the lander
speed in the corresponding direction. In ‘rocket scientist’ talk, we say the
thrusters impart a ‘delta V’ (change in velocity) to the lander.

The end goal is to be over the landing pad and going at a slow descent
speed (and slow lateral speed) by the time your altitude (height above the
landing pad) reaches zero. A safe landing is one where the final speed is
between 0 and -3 m/s (-10.0 ft/s); higher descent speeds result in a crash!
There are no crash penalties for missing the pad - your astronauts will just
have a long walk back to the home base!!

The Beginner option provides practice in slowing the lander’s vertical


speed. In the Novice option, you get practice controlling the vehicle in the
lateral direction. The computer will control the vertical thruster, you only
use the left and right thrusters. The Junior option moves you up to having
the ability to control all thrusters, and hence all motions on the lander. You
now have to position the lander over its pad and make sure you are going at
a slow vertical speed when landing, or else.

Then, the Senior option offers one more concern. With the Senior (and
Advanced) option, the fuel gauge shows you how much fuel you have
remaining. Each thruster burn uses some fuel (the vertical thruster uses
twice as much as the left and right thrusters). So now, you must land at a
safe speed, over the landing pad without running out of fuel. Once you run
out of fuel, your vehicle will just accelerate toward the lunar surface, most
likely resulting in a crash. The final level is Advanced, where your
thrusters work in a random manner, removing predictability from the
program. Constant adjustments are needed to keep the vehicle over the pad
and within speed limits. The program offers an Auto-Pilot mode to
demonstrate how the computer lands the vehicle. It actually does a fairly
decent job.

At any time during the program, you may pause the action by clicking
Pause Game. To restart, click Restart Game. To stop the program before
landing, click Stop Game. Once a landing is complete, the program stops
and you may view the final positions, speeds and fuel consumption. You
can then play again. Though this is lots of explanation – the Moon Landing
game is simple to operate. Start it, then use the three thruster buttons to
change the Altitude and Lateral position of the lander.

For now, click Options to change options. A text window will appear:

There are three options to set. First, choose your pilot level: Beginner,
Novice, Junior, Senior, or Advanced. Decide if you want Auto-Pilot On.
And, select the type of units for distance: Meters or Feet. For this example,
I chose the Senior level, with Auto-Pilot On and Meters as units:

After making your choices, the graphics window reappears with the game
still in the ‘stopped’ state. Click Start Game to get things going. Here’s the
game after 4.0 seconds (an update is given every 0.5 seconds) of running (I
paused at this point):
The graphic on the left shows the current position of the lander. Below this
are two small boxes, one green and one red. The red box indicates the
landing pad lateral location, while the green box marks the moon lander’s
current lateral position. When the two boxes coincide, the lander is over the
pad. Data on the right shows the lander is 558 meters above the pad,
dropping at 6.2 meters/second. It is 188 meters to the right (lateral position
is a negative number) of the pad. The auto-pilot is applying some left thrust,
accelerating the lander to a lateral speed of 2.2 meters/second. The fuel tank
appears full. Below the fuel gauge is a “trajectory plot,” showing past
vehicle positions (the circles) relative to the landing pad (with a suggested
straight-line descent trajectory). The thruster controls don’t appear since we
are using auto-pilot mode.

Here’s the screen after 36.5 seconds:

The computer has applied several bursts of vertical thrust to keep the lander
vertical speed reasonable and used a few right thrusts to move the lander to
the left, toward the pad. But, now it’s applying a left thrust to move it to the
right a little.
And, at 65.5 seconds:

The computer is still giving thrust adjustments to finalize landing. The pad
is nearby and things are looking good.
Finally, at 92.5 seconds, the lander is safely on the pad:

This a near perfect landing, under the safe landing speed of -3.0 m/s and
almost on top of the pad. Notice how all the graphic depictions of lander
position coincide with the numerical values.

Continue playing Moon Landing to understand its operation. Try different


options; try landing without the auto-pilot. Click Exit when you’re done to
stop the game. Look over the code, if you like.

The Moon Landing program demonstrates a principle used extensively in


engineering and mathematics disciplines, that of computer simulation.
Simulation is used to test designs and procedures before actually building
some device or structure. For example, we use simulators to train airline
pilots - this is much safer than training them in actual planes because if they
make a mistake, there is no loss of airplane or life. Before constructing a
building, we simulate it on a computer to see if it can withstand winds and
possible earthquakes. Using simulations, we can determine how a system
operates, learn how its performance varies as we change different
parameters, and develop operation procedures. In building Moon Landing,
we will use realistic numbers based on physics. You can adjust any of these
parameters as you choose.

You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.

We address window design and code design. We discuss how to implement


the various aspects of the game: physics of motion, altitude and lateral
distance calculations, line and shape graphics for the trajectory display and
advanced graphics such as shape animations for the lander motion display.
And, we’ll design a pretty good auto-pilot for demonstration and learning
purposes.
Moon Landing Window Design

Here is a sketch for the window layout for the Moon Landing program:

The rectangle to the left will display the lander animation. On the right side
of the window are several numerical displays for time and lander position
and speed. A fuel gauge may appear depending on options. Under the fuel
gauge is an area for drawing the lander trajectory. Thrust control buttons (if
present) are below this area. Three other button controls will be used: one to
start and stop the game, one to change options and one to exit the program.

We will now begin writing the code for Moon Landing. We will write the
code in several steps. As a first step, we will write the code that sets the
various window components, Then, we do some initial coding for the
start/pause and exit/stop buttons. Then, we add additional elements to the
game, one at a time. During the code development process, recognize you
may modify a particular subroutine several times before arriving at the
finished product.
Start a new program in Small Basic. Once started, we suggest you
immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Lander Viewer

We first establish the viewing area for the lander as it descends to the
landing pad. We also draw the guide (with the little green and red boxes)
underneath the viewing area.

Use this code:

' Moon Landing


InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 600
GraphicsWindow.Height = 400
GraphicsWindow.Title = "Moon Landing"
GraphicsWindow.BackgroundColor =
GraphicsWindow.GetColorFromRGB(192, 192, 255) ' draw view
screen
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(0, 0, 300, 400)
GraphicsWindow.BrushColor = "Black"
ViewerLeft = 10
ViewerTop = 10
ViewerWidth = 280
ViewerHeight = 360
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop,
ViewerWidth, ViewerHeight) GraphicsWindow.BrushColor =
"SlateGray"
GuideLeft = 10
GuideTop = 370
GuideWidth = 280
GuideHeight = 20
GraphicsWindow.FillRectangle(GuideLeft, GuideTop, GuideWidth,
GuideHeight) GraphicsWindow.BrushColor = "Red"
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
PadBox = Shapes.AddRectangle(15, 20)
GraphicsWindow.BrushColor = "Green"
LanderBox = Shapes.AddRectangle(15, 20) Shapes.Move(PadBox,
20, GuideTop) Shapes.Move(LanderBox, 100, GuideTop)
PadBoxWidth = 15
LanderBoxWidth = 15
EndSub

The first line of code calls a subroutine InitializeProgram where we will


put all code needed to set up the program for use. All remaining code here
goes in that subroutine. All the areas are drawn and dimensions defined.

Save and Run the program. The display area is seen:

The green box (representing lander position) and red box (representing
landing pad position) are in arbitrary locations. They will be correctly
positioned following initialization.
Window Design – Status Display

We use five pieces of information to provide the lander status: current time,
vertical position and speed, lateral position and speed. There is also a fuel
gauge (for higher pilot levels). Titling information for this display depends
on selected options:

➢ If PilotLevel = 1: o Label as Beginner.


o No fuel gauge.
➢ If PilotLevel = 2: o Label as Novice.
o No fuel gauge.
➢ If PilotLevel = 3: o Label as Junior.
o No fuel gauge.
➢ If PilotLevel = 4: o Label as Senior.
o Display fuel gauge.
➢ If PilotLevel = 5: o Label as Advanced.
o Display fuel gauge.
➢ Use proper units in position and speed labels based on MetricUnits
value (Meters if “true”, Feet if “false”)

Add these lines at the end of InitializeProgram: 'Default Options


PilotLevel = 1
AutoPilotOn = "false"
MetricUnits = "true"
'create display shapes
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
DisplayTime = Shapes.AddText("") Shapes.Move(DisplayTime, 420, 30)
DisplayVerticalPosition = Shapes.AddText("")
Shapes.Move(DisplayVerticalPosition, 420, 75) DisplayVerticalSpeed =
Shapes.AddText("") Shapes.Move(DisplayVerticalSpeed, 520, 75)
DisplayLateralPosition = Shapes.AddText("")
Shapes.Move(DisplayLateralPosition, 420, 100) DisplayLateralSpeed =
Shapes.AddText("") Shapes.Move(DisplayLateralSpeed, 520, 100)
SetDisplay()

This sets some default options (PilotLevel, AutoPilotOn, MetricUnits),


then establishes the Shapes objects we will use to display the lander status.

The display is initialized with a call to the SetDisplay subroutine: Sub


SetDisplay
'clear what is there first
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(300, 0, 300, 400) 'titling information
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
T = "Landing Control ‐ "
If (PilotLevel = 1) Then T = T + "Beginner"
ElseIf (PilotLevel = 2) Then T = T + "Novice"
ElseIf (PilotLevel = 3) Then T = T + "Junior"
ElseIf (PilotLevel = 4) Then T = T + "Senior"
ElseIf (PilotLevel = 5) Then T = T + "Advanced"
EndIf
GraphicsWindow.DrawText(310, 0, T) GraphicsWindow.FontSize =
16
GraphicsWindow.DrawText(310, 30, "Time (s)") If (MetricUnits)
Then GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf
GraphicsWindow.DrawText(310, 75, "Altitude")
GraphicsWindow.DrawText(310, 100, "Lateral") 'rectangles for data
display
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(390, 30, 90, 20)
GraphicsWindow.FillRectangle(390, 75, 90, 20)
GraphicsWindow.FillRectangle(390, 100, 90, 20)
GraphicsWindow.FillRectangle(490, 75, 90, 20)
GraphicsWindow.FillRectangle(490, 100, 90, 20)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(390, 30, 90, 20)
GraphicsWindow.DrawRectangle(390, 75, 90, 20)
GraphicsWindow.DrawRectangle(390, 100, 90, 20)
GraphicsWindow.DrawRectangle(490, 75, 90, 20)
GraphicsWindow.DrawRectangle(490, 100, 90, 20) 'fuel display
FuelLeft = 350
FuelTop = 130
FuelWidth = 240
FuelHeight = 20
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.DrawText(310, 130, "Fuel")
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(FuelLeft, FuelTop, FuelWidth,
FuelHeight) EndIf
UpdateStatus()
EndSub

This routine calls the UpdateStatus subroutine which for now is empty:
Sub UpdateStatus
EndSub

We will add code to this as we develop the lander equations.

Add this new code. Then, Save and Run the program. You should see the
empty status boxes properly labeled (no fuel gauge since it is Beginner
level):
Window Design – Trajectory Display

Below the displayed values, we will show the trajectory followed by the
lander as it descends. For now, it is just a blank, black rectangle.

Add the shaded code to the SetDisplay subroutine: Sub SetDisplay


'clear what is there first
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(300, 0, 300, 400) 'titling information
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
T = "Landing Control ‐ "
If (PilotLevel = 1) Then T = T + "Beginner"
ElseIf (PilotLevel = 2) Then T = T + "Novice"
ElseIf (PilotLevel = 3) Then T = T + "Junior"
ElseIf (PilotLevel = 4) Then T = T + "Senior"
ElseIf (PilotLevel = 5) Then T = T + "Advanced"
EndIf
GraphicsWindow.DrawText(310, 0, T) GraphicsWindow.FontSize =
16
GraphicsWindow.DrawText(310, 30, "Time (s)") If (MetricUnits)
Then GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf
GraphicsWindow.DrawText(310, 75, "Altitude")
GraphicsWindow.DrawText(310, 100, "Lateral") 'rectangles for data
display
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(390, 30, 90, 20)
GraphicsWindow.FillRectangle(390, 75, 90, 20)
GraphicsWindow.FillRectangle(390, 100, 90, 20)
GraphicsWindow.FillRectangle(490, 75, 90, 20)
GraphicsWindow.FillRectangle(490, 100, 90, 20)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(390, 30, 90, 20)
GraphicsWindow.DrawRectangle(390, 75, 90, 20)
GraphicsWindow.DrawRectangle(390, 100, 90, 20)
GraphicsWindow.DrawRectangle(490, 75, 90, 20)
GraphicsWindow.DrawRectangle(490, 100, 90, 20) 'fuel display
FuelLeft = 350
FuelTop = 130
FuelWidth = 240
FuelHeight = 20
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.DrawText(310, 130, "Fuel")
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(FuelLeft, FuelTop, FuelWidth,
FuelHeight) EndIf
'trajectory screen
TrajectoryLeft = 310
TrajectoryTop = 160
TrajectoryWidth = 280
TrajectoryHeight = 150
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight)
UpdateStatus()
EndSub
Save and Run the program to see the added rectangle:
Window Design – Add Buttons

The Moon Landing game uses six different button controls. Three buttons
are used to control thrust (LeftThrustButton, DownThrustButton,
RightThrustButton). Depending on program options, one, two, three, or
none of the thrust buttons may appear.

➢ If PilotLevel = 1: o Hide LeftThrustButton, RightThrustButton.


➢ If PilotLevel = 2: o Hide DownThrustButton.
➢ If PilotLevel = 3: o Show all thrust buttons.
➢ If PilotLevel = 4: o Show all thrust buttons.
➢ If PilotLevel = 5: o Show all thrust buttons.
➢ If Auto-Pilot On is checked: o Hide LeftThrustButton,
DownThrustButton, RightThrustButton o Display Auto-Pilot On
message

There is also a button to start, pause, and restart the game


(StartPauseButton), one to set program options (OptionsButton), and one
to stop the game and exit the program (StopExitButton).

Add this code to InitializeProgram (before the SetDisplay() line) to create


the six buttons: 'define buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
'thrust buttons
LeftThrustButton = Controls.AddButton("Left", 360, 320)
DownThrustButton = Controls.AddButton("Down", 425, 320)
RightThrustButton = Controls.AddButton("Right", 490, 320)
Controls.SetSize(LeftThrustButton, 60, 31)
Controls.SetSize(DownThrustButton, 60, 31)
Controls.SetSize(RightThrustButton, 60, 31) 'Other buttons
StartPauseButton = Controls.AddButton("Start Game", 305, 360)
Controls.SetSize(StartPauseButton, 110, 31) OptionsButton =
Controls.AddButton("Options", 417, 360) ExitStopButton =
Controls.AddButton("Exit", 485, 360) Controls.SetSize(ExitStopButton,
110, 31) Add the shaded code to SetDisplay to establish which thrust
buttons are displayed based on selected options (PilotLevel and
AutoPilotOn): Sub SetDisplay
'clear what is there first
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(300, 0, 300, 400) 'titling information
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
T = "Landing Control ‐ "
If (PilotLevel = 1) Then T = T + "Beginner"
ElseIf (PilotLevel = 2) Then T = T + "Novice"
ElseIf (PilotLevel = 3) Then T = T + "Junior"
ElseIf (PilotLevel = 4) Then T = T + "Senior"
ElseIf (PilotLevel = 5) Then T = T + "Advanced"
EndIf
GraphicsWindow.DrawText(310, 0, T) GraphicsWindow.FontSize =
16
GraphicsWindow.DrawText(310, 30, "Time (s)") If (MetricUnits)
Then GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf
GraphicsWindow.DrawText(310, 75, "Altitude")
GraphicsWindow.DrawText(310, 100, "Lateral") 'rectangles for data
display
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(390, 30, 90, 20)
GraphicsWindow.FillRectangle(390, 75, 90, 20)
GraphicsWindow.FillRectangle(390, 100, 90, 20)
GraphicsWindow.FillRectangle(490, 75, 90, 20)
GraphicsWindow.FillRectangle(490, 100, 90, 20)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(390, 30, 90, 20)
GraphicsWindow.DrawRectangle(390, 75, 90, 20)
GraphicsWindow.DrawRectangle(390, 100, 90, 20)
GraphicsWindow.DrawRectangle(490, 75, 90, 20)
GraphicsWindow.DrawRectangle(490, 100, 90, 20) 'fuel display
FuelLeft = 350
FuelTop = 130
FuelWidth = 240
FuelHeight = 20
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.DrawText(310, 130, "Fuel")
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(FuelLeft, FuelTop, FuelWidth,
FuelHeight) EndIf
'trajectory screen
TrajectoryLeft = 310
TrajectoryTop = 160
TrajectoryWidth = 280
TrajectoryHeight = 150
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight)
'thrust buttons
If (AutoPilotOn) Then Controls.HideControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.HideControl(RightThrustButton) LeftThrustVisible =
"false"
DownThrustVisible = "false"
RightThrustVisible = "false"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 20
GraphicsWindow.DrawText(390, 320, "Auto‐Pilot On") Else
'buttons based on level
If (PilotLevel = 1) Then Controls.HideControl(LeftThrustButton)
Controls.ShowControl(DownThrustButton)
Controls.HideControl(RightThrustButton) LeftThrustVisible =
"false"
DownThrustVisible = "true"
RightThrustVisible = "false"
ElseIf (PilotLevel = 2) Then
Controls.ShowControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.ShowControl(RightThrustButton) LeftThrustVisible =
"true"
DownThrustVisible = "false"
RightThrustVisible = "true"
Else
Controls.ShowControl(LeftThrustButton)
Controls.ShowControl(DownThrustButton)
Controls.ShowControl(RightThrustButton) LeftThrustVisible
= "true"
DownThrustVisible = "true"
RightThrustVisible = "true"
EndIf
EndIf
UpdateStatus()
EndSub

The values of LeftThrustVisible, DownThrustVisible, and


RightThrustVisible will be used when going to and from paused state in
the game.

Save and Run the program. For the default options, a single thrust button
(DownThrustButton) will appear along with the three program control
buttons:

The window design is complete.


Code Design – Initial Steps

The program begins in ‘stopped’ state. We have three choices – either click
Start Game to start, click Options to change options, or click Exit to exit
the program. We will write code for each of these options in reverse order.
But before we do, add this line at the end of InitializeProgram to set the
GameStatus: GameStatus = "Stopped"

First, we need to be able to detect button clicks so now add this line at the
end of InitializeProgram: Controls.ButtonClicked = ButtonClickedSub
With this, each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.

The code for exiting is simple. It is placed in the ButtonClickedSub


subroutine: Sub ButtonClickedSub B = Controls.LastClickedButton If (B =
ExitStopButton) Then 'exit, stop button
ExitStopButtonClick() EndIf
EndSub

When Exit is clicked, it calls the ExitStopButtonClick subroutine: Sub


ExitStopButtonClick If (GameStatus = "Stopped") Then Program.End()
EndIf
EndSub

Run the program. Click Exit to make sure the game stops.

If the user clicks Options, we want to change program options. We will use
the Small Basic text window to establish game options. Add the shaded
code to the ButtonClickedSub subroutine: Sub ButtonClickedSub B =
Controls.LastClickedButton If (B = ExitStopButton) Then 'exit, stop button
ExitStopButtonClick()
ElseIf (B = OptionsButton) Then 'change options
SetOptions()
EndIf
EndSub

The options are set in the SetOptions subroutine – add this routine: Sub
SetOptions
GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title =
"Moon Landing"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("MOON LANDING OPTIONS")
TextWindow.WriteLine("") GetPilotLevel:
TextWindow.CursorLeft = 3
TextWindow.WriteLine("What level pilot do you want?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Beginner, 2‐Novice, 3‐Junior, 4‐Senior, 5‐
Advanced) ") PilotLevel = TextWindow.ReadNumber() If (PilotLevel
< 1 Or PilotLevel > 5) Then Goto GetPilotLevel EndIf
GetAutoPilotOn:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("Do you want Auto‐Pilot on?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Yes, 2‐No) ") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto
GetAutoPilotOn EndIf
If (T = 1) Then AutoPilotOn = "true"
Else
AutoPilotOn = "false"
EndIf
GetUnits: TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("What units of distance do you want to
use?") TextWindow.CursorLeft = 3 <</p> TextWindow.Write("(1‐
Meters, 2‐Feet) ")
T = TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto
GetUnits
EndIf
If (T = 1) Then MetricUnits = "true"
Else
MetricUnits = "false"
EndIf
SetDisplay()
TextWindow.Hide() GraphicsWindow.Show() EndSub

This routine hides the graphics window, displays a text window and asks
the user questions necessary to establish the three options (PilotLevel,
AutoPilotOn, MetricUnits). Once the questions are answered, the display
is reset and the program returns to the game in ‘stopped’ state.

We will do the calculations in this program in metric units. This means all
positions will be in meters and all speeds will be in meters/second. If a user
selects ‘Feet’ units, we need to multiply all results by the number than
converts meters to feet. This number will be stored in a variable Multiplier.
Find this segment of code in SetDisplay: If (MetricUnits) Then
GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf

Add the two shaded lines:

If (MetricUnits) Then
Multiplier = 1.0
GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
Multiplier = 3.2808
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf
The Multiplier is 1.0 for metric units (meters) and 3.2808 for units of feet.
This says there are 3.2808 feet in a meter.

Save and Run the program. Click the Options button the change options:

Make your choices and press Enter after each. The Moon Landing
window will again appear.

Try each combination of Pilot Level, Auto-Pilot On and MetricUnits


selection. Make sure the proper titling information and displayed
components appear based on your choices. Here’s the screen for Beginner
(PilotLevel = 1), no Auto-Pilot, Meters units:

Novice, no Auto-Pilot, Feet units:


Junior, no Auto-Pilot, Feet units:

Senior, no Auto-Pilot, Meter units:


Note the fuel gauge now appears. The Advanced window looks identical.

With AutoPilotOn set to “true”, the thrust buttons do not appear


(Advanced level shown):
Code Design – Starting, Clock Display

We begin adding elements to the Moon Landing program. A key element is


the Timer object. It is used to update the elapsed time, all computed values
and all graphics elements of the program. In this initialization stage, we’ll
just use it to update the time (Time). We will also write code to start, pause
and restart the Timer object using the StartPauseButton. There are several
steps to get things set up.

Add this code at the end of InitializeProgram to initialize the Timer


object.

Timer.Interval = 500
Timer.Tick = TimerTickSub Timer.Pause() We will update the program
every 500 milliseconds (0.5 seconds). Add the TimerTickSub
subroutine: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
UpdateStatus()
EndSub

This updates the time at each Tick event and calls UpdateStatus where
Time is displayed in its location in the window.

Add this shaded code to the end of UpdateStatus: Sub UpdateStatus


'Time
NumberToFormat = Time DecimalFormat()
Shapes.SetText(DisplayTime, NumberText)
EndSub

The UpdateStatus subroutine uses the DecimalFormat subroutine to


insure a single decimal point in the display: Sub DecimalFormat
WholeNumber = Math.Floor(NumberToFormat) Decimal =
Math.Floor(10 * (NumberToFormat ‐ WholeNumber)) NumberText =
Text.Append(WholeNumber, ".") If (Decimal = 0) Then NumberText
= Text.Append(NumberText, "0") Else
NumberText = Text.Append(NumberText, Decimal) EndIf
EndSub

We’re almost ready to see the time displayed. We need some way to turn on,
pause and restart the timer. Two buttons control the game,
StartPauseButton and ExitStopButton. These buttons have certain
interactions. The StartPauseButton can have one of three possible actions
based on GameStatus. If the GameStatus is “Stopped” when the button is
clicked, the game is initialized and put in playing mode using:

➢ Change GameStatus to “Playing”


➢ Change caption to Pause Game.
➢ Change caption of ExitStopButton to Stop Game.
➢ Hide OptionsButton.
➢ Initialize Time to zero.
➢ Start Timer.

When GameStatus is “Playing” and the button is clicked, we enter pause


mode:

➢ Change GameStatus to “Paused”


➢ Pause Timer.
➢ Change caption to Restart Game.
➢ Hide any thrust control buttons that are being used.
➢ Hide ExitStopButton.

When Game Status is “Paused” and the button is clicked, we re-enter


playing mode:

➢ Change GameStatus to “Playing”


➢ Change caption to Pause Game.
➢ Reshow any thrust control buttons that are being used.
➢ Show ExitStopButton.
➢ Start Timer.

Add shaded code to the ButtonClickSub routine to detect clicks on


StartPauseButton: Sub ButtonClickedSub B =
Controls.LastClickedButton If (B = ExitStopButton) Then 'exit, stop button
ExitStopButtonClick() ElseIf (B = OptionsButton) Then 'change
options
SetOptions()
ElseIf (B = StartPauseButton) Then ' start, stop, pause button
StartPauseButtonClick()
EndIf
EndSub

And, finally, the code that covers the above steps is in the
StartPauseButtonClick subroutine: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton)
Controls.HideControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.HideControl(RightThrustButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) 'show other buttons if
they were showing before
If (LeftThrustVisible) Then
Controls.ShowControl(LeftThrustButton) EndIf
If (DownThrustVisible) Then
Controls.ShowControl(DownThrustButton) EndIf
If (RightThrustVisible) Then
Controls.ShowControl(RightThrustButton) EndIf
Timer.Resume() EndIf
EndSub

Save and Run the program. Make sure the clock time is increasing in 0.5
second increments. Here’s the window for a Senior level, no auto-pilot and
Feet units after 5.5 seconds:

As expected, all thruster controls appear, as does the fuel gauge. Make sure
the Pause Game and Restart Game buttons affect the clock and buttons
correctly. The Stop Game button doesn’t work yet – let’s fix that.
When a player clicks Stop Game (the ExitStopButton in “Playing”
mode), the following should happen:

➢ Change GameStatus to “Stopped”


➢ Stop Timer.
➢ Change caption to Exit.
➢ Change caption of StartPauseButton to Start Game.
➢ Show OptionsButton.

Recall we already wrote code for clicking on ExitStopButton in


“Stopped” mode. Make the shaded change to ExitStopButtonClick: Sub
ExitStopButtonClick If (GameStatus = "Stopped") Then Program.End()
Else
StopGame()
EndIf
EndSub

Now, add the StopGame subroutine: Sub StopGame


GameStatus = "Stopped"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton, "Start
Game") Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.ShowControl(OptionsButton) EndSub

Save and Run Moon Landing. You should now be able to start the game,
pause the game, restart the game and stop the game. You can also stop the
program. Make sure everything works as desired. Next, let’s write the code
that implements the math and physics behind the lunar module motion.
Code Design – Physics of Moon Landing

Are you ready for a little physics and math? Don’t worry it won’t be too
scary. We want to write the equations that describe the position and speed of
the landing vehicle as it descends to the moon. As a first step, we need to
define a coordinate system to do our computations. We assume all graphics
elements (the lander, the thrust flames, the pad) are contained within a
rectangular region named Landscape:

A point within this region is specified by a “Cartesian” pair, (x, y). In the
diagram, note the x (horizontal) coordinate increases from left to right,
starting at 0 and extending to LandscapeWidth - 1. The y (vertical)
coordinate increases from top to bottom, starting at 0 and ending at
LandscapeHeight - 1. All measurements are integers and in units of pixels.
In this program, we will assume one pixel corresponds to one meter of
distance.

Each graphic element is also contained within a rectangle. The lander


element (Lander) is located at the Cartesian pair (LanderX, LanderY)
within the Landscape rectangle:

The Lander has width LanderWidth and height LanderHeight. LanderX


and LanderY are assigned some initial values (at Time = 0). The lander
speeds are LanderXSpeed and LanderYSpeed, in the respective
directions. LanderXSpeed and LanderYSpeed are initialized at zero.

Once we have initial values for LanderX, LanderY, LanderXSpeed and


LanderYSpeed, they are “updated” (incremented or decremented) at
various times. The speeds are updated whenever thrust is used. Both the
speeds and positions are updated with each change of the running clock,
governed by the Timer object. Let’s look at the “update” equations, first
seeing how thrust affects speed.

The vertical thruster affects only the vertical speed, LanderYSpeed. We


assume this, and the horizontal thrusters, work in what rocket scientists call
“impulse mode,” imparting an immediate speed change (delta) in the
opposite direction. If that change in speed is called YDelta, the equation for
changing speed in the y-direction when the thruster is applied is:
LanderYSpeed = LanderYSpeed ‐ YDelta ' Down thruster applied The
vertical (down) thruster slows the vertical speed, providing the slowing we
need for a proper landing.
The horizontal thrusters change horizontal speed, LanderXSpeed.
Assuming an impulse change in speed (XDelta), the equations for speed in
the x-direction when the thrusters are applied are: LanderXSpeed =
LanderXSpeed + XDelta ' Left thruster applied and

LanderXSpeed = LanderXSpeed ‐ XDelta ' Right thruster applied The


left thruster moves the lander toward the right; the right thruster moves
the lander to the left.

Knowing the horizontal (LanderXSpeed) and vertical (LanderYSpeed)


speeds of the lander, how do we determine the positions LanderX and
LanderY? We use the classic formula that tells us: Distance Traveled =
Speed x Time Traveled

This equation is derived using a branch of mathematics known as calculus.


Use that fact to impress your friends. This computation is done every time
the clock updates its time (in TimerTickSub). Let T be the interval of the
timer control in seconds: T = Timer.Interval / 1000

The 1000 divisor converts the Interval property (in milliseconds) to


seconds.

Knowing T, the X and Y position of the lander are updated each clock cycle
using: LanderX = LanderX + SpeedX * T

LanderY = LanderY + SpeedY * T

You should see that SpeedX * T is the horizontal distance traveled by the
lander in one clock cycle and SpeedY * T is the corresponding vertical
distance.

The vertical speed of the lander (LanderYSpeed) also changes with each
clock cycle. Gravity tends to accelerate (increase speed) the lander toward
the moon surface. If the gravitational acceleration is Gravity, in T seconds,
the speed is increased according to: LanderYSpeed = LanderYSpeed +
Gravity * T
The gravity on the moon is about 1/6th the gravity on earth (which is 9.8
meters per second per second; the vertical speed changes 9.8 m/s every
second). So, in our program, we will use: Gravity = 9.8 / 6.0

You can change this if you like to simulate other planets or see how fast a
lander descends on the earth (just use 9.8).

We will also allow for possible changes in the horizontal speed


(LanderXSpeed) with each clock cycle. If we apply a horizontal thrust in
one direction, the lander will continue to move in that direction until a
thrust is applied in the opposite direction. To counteract that effect, if the
lander is moving horizontally, we will apply a “drag” term that tends to
slow it down, even without thrust. If this amount of slowing is Drag, the
corresponding speed corrections are: LanderXSpeed = LanderXSpeed ‐
Drag ' LanderXSpeed > 0

LanderXSpeed = LanderXSpeed + Drag ' LanderXSpeed < 0

Notice there is no slowing if the lander is not moving (LanderXSpeed = 0).

This completes the “update” equations for the lunar lander’s position and
speed. Let’s modify the program to include these equations and get the
lander moving. We initialize LanderX, LanderY, SpeedX, and SpeedY in
the StartPauseButtonClick subroutine. For now, we set all the variables to
zero. Later, we will randomly assign LanderX. The shaded changes are (we
don’t show the entire subroutine, just the modified part): Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
LanderX = 0
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub

Next, add these four variables to InitializeProgram (after setting


GameStatus) to define speed changes, gravity and drag effects: 'Simulation
variables
XDelta = 1.2
YDelta = 2.4
Gravity = 9.8 / 6.0
Drag = 0.1

Each of these numbers (except Gravity) was found by trial and error. You
may want to make changes – feel free.

Vertical thrust is control by the button control DownThrustButton.


Horizontal thrust is control by LeftThrustButton and RightThrustButton.
Add the shaded code to ButtonClickSub to detect clicks on these buttons:
Sub ButtonClickedSub B = Controls.LastClickedButton If (B =
ExitStopButton) Then 'exit, stop button
ExitStopButtonClick() ElseIf (B = OptionsButton) Then 'change
options
SetOptions()
ElseIf (B = StartPauseButton) Then ' start, stop, pause button
StartPauseButtonClick()
ElseIf (B = DownThrustButton) Then 'down thrust
DownThrustButtonClick() ElseIf (B = LeftThrustButton) Then
'left thrust
LeftThrustButtonClick() ElseIf (B = RightThrustButton) Then
'right thrust
RightThrustButtonClick()
EndIf
EndSub

The corresponding subroutines for each of these clicks is: Sub


DownThrustButtonClick If (GameStatus = "Playing") Then LanderYSpeed
= LanderYSpeed ‐ YDelta EndIf
EndSub

Sub LeftThrustButtonClick If (GameStatus = "Playing") Then


LanderXSpeed = LanderXSpeed + XDelta EndIf
EndSub

Sub RightThrustButtonClick If (GameStatus = "Playing") Then


LanderXSpeed = LanderXSpeed ‐ XDelta EndIf
EndSub

These routines update the different speeds due to thrust (when GameStatus
is “Playing”).

Recall both lander position and speed are updated in the TimerTickSub
subroutine. The steps to follow in this subroutine are:

➢ Update time display (already implemented).


➢ Update LanderX and LanderY.
➢ Display status of lander.
➢ Update LanderXSpeed and LanderYSpeed.

Add the shaded code to the TimerTickSub subroutine: Sub TimerTickSub


'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub

Add this code segment at the end of the UpdateStatus subroutine to display
lander status. This code displays position and speed information (converting
to proper units using the Multiplier variable): 'positions
Shapes.SetText(DisplayVerticalPosition, Math.Floor(LanderY *
Multiplier)) Shapes.SetText(DisplayLateralPosition,Math.Floor(LanderX
* Multiplier)) 'speeds
NumberToFormat = LanderYSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayVerticalSpeed, NumberText) NumberToFormat =
LanderXSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayLateralSpeed, NumberText) Save and Run the
program. Select Junior Pilot Level. Click Start Game. The time will
increment, as will the position and speed in the vertical direction (labeled
as Altitude). Click the down thrust button and see the vertical speed
decrease. Try the horizontal thrusters to make sure you can move the
lander left and right (labeled as Lateral). Here’s the middle of a run I
made:

The module has moved down 62 meters and is traveling at 1.7


meters/second upward (I’ve applied a lot of thrust; y is decreasing). The
lander has moved 86 meters to the right and is moving at 8.6 m/s to the
right. Make sure you can move the lander left and right, up and down.
Remaining Work

Believe it or not, the basics of the moon landing program are done – we can
control the lander and see its location and speed (in displayed values). But
there is still a lot of work to be done to make this an appealing, useful
game. Let’s outline the needed work, then get started.

As implemented, the displayed information is not very useful. Knowing the


distance from the left of the landscape rectangle (LanderX) and the
distance from the top of the rectangle (LanderY) does not tell us what we
really need to know – how far we are from the landing pad. So, as a first
task, we will place the landing pad on the landscape and display distances
and speeds relative to the pad. To do this, we need to know image sizes, so
we will load the images used in the program (though we won’t display them
yet). We will add landing detection logic. We will also implement our first
graphic indication of lander location (using the little boxes under the viewer
on the left of the window).

We need to modify the game to account for differences among the various
pilot levels, including monitoring fuel consumption. And, of course, we
need some sounds. After this, we will have a working ‘text version’ of the
game.

The text version of the game is acceptable, but graphics elements add that
extra flair. The first graphic element we add is the trajectory display under
the status displays. After tackling the trajectory display, we move on to the
animated display of the lander moving across the landscape to the landing
pad And the final addition to Moon Landing will be development of an
auto-pilot. This serves two purposes. First, the auto-pilot is actually needed
for the Novice pilot level (where you control horizontal thrust, while the
computer handles the vertical thrust). Second, auto-pilot mode is a good
way to learn how to control the landing vehicle.

As we said, there’s a lot of work to do. Let’s get going.


Code Design – Landing Pad Distances

As noted, the current displayed values do not answer the question – how far
are we from the landing pad? Let’s add the Pad element (a red rectangle) to
the landscape element and determine what these distances are. The Pad
element is located at (PadX, PadY), has width PadWidth and height
PadHeight:

In this sketch, we’ve added two distances. Altitude specifies how far the
lander is above the pad. It is the distance from the bottom of the lander to
the top of the pad: Altitude = (LandscapeHeight ‐ PadHeight) ‐ (LanderY +
LanderHeight) Notice Altitude decreases as the lander goes down
(LanderY increases). This is opposite of our basic coordinate system, but it
makes sense here. Altitude represents the height above the pad – it
approaches zero as the lander gets closer to the pad.

The other distance, Lateral, specifies the horizontal distance from the
lander to the pad. It is the distance from the middle of the lander to the
middle of the pad: Lateral = (LanderX + (LanderWidth / 2)) ‐ (PadX +
(PadWidth / 2)) Notice Lateral is positive if the lander is the right of the
pad, negative if it is to the left of the pad. Lateral is zero if the lander is
directly centered over the pad.
We can add these equations to our program to get proper indication of
Altitude and Lateral, but there’s one problem. We don’t know the sizes of
the various elements (Landscape, Pad, Lander). We’ll fix that now. The
Landscape will simply be a black rectangular area 640 pixels wide by 700
pixels high. Recall we assume one pixel equals one meter in distance.
Similarly, the landing pad (Pad) will be a red rectangle 105 pixels wide (the
width of the Lander) and 15 pixels high.

The lander is displayed by the lander.gif file included in the


KidGamesSB\KidGamesSB Programs\MoonLanding folder. You can
open it in the Windows Paint program or any other drawing program you
might have. The Lander image is 105 pixels wide by 115 pixels high

(shown actual size):

Add this code to InitializeProgram (after setting Simulation variables) to


specify the needed dimensions: 'Set dimensions
LandscapeWidth = 640
LandscapeHeight = 700
LanderWidth = 105
LanderHeight = 115
PadWidth = LanderWidth PadHeight = 15

Having the display element dimensions now allows us to modify the code
to include computations and display of Altitude and Lateral. The
computations of Altitude and Lateral will be placed in the UpdateStatus
subroutine. Make the shaded changes to this subroutine: Sub UpdateStatus
'Time
NumberToFormat = Time DecimalFormat()
Shapes.SetText(DisplayTime, NumberText) 'Positions
Altitude = (LandscapeHeight ‐ PadHeight) ‐ (LanderY +
LanderHeight) Lateral = (LanderX + (LanderWidth / 2)) ‐ (PadX +
(PadWidth / 2)) If (Altitude > 0) Then
Shapes.SetText(DisplayVerticalPosition, Math.Floor(Altitude *
Multiplier))
Else
Shapes.SetText(DisplayVerticalPosition, 0) EndIf
If Math.Abs(Lateral) < 1 Then
Shapes.SetText(DisplayLateralPosition, "Above") Else
Shapes.SetText(DisplayLateralPosition, Math.Floor(Lateral *
Multiplier))
EndIf
'speeds
NumberToFormat = ‐LanderYSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayVerticalSpeed, NumberText)
NumberToFormat = LanderXSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayLateralSpeed, NumberText) EndSub

We have the equations for Altitude and Lateral. For the vertical position
label, LanderY has been replaced by Altitude (limiting the value to zero).
In the vertical speed label, a negative sign has been added to show negative
speed is altitude descent. For horizontal position, LanderX has been
replaced by Lateral (with a note of Above if within 1 meter).

We can almost test the changes. We need to place the pad on the landscape.
With each new game, we will randomly set the horizontal position of the
pad (and the lander) within the landscape rectangle. The pad will be placed
on the bottom of the rectangle. Make the shaded changes in the
StartPauseButtonClick subroutine: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
PadX = Math.GetRandomNumber(LandscapeWidth ‐ PadWidth)
‐1
PadY = LandscapeHeight ‐ PadHeight
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub

These new lines randomly place the lander and pad within the bounds of the
Landscape width.

Save and Run the program. Again, chose Junior level pilot and click Start
Game. You will now see the altitude drop as the speed becomes larger in a
negative sense (descent). The lateral position will approach zero as the
lander gets closer to the pad. Here’s my screen after 9.5 seconds:
Code Design – Landing Detection

If you continue to run the game as programmed, Altitude will stop at zero
(it takes around 26 to 27 seconds), but the speed will continue to increase
and you can still apply thrust. We need someway to detect a landing and
determine if it is a safe landing. We will do this in the TimerTickSub
subroutine. In InitializeProgram, add this variable (with other such
variables) defining the maximum acceptable landing speed:
SafeLandingSpeed = 3.0

Now, add the shaded changes to the TimerTickSub subroutine: Sub


TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
'check for landing
If (Altitude <= 0) Then 'display message
If (AutoPilotOn) Then Message = "Auto‐Pilot "
Else
Message = "You "
EndIf
'crash?
If (LanderYSpeed > SafeLandingSpeed) Then Message =
Message + "Crashed!"
Else
Message = Message + "Landed Safely"
EndIf
'display message
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 24
GraphicsWindow.DrawText(20, 30, Message) StopGame()
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub

In this code, once Altitude reaches zero, the Timer is paused, the thruster
buttons are removed and the appropriate landing message is displayed
based on the vertical speed (and based on whether auto-pilot is on). No
penalty is incurred for missing the landing pad (large value of Lateral).

Save and Run the program again. Now, once the lander altitude reaches
zero, the program will stop and display status upon landing. Here’s my
screen:
I crashed badly. At this point, you can choose to play another game, set
options or exit the program.

One little problem. If you click Start Game, the “You Crashed” message
will still be there. Add the shaded line to StartPauseButtonClick
subroutine to erase this message when starting a new game: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
'clear any previous message from viewer
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop,
ViewerWidth, 60) Controls.SetButtonCaption(StartPauseButton,
"Pause Game") Controls.SetButtonCaption(ExitStopButton, "Stop
Game") Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
PadX = Math.GetRandomNumber(LandscapeWidth ‐ PadWidth)
‐1
PadY = LandscapeHeight ‐ PadHeight UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub
If you like rerun the previous example, then press Start Game to make sure
the message disappears.

Though no penalty is assessed for missing the pad in the horizontal


direction, it is useful to know during and after flight how close the lander is
to the pad. One indication is the numeric lateral position value. Graphic
indicators would be an improvement. The first graphic indicator we use will
be the green (LanderBox) and red (PadBox) rectangles (Shapes objects) in
what we call the guide area (Guide) under the viewer area. The green box
represents the lander horizontal position, while the red box represents the
landing pad. The center of each box within Guide should coincide with the
center of the lander and pad within the landscape background. Or, using
simple proportion, the corresponding distances from the left side of Guide
are: LanderBoxX = (LanderX + LanderWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ LanderBoxWidth / 2

PadBoxX = (PadX + PadWidth / 2) * (GuideWidth / LandscapeWidth) ‐


PadBoxWidth / 2

These calculations are ‘relative to’ the Guide area, or assume the upper left
corner of Guide is at (0, 0). Prior to using them for positioning the boxes,
they are offset by the true upper corner (GuideLeft, GuideTop).

Add the shaded line to the StartPauseButtonClick subroutine to establish


the location of the PadBox: Sub StartPauseButtonClick If (GameStatus =
"Stopped") Then .
.
.
'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
PadX = Math.GetRandomNumber(LandscapeWidth ‐ PadWidth)
‐1
PadBoxX = (PadX + PadWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ PadBoxWidth / 2
Shapes.Move(PadBox, GuideLeft + PadBoxX, GuideTop)
PadY = LandscapeHeight ‐ PadHeight UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub

Add this code segment at the end of the UpdateStatus subroutine: 'location
box
LanderBoxX = (LanderX + LanderWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ LanderBoxWidth / 2
If (LanderBoxX < 0) Then LanderBoxX = 0
ElseIf (LanderBoxX > (GuideWidth ‐ LanderBoxWidth)) Then
LanderBoxX = GuideWidth ‐ LanderBoxWidth EndIf
Shapes.Move(LanderBox, GuideLeft + LanderBoxX, GuideTop) The
code makes sure LanderBox stays within Guide.

Save and Run the program. The green and red boxes will show the relative
horizontal location of the lander to the pad. Here’s my screen:
The lander (green) is to the right of the pad (red). This is also reflected in
the positive Lateral value of 204 meters.

If I apply right thrust, the lander will move to the left nearing the pad.
Here’s the screen a little later:
I’m now just 98 meters to the right, moving to the left. I think you see how
the graphic indicators are really nice. We’ll add even nicer ones (trajectory
panel and animated graphics) later. But, first, just a few more changes to
complete needed coding.
Code – Pilot Levels and Sounds

The Moon Landing game is becoming more complete. The last big change
is adding the graphics features. Before doing that we need to add just a few
other changes.

Some changes related to selected Pilot Level need implementation. First,


the two highest levels (Senior and Advanced) have fuel limitations. We
have added the code that displays the fuel gauge for these levels. We now
need code that computes fuel usage and displays remaining fuel in the
gauge. FuelRemaining keeps track of remaining fuel. And, add these
variables in InitializeProgram: MaximumFuel = 100
HFuel = 0.5
VFuel = 1.0

MaximumFuel is the amount of initial fuel, HFuel is the fuel used by a


burst on a horizontal thruster and VFuel is fuel used by a vertical thruster
burst.

The amount of fuel and fuel gauge are initialized in the


StartPauseButtonClick subroutine (changes are shaded): Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then .
.
.
'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
PadX = Math.GetRandomNumber(LandscapeWidth ‐ PadWidth)
‐1
PadBoxX = (PadX + PadWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ PadBoxWidth / 2
Shapes.Move(PadBox, GuideLeft + PadBoxX, GuideTop) PadY
= LandscapeHeight ‐ PadHeight
FuelRemaining = MaximumFuel If (PilotLevel > 3) Then
GraphicsWindow.BrushColor = "Green"
GraphicsWindow.FillRectangle(FuelLeft, FuelTop,
FuelWidth, FuelHeight) EndIf
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub

For pilot levels without a fuel gauge, we will leave FuelRemaining at


MaximumFuel, so the fuel tank is always full.

Fuel is used with each burst of a thruster. Modify each thruster


(DownThrustButtonClick, LeftThrustButtonClick,
RightThrustButtonClick) subroutine as follows (changes are shaded): Sub
DownThrustButtonClick If (GameStatus = "Playing") Then
If (FuelRemaining > 0) Then
LanderYSpeed = LanderYSpeed ‐ YDelta
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
VFuel EndIf
EndIf
EndIf
EndSub
Sub LeftThrustButtonClick If (GameStatus = "Playing") Then
If (FuelRemaining > 0) Then
LanderXSpeed = LanderXSpeed + XDelta
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

Sub RightThrustButtonClick If (GameStatus = "Playing") Then


If (FuelRemaining > 0) Then
LanderXSpeed = LanderXSpeed ‐ XDelta
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

With these changes, thrust is not allowed if there is no fuel and


FuelRemaining is decremented only for pilot levels greater than 3 (Senior
and Advanced).

Lastly, the fuel gauge is updated in the UpdateStatus subroutine. Add this
code segment at the end of the subroutine: 'fuel
If (PilotLevel > 3) Then If (FuelRemaining > 0) Then FuelValue =
(FuelRemaining / MaximumFuel) * FuelWidth Else
FuelValue = 0
EndIf
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(FuelLeft + FuelValue, FuelTop,
FuelWidth ‐ FuelValue, FuelHeight) EndIf

We ‘black’ out the portion of the Fuel area corresponding to fuel used.
Save and Run the program. Select Senior pilot level. As the lander
descends, apply horizontal and vertical thrust and watch the fuel gauge
drop. Here’s my window after several bursts of thrust:

In the lowest pilot level (Beginner; PilotLevel = 1), the landing pad needs
to be directly under the lander, since horizontal thrusters are not available.
This is done in the StartPauseButtonClick subroutine (new code shaded):
Sub StartPauseButtonClick If (GameStatus = "Stopped") Then .
.
.
'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
If (PilotLevel <> 1) Then
PadX = Math.GetRandomNumber(LandscapeWidth ‐
PadWidth) ‐ 1
Else
PadX = LanderX + (LanderWidth / 2) ‐ PadWidth / 2
EndIf
PadBoxX = (PadX + PadWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ PadBoxWidth / 2
Shapes.Move(PadBox, GuideLeft + PadBoxX, GuideTop) PadY
= LandscapeHeight ‐ PadHeight FuelRemaining = MaximumFuel
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Green"
GraphicsWindow.FillRectangle(FuelLeft, FuelTop,
FuelWidth, FuelHeight) EndIf
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub

Save and Run the program. Select Beginner level. Click Start Game.
Make sure the pad is under the lander. Here’s what I see:
Notice Lateral position is listed as Above. Also note the red box
(representing the pad) under the viewer area completely covers the green
box.

The last change we need to make regarding pilot level is with the
Advanced level. In this level, we want the thrusters to be unpredictable,
generating random amounts of thrust. For horizontal and vertical thrust, we
will have anywhere from 0 to twice the maximum available delta in speed.
These changes are made in the thruster button click events. The changes are
shaded: Sub DownThrustButtonClick If (GameStatus = "Playing") Then If
(FuelRemaining > 0) Then
If (PilotLevel <> 5) Then
LanderYSpeed = LanderYSpeed ‐ YDelta
Else
LanderYSpeed = LanderYSpeed ‐ 2 * YDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
VFuel EndIf
EndIf
EndIf
EndSub

Sub LeftThrustButtonClick If (GameStatus = "Playing") Then If


(FuelRemaining > 0) Then
If (PilotLevel <> 5) Then
LanderXSpeed = LanderXSpeed + XDelta
Else
LanderXSpeed = LanderXSpeed + 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

Sub RightThrustButtonClick If (GameStatus = "Playing") Then If


(FuelRemaining > 0) Then
If (PilotLevel <> 5) Then
LanderXSpeed = LanderXSpeed ‐ XDelta
Else
LanderXSpeed = LanderXSpeed ‐ 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

Save and Run the program. Try the Advanced level and watch the fuel go
down very fast. This completes all but one change needed for pilot level.
The one change still needed is related to the Novice level (PilotLevel = 2).
At that level, you only control the horizontal thrusters to practice moving in
the lateral direction. The vertical thrust is controlled by the computer auto-
pilot. Since we haven’t coded the auto-pilot yet, you are guaranteed to crash
at Novice level (until we’ve completed the Moon Landing program, that
is).

One last change before tackling all the graphic effects – let’s add sounds. In
the KidGamesSB\KidGamesSB Programs\MoonLanding folder are four
wav files. The file vthrust.wav is played when vertical thrust is applied,
hthrust.wav is played when horizontal thrust is applied, safe.wav is played
following a safe landing, while crash.wav is played is you crash. Copy the
four files to your program’s folder.

The vertical thrust sound is played when vertical (down) thrust is applied.
Add the two shaded lines to the DownThrustButtonClick subroutine: Sub
DownThrustButtonClick If (GameStatus = "Playing") Then If
(FuelRemaining > 0) Then
Sound.Stop(Program.Directory + "\vthrust.wav")
Sound.Play(Program.Directory + "\vthrust.wav")
If (PilotLevel <> 5) Then LanderYSpeed = LanderYSpeed ‐
YDelta Else
LanderYSpeed = LanderYSpeed ‐ 2 * YDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
VFuel EndIf
EndIf
EndIf
EndSub
The horizontal thrust sound is played when either left or right thrust is
applied. Add the shaded lines to the LeftThrustButtonClick and
RightThrustButtonClick subroutines: Sub LeftThrustButtonClick If
(GameStatus = "Playing") Then If (FuelRemaining > 0) Then
Sound.Stop(Program.Directory + "\hthrust.wav")
Sound.Play(Program.Directory + "\hthrust.wav")
If (PilotLevel <> 5) Then LanderXSpeed = LanderXSpeed +
XDelta Else
LanderXSpeed = LanderXSpeed + 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

Sub RightThrustButtonClick If (GameStatus = "Playing") Then If


(FuelRemaining > 0) Then
Sound.Stop(Program.Directory + "\hthrust.wav")
Sound.Play(Program.Directory + "\hthrust.wav")
If (PilotLevel <> 5) Then LanderXSpeed = LanderXSpeed ‐
XDelta Else
LanderXSpeed = LanderXSpeed ‐ 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub
The landing sounds (safe.wav or crash.wav) are played following landing.
Add the shaded changes to the TimerTickSub subroutine (where the
landing is evaluated): Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
'check for landing
If (Altitude <= 0) Then 'display message
If (AutoPilotOn) Then Message = "Auto‐Pilot "
Else
Message = "You "
EndIf
'crash?
If (LanderYSpeed > SafeLandingSpeed) Then
Sound.Stop(Program.Directory + "\crash.wav")
Sound.Play(Program.Directory + "\crash.wav")
Message = Message + "Crashed!"
Else
Sound.Stop(Program.Directory + "\safe.wav")
Sound.Play(Program.Directory + "\safe.wav")
Message = Message + "Landed Safely"
EndIf
'display message
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 24
GraphicsWindow.DrawText(20, 30, Message) StopGame()
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub

Save and Run the program. Select a pilot level and play a game. Make sure
you hear sounds when the thrusters are applied. Make sure the proper
landing sound plays. You’ll have to figure out how to do a safe landing
(speed under -3 meters/second) to hear the safe landing sound!

At this point in the development of Moon Landing, we have a fully-


functional (except for auto-pilot) ‘text version’ of the game, meaning we
need to carefully watch displayed numerical values to monitor our lander’s
location and speed. Way back in the earliest days of home computing,
similar programs (using only vertical thrust, with names like Rocket,
Lunar, LEM, Apollo) were among the most popular computer games.
Since then, great strides have been made in the graphics capabilities of
computers. Let’s take advantage of those capabilities and develop ways to
graphically follow our lander’s excursion to the moon’s surface.
Code Design – Trajectory Display, Suggested Path

The first display we will develop is in the Trajectory rectangle on the right
side of the window. In this rectangle, we will draw a line indicating the
desired path from the lander to the pad. This line will connect the initial
lander position with the landing pad position to give you (and later the auto-
pilot) a suggested trajectory (path) to follow while landing. It only needs to
be drawn once (at the beginning of the descent). We will also draw the path
followed by the lander as it descends.

Let’s look a sketch of the initial lander and pad location on the Landscape

element:

The line we want to draw is shown in black, connecting the bottom middle
of the lander with the top center of the pad. The Cartesian pair at the bottom
of the lander is: X = LanderX + LanderWidth / 2
Y = LanderY + LanderHeight And the middle of the landing pad:

X = PadX + Pad.Width / 2
Y = PadY + PadHeight The coordinates given are relative to the size of
the landscape element and we want to draw the line in the trajectory
element (we know the dimensions of both). Hence, prior to drawing the
line, we need to scale the X and Y coordinates to fit the points within the
Trajectory rectangle. Each X coordinate is multiplied by
TrajectoryXScale: TrajectoryXScale = TrajectoryWidth /
LandscapeWidth and the Y coordinate is multiplied by
TrajectoryYScale: TrajectoryYScale = TrajectoryHeight /
LandscapeHeight Calculations assume the upper left corner of
Trajectory is at (0, 0). Prior to using computed points for drawing a line,
they are offset by the true upper corner (TrajectoryLeft,
TrajectoryTop).

Let’s make the code modifications to get the line drawn. Create a new
subroutine (UpdateTrajectory) with the code to draw the trajectory line:
Sub UpdateTrajectory TrajectoryXScale = TrajectoryWidth /
LandscapeWidth TrajectoryYScale = TrajectoryHeight / LandscapeHeight
If (Time = 0.0) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight) GraphicsWindow.PenColor =
"Red"
GraphicsWindow.PenWidth = 2
'four points for red trajectory line
x1 = TrajectoryLeft + TrajectoryXScale * (LanderX +
LanderWidth / 2) y1 = TrajectoryTop + TrajectoryYScale *
(LanderY + LanderHeight) x2 = TrajectoryLeft +
TrajectoryXScale * (PadX + PadWidth / 2) y2 = TrajectoryTop +
TrajectoryYScale * (PadY + PadHeight)
GraphicsWindow.DrawLine(x1, y1, x2, y2) EndIf
EndSub

This code compute the trajectory line endpoints and connects them with a
red line. Right now, this subroutine is only used for the initial line. We will
modify it soon to display the trajectory followed by the lander.

Add the one shaded line to the StartPauseButtonClick subroutine to draw


the initial suggested trajectory using UpdateTrajectory: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then .
.
.
'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
If (PilotLevel <> 1) Then PadX =
Math.GetRandomNumber(LandscapeWidth ‐ PadWidth) ‐ 1
Else
PadX = LanderX + (LanderWidth / 2) ‐ PadWidth / 2
EndIf
PadBoxX = (PadX + PadWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ PadBoxWidth / 2
Shapes.Move(PadBox, GuideLeft + PadBoxX, GuideTop) PadY
= LandscapeHeight ‐ PadHeight FuelRemaining = MaximumFuel
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Green"
GraphicsWindow.FillRectangle(FuelLeft, FuelTop,
FuelWidth, FuelHeight) EndIf
UpdateStatus()
UpdateTrajectory()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub

Save and Run the program. Select a pilot level and click Start Game. You
should now see the trajectory to the pad in the Trajectory area. Here’s my
example:

Now, we want the trajectory followed by the lander to be drawn. We will


use circles (ellipses) to mark this trajectory.
Code Design – Trajectory Display, Actual Path

We modify the UpdateTrajectory subroutine to draw a circle at the lander


position as time elapses. With this, we will have a graphic depiction of the
path followed by the lander as it descends. Such a depiction improves our
ability to monitor the lander position with respect to the pad.

The circle is centered at the bottom of the lander graphic element. That
point was earlier defined by: X = LanderX + LanderWidth / 2
Y = LanderY + LanderHeight Recall this position is relative to the
landscape element hence each point needs to be scaled to fit within the
Trajectory element.

Make the shaded changes to the UpdateTrajectory subroutine to draw the


circles: Sub UpdateTrajectory TrajectoryXScale = TrajectoryWidth /
LandscapeWidth TrajectoryYScale = TrajectoryHeight / LandscapeHeight
If (Time = 0.0) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight) GraphicsWindow.PenColor =
"Red"
GraphicsWindow.PenWidth = 2
'four points for red trajectory line
x1 = TrajectoryLeft + TrajectoryXScale * (LanderX +
LanderWidth / 2) y1 = TrajectoryTop + TrajectoryYScale *
(LanderY + LanderHeight) x2 = TrajectoryLeft +
TrajectoryXScale * (PadX + PadWidth / 2) y2 = TrajectoryTop +
TrajectoryYScale * (PadY + PadHeight)
GraphicsWindow.DrawLine(x1, y1, x2, y2) EndIf
'location of circles
x1 = TrajectoryXScale * (LanderX + LanderWidth / 2) ‐ 3
If (x1 < 0) Then x1 = 0
ElseIf (x1 > TrajectoryWidth ‐ 6) Then x1 = TrajectoryWidth ‐ 6
EndIf
y1 = TrajectoryYScale * (LanderY + LanderHeight) ‐ 3
If (y1 < 0) Then y1 = 0
EndIf
'light green circles 6 x 6 pixels
GraphicsWindow.PenColor = "LightGreen"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawEllipse(TrajectoryLeft + x1, TrajectoryTop +
y1, 6, 6)
EndSub

In the added code, we draw circles (diameter of 6 pixels) centered at


LanderX + Lander.Width/2, using a light green pen. We also have code to
make sure the circles stay within the Trajectory rectangle.

A circle is drawn with each new lander position update. Place the shaded
line in the TimerTickSub subroutine: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory()
'check for landing
If (Altitude <= 0) Then .
.
.
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub

Save and Run the program. Select a pilot level, click Start Game. Try to
land safely using the thrusters. You should see that the Trajectory display
provides a useful indication of where the lander is located relative to the
pad. And you get a plot of the trajectory followed to landing. Here’s a run I
made (Junior pilot level):

I didn’t stay real close to the suggested trajectory, but I made a pretty good
landing!

The trajectory display is useful in helping land on the moon safely. But, we
can do better. Let’s develop an animated display of the lander as it descends
onto the landing pad. We place this animation in the Viewer region on the
left of the window.
Code Design – Lander Animation

We want an animation of the lander descending to the surface of the moon.

Recall the lander image (lander.gif) appears as:

We will use the Shapes object Move method to position this in the Viewer
region. The lander.gif file included in the KidGamesSB\KidGamesSB
Programs\MoonLanding folder. Copy it to your program’s folder.

Here is the Viewer region we will use to watch the animation:

The Viewer region moves within the Landscape element (which includes
the entire area the lander can move within). We choose to keep the lander
image centered within the Viewer (if possible). Superimposing the viewer
on the landscape (also showing the lander in the green box, we have:

How do we know LandscapeX and LandscapeY (the location of the


Viewer within Landscape)? Let’s do the math. We have two variables
(CenterX and CenterY) that specify the distance from the edges of the
Viewer to the lander image to keep the lander centered: CenterX =
(ViewerWidthCenterX = (ViewerWidth – LanderWidth) / 2
CenterY = (ViewerHeightCenterY = (ViewerHeight – LanderHeight) / 2

With these, the values of LandscapeX and LandscapeY (knowing


LanderX and LanderY) are seen to be: LandscapeX = LanderX – CenterX
LandscapeY = LanderY – CenterY

So, as the lander moves (varying LanderX and LanderY), we compute


LandscapeX and LandscapeY. This defines where the lander is in the
landscape. The landscape behind the lander will be black until the pad
enters the viewer, as the lander descends.

Notice we said we would center the lander in the viewer, if possible. There
are four cases where we will not be able to center the lander, each related to
being beyond one of the four borders of the landscape. Let’s look at each
border and the limiting values of LandscapeX and LandscapeY: Left
border, LandscapeX > 0
Right border, LandscapeX < LandscapeWidth – ViewerWidth Top
border, LandscapeY > 0
Bottom border, LandscapeY < LandscapeHeight – ViewerHeight In
these limiting cases, we will relax the need to center the lander and allow
it to move freely (although always keeping it in the viewer).

Now, let’s get the lander moving. Add this code in InitializeProgram (after
the lines setting dimensions of the landscape and lander) to create the
Lander shape and initially place it at the top center of the viewer. We also
compute CenterX and CenterY: 'Create shapes
Lander = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\lander.gif")) Shapes.Move(Lander, ViewerLeft + 0.5 * (ViewerWidth ‐
LanderWidth), ViewerTop) CenterX = (ViewerWidth ‐ LanderWidth) / 2
CenterY = (ViewerHeight ‐ LanderHeight) / 2

Double-check that you copied the lander graphics file to your program’s
folder.

Save and Run the program to make sure the lander appears:
Add a subroutine (UpdateViewer) for the code associated with the landing
animation: Sub UpdateViewer
'position lander
ViewLanderX = CenterX
ViewLanderY = CenterY
'adjust landscape background
LandscapeX = LanderX ‐ CenterX
If (LandscapeX <= 0) Then LandscapeX = 0
ViewLanderX = LanderX
EndIf
If (LandscapeX >= LandscapeWidth ‐ ViewerWidth) Then
LandscapeX = LandscapeWidth ‐ ViewerWidth ViewLanderX =
LanderX ‐ LandscapeX
EndIf
LandscapeY = LanderY ‐ CenterY
If (LandscapeY <= 0) Then LandscapeY = 0
ViewLanderY = LanderY
EndIf
If (LandscapeY >= LandscapeHeight ‐ ViewerHeight) Then
LandscapeY = LandscapeHeight ‐ ViewerHeight ViewLanderY =
LanderY ‐ LandscapeY
EndIf
'keep lander in borders
If (ViewLanderX < 0) Then ViewLanderX = 0
ElseIf (ViewLanderX + LanderWidth > ViewerWidth) Then
ViewLanderX = ViewerWidth ‐ LanderWidth EndIf
If (ViewLanderY < 0) Then ViewLanderY = 0
EndIf
'show lander
Shapes.Move(Lander, ViewerLeft + ViewLanderX, ViewerTop +
ViewLanderY) EndSub
The code above determines LandscapeX and LandscapeY (being
cognizant of the borders). We also determine the lander position
(ViewLanderX, ViewLanderY). We adjust this position if we have moved
past any of the borders of the landscape. The Lander shape is then placed
in the viewer.

Initialize the viewer with the shaded line in the StartPauseButtonClick


subroutine: Sub StartPauseButtonClick If (GameStatus = "Stopped") Then
.
.
.
'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
If (PilotLevel <> 1) Then PadX =
Math.GetRandomNumber(LandscapeWidth ‐ PadWidth) ‐ 1
Else
PadX = LanderX + (LanderWidth / 2) ‐ PadWidth / 2
EndIf
PadBoxX = (PadX + PadWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ PadBoxWidth / 2
Shapes.Move(PadBox, GuideLeft + PadBoxX, GuideTop) PadY
= LandscapeHeight ‐ PadHeight FuelRemaining = MaximumFuel
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Green"
GraphicsWindow.FillRectangle(FuelLeft, FuelTop,
FuelWidth, FuelHeight) EndIf
UpdateStatus()
UpdateTrajectory()
UpdateViewer()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub

And, the viewer updates are done in the TimerTickSub subroutine (add
shaded line): Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory()
UpdateViewer()
'check for landing
If (Altitude <= 0) Then .
.
.
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub
Save and Run the program. Start a game with Junior Level. Immediately
click Pause Game. Here’s my screen:

Notice the lander is not centered (horizontally or vertically) in the viewer. It


is not centered horizontally because the lander is at the far left of the
landscape (see the trajectory display showing the green circle at the far left).
It is not centered vertically because the landscape is at its upper limit
(LandscapeY = 0). Click Restart Game. Let the lander drop. Pause the
game once the lander drops to the middle of the viewer.

You should now see a very nice animation of the landing process. Here’s
my screen:
Click Restart. As the lander nears the bottom on the landscape (eventually
we will have the landing pad appear in the viewer), it will no longer be
centered since the landscape is near its lower limit. Here’s my screen after a
crash landing:

Notice the lander moved a little toward the left – I applied some thrust to do
that.

We finish the animation now by adding other graphic elements – the


thrusters and the landing pad.
Code Design – Adding Thrust

Adding thruster flames is a cool effect. There are two files (hthrust.gif and
vthrust.gif) in the KidGamesSB\KidGamesSB Programs\MoonLanding
folder used for this effect. Copy these images to your program’s folder.

The horizontal thrust image (hthrust.gif) is 32 pixels by 16 pixels (twice


actual size):

This image will be used for both the left and right thrust. The vertical thrust
image (vthrust.gif) is 24 pixels by 32 pixels (also twice actual size):

This is used for the downward thrust.

Like the lander, each of these images is represented by a Small Basic


Shapes object. Add this code in InitializeProgram (after the code creating
the Lander object) to create these objects and specify their dimensions of
all the graphic elements. Once created, we hide the images (LeftThrust,
RightThrust, DownThrust) so they cannot be seen.

LeftThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\hthrust.gif")) RightThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\hthrust.gif")) DownThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\vthrust.gif")) Shapes.HideShape(LeftThrust)
Shapes.HideShape(RightThrust) Shapes.HideShape(DownThrust)
HThrustWidth = 32
HThrustHeight = 16
VThrustWidth = 24
VThrustHeight = 32
Drawing the thrust graphics in the viewer is straightforward. All of the code
goes in the UpdateViewer subroutine. Before modifying this subroutine,
we need one little change. To add thruster graphics to the animation, we
need to know if thrust is being applied. We use three variables
(DownThrustOn, LeftThrustOn, RightThrustOn) for this purpose.

Then, in each of the corresponding thrust control button subroutines, set the
value of these variables (shaded lines): Sub DownThrustButtonClick If
(GameStatus = "Playing") Then If (FuelRemaining > 0) Then
Sound.Stop(Program.Directory + "\vthrust.wav")
Sound.Play(Program.Directory + "\vthrust.wav")
DownThrustOn = "true"
If (PilotLevel <> 5) Then LanderYSpeed = LanderYSpeed ‐
YDelta Else
LanderYSpeed = LanderYSpeed ‐ 2 * YDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
VFuel EndIf
EndIf
EndIf
EndSub

Sub LeftThrustButtonClick If (GameStatus = "Playing") Then If


(FuelRemaining > 0) Then Sound.Stop(Program.Directory +
"\hthrust.wav") Sound.Play(Program.Directory + "\hthrust.wav")
LeftThrustOn = "true"
If (PilotLevel <> 5) Then LanderXSpeed = LanderXSpeed +
XDelta Else
LanderXSpeed = LanderXSpeed + 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

Sub RightThrustButtonClick If (GameStatus = "Playing") Then If


(FuelRemaining > 0) Then Sound.Stop(Program.Directory +
"\hthrust.wav") Sound.Play(Program.Directory + "\hthrust.wav")
RightThrustOn = "true"
If (PilotLevel <> 5) Then LanderXSpeed = LanderXSpeed ‐
XDelta Else
LanderXSpeed = LanderXSpeed ‐ 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

Upon landing, we want to make sure the thrusters are off. Add the shaded
code change to the TimerTickSub subroutine: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory() UpdateViewer()
'check for landing
If (Altitude <= 0) Then
LeftThrustOn = "false"
RightThrustOn = "false"
DownThrustOn = "false"
UpdateViewer()
.
.
.
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub

Note we need to update the viewer after turning the thrusters off to make
sure they do not appear.

Now, make the shaded changes to the UpdateViewer subroutine to draw


the thrusts (when on): Sub UpdateViewer
'position lander
.
.
.
'add thrusters if on
If (DownThrustOn) Then Shapes.Move(DownThrust, ViewerLeft +
ViewLanderX + 0.5 * LanderWidth ‐ 0.5 * VThrustWidth,
ViewerTop + ViewLanderY + LanderHeight ‐ VThrustHeight)
Shapes.ShowShape(DownThrust) DownThrustOn = "false"
Else
Shapes.HideShape(DownThrust) EndIf
If (LeftThrustOn) Then Shapes.Move(LeftThrust, ViewerLeft +
ViewLanderX ‐ 5, ViewerTop + ViewLanderY + 40)
Shapes.ShowShape(LeftThrust) LeftThrustOn = "false"
Else
Shapes.HideShape(LeftThrust) EndIf
If (RightThrustOn) Then Shapes.Move(RightThrust, ViewerLeft +
ViewLanderX + LanderWidth ‐ HThrustWidth + 5, ViewerTop +
ViewLanderY + 40) Shapes.ShowShape(RightThrust) RightThrustOn
= "false"
Else
Shapes.HideShape(RightThrust) EndIf
EndSub

Here, the thrust shapes are added to the viewer (if the corresponding
thruster is on). The positions of the shapes were obtained by trial and error.

Save and Run the program. Start a game. Try out the thrusters. Here’s my
screen after applying a bit of right thrust:
Code Design – Displaying Pad

As the lander nears the bottom of the landscape, we want the landing pad (a
red rectangle) to appear in the viewer. To do this, we need to do a little bit
of math.

Here’s a sketch of the landscape, viewer and pad just as the pad enters the
bottom right of the viewer:

From this sketch, we see all or some of the Pad is in the Viewer when each
of these conditions holds: PadX >= LandscapeX
PadX <= LandscapeX + ViewerWidth
PadY > LandscapeY
PadY < LandscapeY + ViewerHeight

How much of the Pad is in the viewer (the red area in the sketch)? The
width (W) is: W = LandscapeX + ViewerWidth ‐ PadX

If this value is greater than the PadWidth, it is limited to PadWidth. The


height (H) is: H = LandscapeY + ViewerHeight ‐ PadY

Knowing these values, the pad is drawn in the viewer using:


GraphicsWindow.FillRectangle(ViewerLeft + PadX ‐ LandscapeX,
ViewerTop + PadY ‐ LandscapeY, W, H) We’ve considered the case where
the pad moves into the viewer from the right. There’s one more possibility –
what if it moves in from the left:

From this sketch, we see all or some of the Pad is in the Viewer when each
of these conditions holds: PadX + PadWidth > LandscapeX
PadX + PadWidth < LandscapeX + ViewerWidth
PadY > LandscapeY
PadY < LandscapeY + ViewerHeight

With this configuration, how much of the Pad is in the viewer (the red area
in the sketch)? The width (W) is: W = PadX + PadWidth ‐ LandscapeX

The height (H) is: H = LandscapeY + ViewerHeight ‐ PadY

Knowing these values, the pad is drawn in the viewer using:


GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop + PadY ‐
LandscapeY, W, H) Add the shaded code to the UpdateViewer subroutine
to incorporate these equations: Sub UpdateViewer
'position lander
.
.
.
'add thrusters if on
.
.
.
'see if landing pad is in landscape
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop,
ViewerWidth, ViewerHeight) If (PadX >= LandscapeX And PadX <=
LandscapeX + ViewerWidth) Then If (PadY > LandscapeY And
PadY < LandscapeY + ViewerHeight) Then 'at right or completely in
window
GraphicsWindow.BrushColor = "DarkRed"
W = LandscapeX + ViewerWidth ‐ PadX
If (W > PadWidth) Then W = PadWidth EndIf
H = LandscapeY + ViewerHeight ‐ PadY
GraphicsWindow.FillRectangle(ViewerLeft + PadX ‐
LandscapeX, ViewerTop + PadY ‐ LandscapeY, W, H) EndIf
ElseIf (PadX + PadWidth > LandscapeX And PadX + PadWidth <
LandscapeX + ViewerWidth) Then If (PadY > LandscapeY And
PadY < LandscapeY + ViewerHeight) Then 'at left
GraphicsWindow.BrushColor = "DarkRed"
W = PadX + PadWidth ‐ LandscapeX
H = LandscapeY + ViewerHeight ‐ PadY
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop +
PadY ‐ LandscapeY, W, H) EndIf
EndIf
EndSub

Save and Run the program. Try landing. As you near the bottom of the
landscape (Altitude under 100 meters or so), the landing pad should begin
to appear. Here is a run I made:

The lander is approaching the pad. I think you’ll agree you have a nice
game by now. We need one last change to make it complete. We need to
code the autopilot option.
Code Design - Autopilot

The auto-pilot option allows you to see how the computer controls the
lander as it descends to the moon. With auto-pilot, the computer controls
the horizontal and vertical thrusters in attempt to make a safe landing. The
goal is to be under a safe vertical landing speed (3 meters/second), while
being near the landing pad. We will develop the vertical and horizontal
thruster auto-pilots separately.

Like the game playing logic in Tic Tac Toe and Match Game, there are no
rigid rules for developing an auto-pilot. Like those games, I tried to develop
rules for how I (a human) might control the lander and put those rules into
code. Feel free to change any of the auto-pilot code as you see fit.

Here are the rules I use to automatically control the vertical (down) thruster
control:

➢ If Altitude is above 300 meters, apply down thrust to keep


LanderYSpeed under 12 meters/second.
➢ If Altitude is between 100 and 300 meters, apply down thrust to keep
LanderYSpeed under 6 meters/second.
➢ If Altitude is under 100 meters, apply down thrust to keep
LanderYSpeed under 2 + 0.04 * Altitude.

What I am attempting to do is make sure the lander never accelerates to


extremely high speeds, then as it nears the surface, ramp down the speed to
have it near 2 meters/second upon landing (Altitude = 0).

The code for the vertical auto-pilot is placed in the TimerTickSub


subroutine. The additions are noted by the shaded code: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory() UpdateViewer()
'check for landing
If (Altitude <= 0) Then .
.
.
EndIf
'autopilot or Novice level ‐ adjust vertical thrust If (AutoPilotOn Or
PilotLevel = 2) Then If (Altitude > 300) Then If (LanderYSpeed >
12) Then DownThrustButtonClick() EndIf
ElseIf Altitude > 100 Then If LanderYSpeed > 6 Then
DownThrustButtonClick() EndIf
Else
If LanderYSpeed > (2 + 0.04 * Altitude) Then
DownThrustButtonClick() EndIf
EndIf
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub

In this new code, when the computer needs to apply thrust, it makes a direct
call to the DownThrustButtonClick subroutine. Notice we use auto-pilot
when AutoPilotOn is “true” or when PilotLevel = 2 (when you, the
human, only control horizontal thrust).

Save and Run the program. Click Options. Select Beginner pilot level.
Select the Auto-Pilot On option. Click Start Game. The computer takes
over (the first burst of thrust will occur when the downward speed exceeds
12 meters/sec) and brings the lander to a safe landing:

Run the game again, this time with Novice pilot level and auto-pilot off.
Make sure the computer provides the needed vertical thrust as you control
the horizontal thrust. Here’s my run with Novice level (not a bad job):

Now, let’s complete this game with some automatic horizontal thrust
control.

To automatically control the horizontal thrusters, we will use the suggested


path (the red line) drawn in the trajectory panel. The idea is to apply thrust
such that the lander stays near this path, leading to the landing pad.
Engineers call this approach “trajectory following.” Let the altitude at
Time = 0.0 be Altitude0 and the corresponding lateral distance be Lateral0
(the starting point on the trajectory). Here’s a sketch of the suggested
trajectory (red line) and the current lander location (green circle), with
corresponding variables:

In this graph, the origin (where Altitude = Lateral = 0) represents the


center of the landing pad.

In this sketch, the lander lateral position is Lateral, yet we want it to be D,


the point on the trajectory line corresponding to the lander altitude
(Altitude). We define a “miss” distance (Miss) as: Miss = LateralMiss =
Lateral – D

Using the idea of similar triangles, we can write:

D / Lateral0 = Altitude / Altitude0

Or

D = Lateral0 * (Altitude / Altitude0) Then, the Miss distance is: Miss =


Lateral – Lateral0 * (Altitude / Altitude0) If Miss is a positive number,
we want the lander to move to the left (or apply right thrust). Conversely,
is Miss is negative, we want the lander to move to the right (or apply left
thrust). A good question to ask is how big does Miss need to be before
applying thrust? Zero would not be a good answer. In such a case, the
right thruster would move the lander to the left of the path, then the left
thruster would move it back to the right. The horizontal thrusters would
just keep alternating, burning lots of fuel. In our game, we will not apply
any horizontal thrust until the lander is at least two meters away from the
suggested trajectory path.

As an aside, this is similar to logic used in the thermostat used to heat your
home. When the temperature is lower than the thermostat setting, the
furnace is turned on. When the temperature exceeds the setting, the furnace
is turned off. But, the furnace doesn’t turn on if the temperature is just
below the setting. It waits until the temperature difference (Miss) is about 2
degrees or so. The same difference in temperature is used before turning the
furnace back off. This keeps your furnace from just cycling on and off.

Let’s code the final element of the Moon Landing game – the horizontal
autopilot. The initial altitude and lateral distance are established in the
UpdateTrajectory subroutine (shaded changes): Sub UpdateTrajectory
TrajectoryXScale = TrajectoryWidth / LandscapeWidth TrajectoryYScale =
TrajectoryHeight / LandscapeHeight If (Time = 0.0) Then
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight) GraphicsWindow.PenColor = "Red"
GraphicsWindow.PenWidth = 2
'four points for red trajectory line
x1 = TrajectoryLeft + TrajectoryXScale * (LanderX +
LanderWidth / 2) y1 = TrajectoryTop + TrajectoryYScale * (LanderY +
LanderHeight) x2 = TrajectoryLeft + TrajectoryXScale * (PadX +
PadWidth / 2) y2 = TrajectoryTop + TrajectoryYScale * (PadY +
PadHeight) GraphicsWindow.DrawLine(x1, y1, x2, y2)
Altitude0 = Altitude Lateral0 = Lateral
EndIf
'location of circles
x1 = TrajectoryXScale * (LanderX + LanderWidth / 2) ‐ 3
If (x1 < 0) Then x1 = 0
ElseIf (x1 > TrajectoryWidth ‐ 6) Then x1 = TrajectoryWidth ‐ 6
EndIf
y1 = TrajectoryYScale * (LanderY + LanderHeight) ‐ 3
If (y1 < 0) Then y1 = 0
EndIf
'light green circles 6 x 6 pixels
GraphicsWindow.PenColor = "LightGreen"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawEllipse(TrajectoryLeft + x1, TrajectoryTop +
y1, 6, 6) EndSub

The code for the horizontal auto-pilot is placed under the vertical auto-pilot
code in the TimerTickSub subroutine. The additions are noted by the
shaded code: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory() UpdateViewer()
'check for landing
If (Altitude <= 0) Then .
.
.
EndIf
'autopilot or Novice level ‐ adjust vertical thrust If (AutoPilotOn Or
PilotLevel = 2) Then If (Altitude > 300) Then If (LanderYSpeed >
12) Then DownThrustButtonClick() EndIf
ElseIf Altitude > 100 Then If LanderYSpeed > 6 Then
DownThrustButtonClick() EndIf
Else
If LanderYSpeed > (2 + 0.04 * Altitude) Then
DownThrustButtonClick() EndIf
EndIf
EndIf
'autopilot ‐ adjust horizontal thrust
If (AutoPilotOn) Then Miss = Lateral ‐ Altitude * (Lateral0 /
Altitude0) If (Miss > 2) Then RightThrustButtonClick() ElseIf (Miss
< ‐2) Then LeftThrustButtonClick() EndIf
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub

Save the program one last time. Run the program. Select Senior pilot level,
and turn Auto-Pilot On. Here’s the game after 4.0 seconds of running (I
paused at this point):
The auto-pilot is applying some left thrust, accelerating the lander to a
lateral speed of 2.2 meters/second, moving the lander toward the trajectory
line (see trajectory display).

Here’s the screen after 36.5 seconds:

The computer has applied several bursts of vertical thrust to keep the lander
vertical speed reasonable and used a few horizontal thrusts to keep the
lander near the desired trajectory.

Now, at 65.5 seconds:


The computer is still giving thrust adjustments to finalize landing. The pad
is nearby and things are looking good.
Finally, at 92.5 seconds, the lander is safely on the pad:

A near perfect landing under the safe landing speed of -3.0 m/s and almost
right on top of the pad.

The game is now complete. As you play, it will become obvious that there
are many ways to obtain a safe landing with the vehicle. Without a fuel
constraint, you can take forever to land. A more interesting problem is to try
to land as fast as possible. This is the so-called minimum time problem.
Or try to land using the least fuel possible - an important problem in space
travel where you don't want to launch a lot of unnecessary weight.

Try a so-called ‘coast and burn’ approach. That is, let your lander keep
dropping until some point where you apply nearly constant vertical thrust
until landed. This approach needs to be used in space vehicles where
thrusters can only be turned on, but never off (like solid rocket motors).
Moon Landing Game Program Listing

Here is the complete listing of the Moon Landing Small Basic program: '
Moon Landing
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 600
GraphicsWindow.Height = 400
GraphicsWindow.Title = "Moon Landing"
GraphicsWindow.BackgroundColor =
GraphicsWindow.GetColorFromRGB(192, 192, 255) ' draw view screen
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(0, 0, 300, 400)
GraphicsWindow.BrushColor = "Black"
ViewerLeft = 10
ViewerTop = 10
ViewerWidth = 280
ViewerHeight = 360
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop, ViewerWidth,
ViewerHeight) GraphicsWindow.BrushColor = "SlateGray"
GuideLeft = 10
GuideTop = 370
GuideWidth = 280
GuideHeight = 20
GraphicsWindow.FillRectangle(GuideLeft, GuideTop, GuideWidth,
GuideHeight) GraphicsWindow.BrushColor = "Red"
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
PadBox = Shapes.AddRectangle(15, 20) GraphicsWindow.BrushColor =
"Green"
LanderBox = Shapes.AddRectangle(15, 20) Shapes.Move(PadBox, 20,
GuideTop) Shapes.Move(LanderBox, 100, GuideTop) PadBoxWidth =
15
LanderBoxWidth = 15
'Default Options
PilotLevel = 1
AutoPilotOn = "false"
MetricUnits = "true"
'create display shapes
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
DisplayTime = Shapes.AddText("") Shapes.Move(DisplayTime, 420, 30)
DisplayVerticalPosition = Shapes.AddText("")
Shapes.Move(DisplayVerticalPosition, 420, 75) DisplayVerticalSpeed =
Shapes.AddText("") Shapes.Move(DisplayVerticalSpeed, 520, 75)
DisplayLateralPosition = Shapes.AddText("")
Shapes.Move(DisplayLateralPosition, 420, 100) DisplayLateralSpeed =
Shapes.AddText("") Shapes.Move(DisplayLateralSpeed, 520, 100)
'define buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
'thrust buttons
LeftThrustButton = Controls.AddButton("Left", 360, 320)
DownThrustButton = Controls.AddButton("Down", 425, 320)
RightThrustButton = Controls.AddButton("Right", 490, 320)
Controls.SetSize(LeftThrustButton, 60, 31)
Controls.SetSize(DownThrustButton, 60, 31)
Controls.SetSize(RightThrustButton, 60, 31) 'Other buttons
StartPauseButton = Controls.AddButton("Start Game", 305, 360)
Controls.SetSize(StartPauseButton, 110, 31) OptionsButton =
Controls.AddButton("Options", 417, 360) ExitStopButton =
Controls.AddButton("Exit", 485, 360) Controls.SetSize(ExitStopButton,
110, 31) SetDisplay()
GameStatus = "Stopped"
'Simulation variables
XDelta = 1.2
YDelta = 2.4
Gravity = 9.8 / 6.0
Drag = 0.1
SafeLandingSpeed = 3.0
MaximumFuel = 100
HFuel = 0.5
VFuel = 1.0
'Set dimensions
LandscapeWidth = 640
LandscapeHeight = 700
LanderWidth = 105
LanderHeight = 115 PadWidth = LanderWidth PadHeight = 15
'Create shapes
Lander = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\lander.gif")) Shapes.Move(Lander, ViewerLeft + 0.5 * (ViewerWidth ‐
LanderWidth), ViewerTop) LeftThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\hthrust.gif")) RightThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\hthrust.gif")) DownThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\vthrust.gif")) Shapes.HideShape(LeftThrust)
Shapes.HideShape(RightThrust) Shapes.HideShape(DownThrust)
HThrustWidth = 32
HThrustHeight = 16
VThrustWidth = 24
VThrustHeight = 32
CenterX = (ViewerWidth ‐ LanderWidth) / 2
CenterY = (ViewerHeight ‐ LanderHeight) / 2
Controls.ButtonClicked = ButtonClickedSub Timer.Interval = 500
Timer.Tick = TimerTickSub Timer.Pause() EndSub

Sub SetDisplay
'clear what is there first
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(300, 0, 300, 400) 'titling information
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
T = "Landing Control ‐ "
If (PilotLevel = 1) Then T = T + "Beginner"
ElseIf (PilotLevel = 2) Then T = T + "Novice"
ElseIf (PilotLevel = 3) Then T = T + "Junior"
ElseIf (PilotLevel = 4) Then T = T + "Senior"
ElseIf (PilotLevel = 5) Then T = T + "Advanced"
EndIf
GraphicsWindow.DrawText(310, 0, T) GraphicsWindow.FontSize = 16
GraphicsWindow.DrawText(310, 30, "Time (s)") If (MetricUnits) Then
Multiplier = 1.0
GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
Multiplier = 3.2808
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf
GraphicsWindow.DrawText(310, 75, "Altitude")
GraphicsWindow.DrawText(310, 100, "Lateral") 'rectangles for data
display
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(390, 30, 90, 20)
GraphicsWindow.FillRectangle(390, 75, 90, 20)
GraphicsWindow.FillRectangle(390, 100, 90, 20)
GraphicsWindow.FillRectangle(490, 75, 90, 20)
GraphicsWindow.FillRectangle(490, 100, 90, 20)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(390, 30, 90, 20)
GraphicsWindow.DrawRectangle(390, 75, 90, 20)
GraphicsWindow.DrawRectangle(390, 100, 90, 20)
GraphicsWindow.DrawRectangle(490, 75, 90, 20)
GraphicsWindow.DrawRectangle(490, 100, 90, 20) 'fuel display
FuelLeft = 350
FuelTop = 130
FuelWidth = 240
FuelHeight = 20
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.DrawText(310, 130, "Fuel")
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(FuelLeft, FuelTop, FuelWidth,
FuelHeight) EndIf
'trajectory screen
TrajectoryLeft = 310
TrajectoryTop = 160
TrajectoryWidth = 280
TrajectoryHeight = 150
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight) 'thrust buttons
If (AutoPilotOn) Then Controls.HideControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.HideControl(RightThrustButton) LeftThrustVisible = "false"
DownThrustVisible = "false"
RightThrustVisible = "false"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 20
GraphicsWindow.DrawText(390, 320, "Auto‐Pilot On") Else
'buttons based on level
If (PilotLevel = 1) Then Controls.HideControl(LeftThrustButton)
Controls.ShowControl(DownThrustButton)
Controls.HideControl(RightThrustButton) LeftThrustVisible =
"false"
DownThrustVisible = "true"
RightThrustVisible = "false"
ElseIf (PilotLevel = 2) Then
Controls.ShowControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.ShowControl(RightThrustButton) LeftThrustVisible =
"true"
DownThrustVisible = "false"
RightThrustVisible = "true"
Else
Controls.ShowControl(LeftThrustButton)
Controls.ShowControl(DownThrustButton)
Controls.ShowControl(RightThrustButton) LeftThrustVisible =
"true"
DownThrustVisible = "true"
RightThrustVisible = "true"
EndIf
EndIf
UpdateStatus()
EndSub

Sub UpdateStatus
'Time
NumberToFormat = Time DecimalFormat()
Shapes.SetText(DisplayTime, NumberText) 'Positions
Altitude = (LandscapeHeight ‐ PadHeight) ‐ (LanderY + LanderHeight)
Lateral = (LanderX + (LanderWidth / 2)) ‐ (PadX + (PadWidth / 2)) If
(Altitude > 0) Then Shapes.SetText(DisplayVerticalPosition,
Math.Floor(Altitude * Multiplier)) Else
Shapes.SetText(DisplayVerticalPosition, 0) EndIf
If Math.Abs(Lateral) < 1 Then Shapes.SetText(DisplayLateralPosition,
"Above") Else
Shapes.SetText(DisplayLateralPosition, Math.Floor(Lateral *
Multiplier)) EndIf
'speeds
NumberToFormat = ‐LanderYSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayVerticalSpeed, NumberText) NumberToFormat =
LanderXSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayLateralSpeed, NumberText) 'location box
LanderBoxX = (LanderX + LanderWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ LanderBoxWidth / 2
If (LanderBoxX < 0) Then LanderBoxX = 0
ElseIf (LanderBoxX > (GuideWidth ‐ LanderBoxWidth)) Then
LanderBoxX = GuideWidth ‐ LanderBoxWidth EndIf
Shapes.Move(LanderBox, GuideLeft + LanderBoxX, GuideTop) 'fuel
If (PilotLevel > 3) Then If (FuelRemaining > 0) Then FuelValue =
(FuelRemaining / MaximumFuel) * FuelWidth Else
FuelValue = 0
EndIf
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(FuelLeft + FuelValue, FuelTop,
FuelWidth ‐ FuelValue, FuelHeight) EndIf
EndSub

Sub ButtonClickedSub B = Controls.LastClickedButton If (B =


ExitStopButton) Then 'exit, stop button
ExitStopButtonClick() ElseIf (B = OptionsButton) Then 'change
options
SetOptions()
ElseIf (B = StartPauseButton) Then ' start, stop, pause button
StartPauseButtonClick() ElseIf (B = DownThrustButton) Then
'down thrust
DownThrustButtonClick() ElseIf (B = LeftThrustButton) Then 'left
thrust
LeftThrustButtonClick() ElseIf (B = RightThrustButton) Then 'right
thrust
RightThrustButtonClick() EndIf
EndSub

Sub ExitStopButtonClick If (GameStatus = "Stopped") Then


Program.End() Else
StopGame()
EndIf
EndSub

Sub SetOptions
GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title =
"Moon Landing"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("MOON LANDING OPTIONS")
TextWindow.WriteLine("") GetPilotLevel:
TextWindow.CursorLeft = 3
TextWindow.WriteLine("What level pilot do you want?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Beginner, 2‐Novice, 3‐Junior, 4‐Senior, 5‐
Advanced) ") PilotLevel = TextWindow.ReadNumber() If (PilotLevel < 1
Or PilotLevel > 5) Then Goto GetPilotLevel EndIf
GetAutoPilotOn:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("Do you want Auto‐Pilot on?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Yes, 2‐No) ") T = TextWindow.ReadNumber() If
(T < 1 Or T > 2) Then Goto GetAutoPilotOn EndIf
If (T = 1) Then AutoPilotOn = "true"
Else
AutoPilotOn = "false"
EndIf
GetUnits:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("What units of distance do you want to use?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Meters, 2‐Feet) ") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto GetUnits
EndIf
If (T = 1) Then MetricUnits = "true"
Else
MetricUnits = "false"
EndIf
SetDisplay()
TextWindow.Hide() GraphicsWindow.Show() EndSub

Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000) LanderY
= LanderY + LanderYSpeed * (Timer.Interval / 1000) UpdateStatus()
UpdateTrajectory() UpdateViewer()
'check for landing
If (Altitude <= 0) Then LeftThrustOn = "false"
RightThrustOn = "false"
DownThrustOn = "false"
UpdateViewer()
'display message
If (AutoPilotOn) Then Message = "Auto‐Pilot "
Else
Message = "You "
EndIf
'crash?
If (LanderYSpeed > SafeLandingSpeed) Then
Sound.Stop(Program.Directory + "\crash.wav")
Sound.Play(Program.Directory + "\crash.wav") Message = Message
+ "Crashed!"
Else
Sound.Stop(Program.Directory + "\safe.wav")
Sound.Play(Program.Directory + "\safe.wav") Message =
Message + "Landed Safely"
EndIf
'display message
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 24
GraphicsWindow.DrawText(20, 30, Message) StopGame()
EndIf
'autopilot or Novice level ‐ adjust vertical thrust If (AutoPilotOn Or
PilotLevel = 2) Then If (Altitude > 300) Then If (LanderYSpeed > 12)
Then DownThrustButtonClick() EndIf
ElseIf Altitude > 100 Then If LanderYSpeed > 6 Then
DownThrustButtonClick() EndIf
Else
If LanderYSpeed > (2 + 0.04 * Altitude) Then
DownThrustButtonClick() EndIf
EndIf
EndIf
'autopilot ‐ adjust horizontal thrust
If (AutoPilotOn) Then Miss = Lateral ‐ Altitude * (Lateral0 / Altitude0)
If (Miss > 2) Then RightThrustButtonClick() ElseIf (Miss < ‐2) Then
LeftThrustButtonClick() EndIf
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub

Sub DecimalFormat
WholeNumber = Math.Floor(NumberToFormat) Decimal =
Math.Floor(10 * (NumberToFormat ‐ WholeNumber)) NumberText =
Text.Append(WholeNumber, ".") If (Decimal = 0) Then NumberText =
Text.Append(NumberText, "0") Else
NumberText = Text.Append(NumberText, Decimal) EndIf
EndSub

Sub StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus


= "Playing"
'clear any previous message from viewer
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop,
ViewerWidth, 60) Controls.SetButtonCaption(StartPauseButton,
"Pause Game") Controls.SetButtonCaption(ExitStopButton, "Stop
Game") Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
If (PilotLevel <> 1) Then PadX =
Math.GetRandomNumber(LandscapeWidth ‐ PadWidth) ‐ 1
Else
PadX = LanderX + (LanderWidth / 2) ‐ PadWidth / 2
EndIf
PadBoxX = (PadX + PadWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ PadBoxWidth / 2
Shapes.Move(PadBox, GuideLeft + PadBoxX, GuideTop) PadY =
LandscapeHeight ‐ PadHeight FuelRemaining = MaximumFuel If
(PilotLevel > 3) Then GraphicsWindow.BrushColor = "Green"
GraphicsWindow.FillRectangle(FuelLeft, FuelTop, FuelWidth,
FuelHeight) EndIf
UpdateStatus()
UpdateTrajectory() UpdateViewer()
Timer.Resume() ElseIf (GameStatus = "Playing") Then GameStatus
= "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton, "Restart
Game") Controls.HideControl(ExitStopButton)
Controls.HideControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.HideControl(RightThrustButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) 'show other buttons if they
were showing before
If (LeftThrustVisible) Then
Controls.ShowControl(LeftThrustButton) EndIf
If (DownThrustVisible) Then
Controls.ShowControl(DownThrustButton) EndIf
If (RightThrustVisible) Then
Controls.ShowControl(RightThrustButton) EndIf
Timer.Resume() EndIf
EndSub

Sub StopGame
GameStatus = "Stopped"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton, "Start
Game") Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.ShowControl(OptionsButton) EndSub

Sub DownThrustButtonClick If (GameStatus = "Playing") Then If


(FuelRemaining > 0) Then Sound.Stop(Program.Directory +
"\vthrust.wav") Sound.Play(Program.Directory + "\vthrust.wav")
DownThrustOn = "true"
If (PilotLevel <> 5) Then LanderYSpeed = LanderYSpeed ‐
YDelta Else
LanderYSpeed = LanderYSpeed ‐ 2 * YDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
VFuel EndIf
EndIf
EndIf
EndSub

Sub LeftThrustButtonClick If (GameStatus = "Playing") Then If


(FuelRemaining > 0) Then Sound.Stop(Program.Directory +
"\hthrust.wav") Sound.Play(Program.Directory + "\hthrust.wav")
LeftThrustOn = "true"
If (PilotLevel <> 5) Then LanderXSpeed = LanderXSpeed +
XDelta Else
LanderXSpeed = LanderXSpeed + 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

Sub RightThrustButtonClick If (GameStatus = "Playing") Then If


(FuelRemaining > 0) Then Sound.Stop(Program.Directory +
"\hthrust.wav") Sound.Play(Program.Directory + "\hthrust.wav")
RightThrustOn = "true"
If (PilotLevel <> 5) Then LanderXSpeed = LanderXSpeed ‐
XDelta Else
LanderXSpeed = LanderXSpeed ‐ 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub

Sub UpdateTrajectory TrajectoryXScale = TrajectoryWidth /


LandscapeWidth TrajectoryYScale = TrajectoryHeight / LandscapeHeight
If (Time = 0.0) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight) GraphicsWindow.PenColor =
"Red"
GraphicsWindow.PenWidth = 2
'four points for red trajectory line
x1 = TrajectoryLeft + TrajectoryXScale * (LanderX + LanderWidth /
2) y1 = TrajectoryTop + TrajectoryYScale * (LanderY + LanderHeight)
x2 = TrajectoryLeft + TrajectoryXScale * (PadX + PadWidth / 2) y2 =
TrajectoryTop + TrajectoryYScale * (PadY + PadHeight)
GraphicsWindow.DrawLine(x1, y1, x2, y2) Altitude0 = Altitude Lateral0
= Lateral EndIf
'location of circles
x1 = TrajectoryXScale * (LanderX + LanderWidth / 2) ‐ 3
If (x1 < 0) Then x1 = 0
ElseIf (x1 > TrajectoryWidth ‐ 6) Then x1 = TrajectoryWidth ‐ 6
EndIf
y1 = TrajectoryYScale * (LanderY + LanderHeight) ‐ 3
If (y1 < 0) Then y1 = 0
EndIf
'light green circles 6 x 6 pixels
GraphicsWindow.PenColor = "LightGreen"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawEllipse(TrajectoryLeft + x1, TrajectoryTop + y1,
6, 6) EndSub

Sub UpdateViewer
'position lander
ViewLanderX = CenterX
ViewLanderY = CenterY
'adjust landscape background
LandscapeX = LanderX ‐ CenterX
If (LandscapeX <= 0) Then LandscapeX = 0
ViewLanderX = LanderX
EndIf
If (LandscapeX >= LandscapeWidth ‐ ViewerWidth) Then LandscapeX
= LandscapeWidth ‐ ViewerWidth ViewLanderX = LanderX ‐
LandscapeX
EndIf
LandscapeY = LanderY ‐ CenterY
If (LandscapeY <= 0) Then LandscapeY = 0
ViewLanderY = LanderY
EndIf
If (LandscapeY >= LandscapeHeight ‐ ViewerHeight) Then LandscapeY
= LandscapeHeight ‐ ViewerHeight ViewLanderY = LanderY ‐
LandscapeY
EndIf
'keep lander in borders
If (ViewLanderX < 0) Then ViewLanderX = 0
ElseIf (ViewLanderX + LanderWidth > ViewerWidth) Then
ViewLanderX = ViewerWidth ‐ LanderWidth EndIf
If (ViewLanderY < 0) Then ViewLanderY = 0
EndIf
'show lander
Shapes.Move(Lander, ViewerLeft + ViewLanderX, ViewerTop +
ViewLanderY) 'add thrusters if on
If (DownThrustOn) Then Shapes.Move(DownThrust, ViewerLeft +
ViewLanderX + 0.5 * LanderWidth ‐ 0.5 * VThrustWidth, ViewerTop +
ViewLanderY + LanderHeight ‐ VThrustHeight)
Shapes.ShowShape(DownThrust) DownThrustOn = "false"
Else
Shapes.HideShape(DownThrust) EndIf
If (LeftThrustOn) Then Shapes.Move(LeftThrust, ViewerLeft +
ViewLanderX ‐ 5, ViewerTop + ViewLanderY + 40)
Shapes.ShowShape(LeftThrust) LeftThrustOn = "false"
Else
Shapes.HideShape(LeftThrust) EndIf
If (RightThrustOn) Then Shapes.Move(RightThrust, ViewerLeft +
ViewLanderX + LanderWidth ‐ HThrustWidth + 5, ViewerTop +
ViewLanderY + 40) Shapes.ShowShape(RightThrust) RightThrustOn =
"false"
Else
Shapes.HideShape(RightThrust) EndIf
'see if landing pad is in landscape
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop, ViewerWidth,
ViewerHeight) If (PadX >= LandscapeX And PadX <= LandscapeX +
ViewerWidth) Then If (PadY > LandscapeY And PadY < LandscapeY +
ViewerHeight) Then 'at right or completely in window
GraphicsWindow.BrushColor = "DarkRed"
W = LandscapeX + ViewerWidth ‐ PadX
If (W > PadWidth) Then W = PadWidth EndIf
H = LandscapeY + ViewerHeight ‐ PadY
GraphicsWindow.FillRectangle(ViewerLeft + PadX ‐
LandscapeX, ViewerTop + PadY ‐ LandscapeY, W, H) EndIf
ElseIf (PadX + PadWidth > LandscapeX And PadX + PadWidth <
LandscapeX + ViewerWidth) Then If (PadY > LandscapeY And PadY <
LandscapeY + ViewerHeight) Then 'at left
GraphicsWindow.BrushColor = "DarkRed"
W = PadX + PadWidth ‐ LandscapeX
H = LandscapeY + ViewerHeight ‐ PadY
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop + PadY ‐
LandscapeY, W, H) EndIf
EndIf
EndSub
Moon Landing Game Program Review

The Moon Landing game program is now complete. Save and Run the
program and make sure it works as promised. Check that all options work
correctly.

If there are errors in your implementation, go back over the steps of


window and code design. Go over the developed code – make sure you
understand how different parts of the program were coded. As mentioned in
the beginning of this chapter, the completed program is saved as
MoonLanding in the KidGamesSB\KidGamesSB
Programs\MoonLanding folder.

While completing this program, new concepts and skills you should have
gained include:

➢ Proper steps in game design and game flow.


➢ Use of math and physics to describe motion.
➢ How to move around landscape backgrounds.
➢ The concept and use of animation.
➢ How to code a moon landing auto-pilot.
Moon Landing Game Program Enhancements

There are some ways to change the Moon Landing program. Some
possibilities are:

➢ It would be nice if the options selections you make are saved from
one game to the next. This requires the use of files which are
discussed in the next chapter.
➢ Add more elaborate graphic effects upon crash landings.
➢ Add keyboard control for the thrusters.
➢ Add a way to graphically see how close you are to a safe landing
speed (rather than just display the number).
➢ As implemented, you may notice a bit of a delay between hearing a
thruster and seeing the graphic display. This delay is because the
sound and drawing of the thrust are in two different subroutines. I
kind of like the delay – you hear the sound, then pretty soon the
flames start flying. If the delay bothers you, try to put the sound and
graphics in the same routine.
➢ The current game gives minimal evaluation of the landing, just
checking to see if the vertical speed is acceptable. Expand the
definition of a safe landing to include horizontal position and speed.
You might like to add some comments. In the original text versions
of this game, comments on the landing were quite cynical. Some
example comments for bad landings from these old programs are:

“Sorry, there were no survivors – you blew it!”


“Appropriate condolences will be sent to your next of kin.”
“The space program hates to lose experienced astronauts.”
10. Leap Frog Program
Review and Preview

The final game we build is a version of a classic video game named


Frogger. We call our game Leap Frog. In the game, you maneuver a
frog through highway traffic, past a roaming snake and across a
raging river to reach home safely.

The game features fun graphics and multiple levels for challenging play.
While building the program, you learn more graphics capabilities and how to
work with data files (for saving high scores).
Leap Frog Program Preview

In this chapter, we will build a Leap Frog game. In the game, you move a
frog across a busy road, past a roaming snake and through a river with
interesting currents, to reach home safely. Once five frogs are safe, you
achieve a new level.

The finished program is saved as LeapFrog in the


KidGamesSB\KidGamesSB Programs\LeapFrog folder. Start Small Basic
and open the finished program. Run the program (click the Run toolbar
button or press <F5>). The game will appear in its ‘stopped’ state. It’s kind
of boring right now – nothing appears until the game is started. At this point,
you can click the Start Game button to start the game, click Exit to exit the
program, or click High Scores to see the top ten scores.
Note the title bar states this is Level 1. A high score appears. The five homes
(black rectangles) are drawn near the top of the window and lines appear on
the road.

Now, click Start Game, then immediately click Pause Game to see what
the game screen looks like while playing:

That’s better – there’s things to see now. Let’s describe how the game is
played.

As you see, your frog starts out at the bottom. You use the keyboard arrow
keys to move the frog from the bottom of the screen into one of the safe
homes at the top. The first challenge is cross road with cars, trucks and
semis. The first two lanes travel right-to-left, while the third travels left-to-
right. If a vehicle collides with the frog or the frog collides with a vehicle, a
beep is heard and the frog’s journey stops. You lose a frog and try again (the
number of frogs you have remaining is shown in the upper right corner).
Restart the game and try to get the frog through the traffic. Pause the game
once you make it. Here’s what things look like after I made it (you can use
the up, down, left or right arrow keys to avoid traffic):

My score is up to 402 points. Notice the snake that just went by. Once you
cross the highway, this snake will pop up randomly, traveling left-to-right. If
the snake and frog collide, a sound is heard, the journey ends and a new frog
tries the trip.

After crossing the road and avoiding the snake, the frog needs to cross the
river by jumping onto floating logs to reach home. The Leap Frog game
features a river with unique current characteristics. As you go up, the first
row of logs travels left-to-right, the second travels right-to-left and the final
row travels left-to-right. Your job is to maneuver the frog across the logs and
move him into one of the homes at the top of the screen. If you miss a log,
miss home or float off the edge of the screen, a splashing sound is heard, the
journey ends and another frog gives it a try. If you successfully reach home,
the frog “ribbits,” you are given bonus points and another frog appears at the
bottom of the screen. Fill all five homes with frogs and you move to the next
level. As you go to higher levels, game play gets faster, more vehicles and
fewer logs appear.

Restart the game and try to get a frog home. You’ll find the home on the left
is the hardest to reach. Here’s my screen after getting four frogs home:
Then, when I get the final frog home, the game switches to Level 2:

A log has been removed and things are faster. I’ve been lucky so far and still
have all my frogs left.

As seen, at any time during the program, you may pause the action by
clicking Pause Game. To restart, click Restart Game. To stop the program
before running out of frogs, click Stop Game. Once a game is stopped, your
score is checked against other scores to see if you have one of the ten highest
scores. When I click Stop Game, after playing a bit longer, this text window
appears:

My score appears in Position 5. I type my name and press Enter. Keeping


track of high scores is a fun part of arcade games.

Continue playing Leap Frog to understand its operation. You’ll find it’s
quite addictive as you try to beat your past scores. Click Exit when you’re
done to stop the program. Look over the code, if you like.

You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.

We address window design. Specifically, we discuss sizing the form and


game panels to meet the needs of graphics used in the game. And, we
address code design. New graphics methods are learned, we look at moving
objects using the keyboard and how to detect collisions. We’ll also discuss
strategies behind different game levels and how to keep track of high scores
(using files).
Game Design – Prelude to Window Design

Before beginning the Leap Frog program, we need to talk a bit about game
design. In this game (and all arcade type games), things are constantly
moving around and the code is checking to see where things are located and
whether they are colliding with other things. To do all this, we need specific
information about the size of the objects used in the game.

In Leap Frog, the basic object will be the frog. The program uses several
images to represent the frog moving up, down, left, right or sitting at home.
Each of these images is 40 pixels by 40 pixels. For example, the frog moving
up (FrogUp.gif, in the KidGamesSB\KidGamesSB Programs\LeapFrog

folder) is:

This frog needs to fit in a highway lane, in the area with the snake, on a
floating log in the river and in the home location at the top of the screen.
Hence, in designing the game form, each element, whether it is a panel
hosting graphics or an element within the panel (vehicle, snake, log), will be
sized with this basic ‘frog element’ in mind.

Three vehicles are used the game, a car, a truck and a semi, each vehicle
having a left moving image and a right moving image. The car is 40 pixels
by 40 pixels. Here is the left moving car (LeftCar.gif, in the

KidGamesSB\KidGamesSB Programs\LeapFrog folder):

The truck is 80 pixels by 40 pixels (2 ‘frog units’). Here is the left moving
truck (LeftTruck.gif, in the KidGamesSB\KidGamesSB

Programs\LeapFrog folder):

And, the semi is 120 pixels by 40 pixels (3 ‘frog units’). Here is the left
moving semi (LeftSemi.gif, in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder):

Similarly, three log sizes are used in the game. The smallest log is 40 pixels
by 40 pixels (SmallLog.gif, in the KidGamesSB\KidGamesSB

Programs\LeapFrog folder):

The next size log is 80 pixels by 40 pixels (MediumLog.gif, in the

KidGamesSB\KidGamesSB Programs\LeapFrog folder):

and the largest log is 120 pixels by 40 pixels (LargeLog.gif, in the


KidGamesSB\KidGamesSB Programs\LeapFrog folder):

Two snake images are used to give a slithering appearance. Each of these is
111 pixels by 24 pixels. Here is one of the images (Snake1.gif, in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder):

This images does violate our rule of being based on ‘frog units,’ but since we
only look for collisions with the snake, the rule is easily worked around.

Now, let’s start the game window, assigning specific sizes to the panel areas
based on these graphic elements.
Leap Frog Window Design

Here is a sketch for the window layout for the Leap Frog program:

The basic window layout is quite simple. There are areas at the top to keep
track of game scores. Then, several ‘panels’ are used to display the graphics
used in Leap Frog. The frog moves up the screen. The Start panel at the
bottom(green; 640 x 40 pixels) is where the frog begins its journey. The next
panel up is the Road (gray; 640 x 140 pixels) which has the moving traffic.
Then, a Grass panel (green; 640 x 40 pixels) with a snake, a River panel
(blue; 640 x 120 pixels) with floating logs and the Home panel (green; 640 x
80 pixels) has frog finishing spots. Two buttons at the bottom are used to
start/pause the game and to stop the game or exit the program. And a button
is used to display high scores.

We will now begin writing the code for the game. We will write the code in
several steps. We’ll start with the graphics elements. We have many things
moving around. In the previous chapter, we used the Shapes object and
introduced the idea of animation using the Move method. We do the same
here. First, we program the moving vehicles. Then, we add additional
elements to the game, one at a time. During the code development process,
recognize you may modify a particular subroutine several times before
arriving at the finished product.

Start a new program in Small Basic. Once started, we suggest you


immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Add Buttons

As a first step, we build the basic game window and add the controlling
buttons. Put this code in the code window: ' Leap Frog
InitializeProgram()

Sub InitializeProgram 'graphics window


GraphicsWindow.Width = 640
GraphicsWindow.Height = 510
GraphicsWindow.Title = "Leap Frog"
GraphicsWindow.BackgroundColor = "DarkGreen"
GameStatus = "Stopped"
'define buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
StartPauseButton = Controls.AddButton("Start Game", 120, 475)
Controls.SetSize(StartPauseButton, 120, 31) ExitStopButton =
Controls.AddButton("Exit", 260, 475)
Controls.SetSize(ExitStopButton, 120, 31) HighScoresButton =
Controls.AddButton("High Scores", 400, 475)
Controls.SetSize(HighScoresButton, 120, 31) Controls.ButtonClicked
= ButtonClickedSub EndSub

The first line of code calls a subroutine InitializeProgram where we will


put all code needed to set up the program for use. This code sets up the
window, sets the GameStatus as “Stopped” and places the three control
buttons at the bottom of the window. Note each time a ButtonClicked event
occurs, the subroutine named ButtonClickedSub is called.

Add the ButtonClickedSub subroutine: Sub ButtonClickedSub


B = Controls.LastClickedButton If (B = StartPauseButton) Then '
start, stop, pause button
StartPauseButtonClick() ElseIf (B = ExitStopButton) Then 'exit,
stop button
ExitStopButtonClick() ElseIf (B = HighScoresButton) Then 'high
scores button
HighScoresButtonClick() EndIf
EndSub

And, add the three empty subroutines for each individual button click: Sub
StartPauseButtonClick EndSub

Sub ExitStopButtonClick EndSub

Sub HighScoresButtonClick EndSub

We will add code to each of these subroutines as we build the Leap Frog
game.
Save and Run the program. The three buttons will appear:
Code Design – Road Panel

In Leap Frog, the vehicles will move in the Road panel and motion will be
governed by the Small Basic Timer object. There are three different vehicles
(car, truck, semi), each with the capability of moving left or right. The
images used for each vehicle/direction are found in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder:

Recall cars are 40 pixels by 40 pixels, trucks are 80 pixels by 40 pixels and
semis are 120 pixels by 40 pixels. The program will assume these files are in
your program’s folder. Copy the six files to that folder.

The road panel will have three lanes (each 40 pixels high). In the top lane,
vehicles will travel from left to right. In the bottom two lanes, vehicles will
travel from right to left. Recall the road panel is 140 pixels high, 120 pixels
for the three travel lanes and the additional pixels for lane markings. The
layout of the road panel is (not to scale):
The border area of each lane is 5 pixels high. Make sure you see how the
total height is 140 pixels.

We will use 12 vehicles (at most, lower game levels will have fewer), four in
each lane. The vehicles will be represented by an array (Vehicle) of Shapes
objects. The assignments I made are (feel free to change these if you like):
Vehicle[1]: Semi, Top Lane Vehicle[2]: Truck, Top Lane Vehicle[3]: Car,
Top Lane Vehicle[4]: Car, Top Lane Vehicle[5]: Truck, Middle Lane
Vehicle[6]: Car, Middle Lane Vehicle[7]: Truck, Middle Lane Vehicle[8]:
Truck, Middle Lane Vehicle[9]: Car, Bottom Lane Vehicle[10]: Semi,
Bottom Lane Vehicle[11]: Car, Bottom Lane Vehicle[12]: Truck, Bottom
Lane Add this code to InitializeProgram to establish the Road panel and
images used for the vehicles: 'Vehicles on road
RoadTop = 290
RoadHeight = 140
DrawRoad()
NumberOfVehicles = 12
Vehicle[1] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightSemi.gif")) Vehicle[2] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightTruck.gif")) Vehicle[3] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightCar.gif")) Vehicle[4] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightCar.gif")) Vehicle[5] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[6] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[7] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[8] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[9] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[10] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftSemi.gif")) Vehicle[11] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[12] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) For I = 1 to 12
Shapes.HideShape(Vehicle[I]) VehicleIsVisible[I] = "false"
EndFor

This defines the size and position of the Road panel (RoadTop,
RoadHeight) and draws the empty road (DrawRoad subroutine). That
subroutine is: Sub DrawRoad
GraphicsWindow.BrushColor = "DimGray"
GraphicsWindow.FillRectangle(0, RoadTop, GraphicsWindow.Width,
RoadHeight) 'draw road lines
GraphicsWindow.PenColor = "White"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawLine(0, RoadTop + 2, GraphicsWindow.Width,
RoadTop + 2) GraphicsWindow.DrawLine(0, RoadTop + RoadHeight
‐ 2, GraphicsWindow.Width, RoadTop + RoadHeight ‐ 2)
GraphicsWindow.DrawLine(0, RoadTop + 92,
GraphicsWindow.Width, RoadTop + 92) GraphicsWindow.PenColor =
"Yellow"
GraphicsWindow.DrawLine(0, RoadTop + 47,
GraphicsWindow.Width, RoadTop + 47)
GraphicsWindow.DrawLine(0, RoadTop + 49,
GraphicsWindow.Width, RoadTop + 49) EndSub

White lines are used to define the sides of the road and to separate the two
lower lanes. Two yellow lines separate the traffic moving in opposite
directions. After drawing the road, this code defines the 12 Shapes objects
(Vehicle array) we will use for the vehicles. Note the code expects all image
files to be in your program folder. After the vehicles are created, they are
hidden until the game begins. If we don’t do this, all the images will appear
in the upper left corner of the window (try it if you like). The array
VehicleIsVisible is used to indicate if a particular vehicle is visible.

Save and Run the program. You will see an empty road:

The vehicle positions are initialized when the Start Game button is clicked.
Let’s do that.

The StartPauseButton and ExitStopButton have certain interactions. The


StartPauseButton can have one of three possible actions based on
GameStatus. If the GameStatus is “Stopped” when the button is clicked,
the game is initialized and put in playing mode using:

➢ Change GameStatus to “Playing”


➢ Change caption to Pause Game.
➢ Change caption of ExitStopButton to Stop Game.
➢ Position the vehicles and display the vehicles.

When GameStatus is “Playing” and the button is clicked, we enter pause


mode:

➢ Change GameStatus to “Paused”


➢ Change caption to Restart Game.
➢ Hide ExitStopButton.

When Game Status is “Paused” and the button is clicked, we re-enter


playing mode:

➢ Change GameStatus to “Playing”


➢ Change caption to Pause Game.
➢ Show ExitStopButton.

The StartPauseButtonClick subroutine that accomplishes these steps is:


Sub StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus
= "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
PositionVehicles()
For I = 1 To NumberOfVehicles Shapes.ShowShape(Vehicle[I])
VehicleIsVisible[I] = "true"
EndFor
ElseIf (GameStatus = "Playing") Then GameStatus = "Paused"
Controls.SetButtonCaption(StartPauseButton, "Restart Game")
Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) EndIf
EndSub
The subroutine PositionVehicles draws the road and assigns the initial
vehicle positions. Add this to the program: Sub PositionVehicles
DrawRoad()
'top row
VehicleX[1] = 20
VehicleY[1] = RoadTop + 5
VehicleW[1] = 120
VehicleH[1] = 40
VehicleX[2] = 200
VehicleY[2] = RoadTop + 5
VehicleW[2] = 80
VehicleH[2] = 40
VehicleX[3] = 380
VehicleY[3] = RoadTop + 5
VehicleW[3] = 40
VehicleH[3] = 40
VehicleX[4] = 540
VehicleY[4] = RoadTop + 5
VehicleW[4] = 40
VehicleH[4] = 40
'middle row
VehicleX[5] = 40
VehicleY[5] = RoadTop + 50
VehicleW[5] = 80
VehicleH[5] = 40
VehicleX[6] = 220
VehicleY[6] = RoadTop + 50
VehicleW[6] = 40
VehicleH[6] = 40
VehicleX[7] = 360
VehicleY[7] = RoadTop + 50
VehicleW[7] = 80
VehicleH[7] = 40
VehicleX[8] = 520
VehicleY[8] = RoadTop + 50
VehicleW[8] = 80
VehicleH[8] = 40
'bottom row
VehicleX[9] = 60
VehicleY[9] = RoadTop + 95
VehicleW[9] = 40
VehicleH[9] = 40
VehicleX[10] = 180
VehicleY[10] = RoadTop + 95
VehicleW[10] = 120
VehicleH[10] = 40
VehicleX[11] = 380
VehicleY[11] = RoadTop + 95
VehicleW[11] = 40
VehicleH[11] = 40
VehicleX[12] = 520
VehicleY[12] = RoadTop + 95
VehicleW[12] = 80
VehicleH[12] = 40
'speeds
VehicleSpeed[1] = 3
VehicleSpeed[2] = 3
VehicleSpeed[3] = 3
VehicleSpeed[4] = 3
VehicleSpeed[5] = ‐3
VehicleSpeed[6] = ‐3
VehicleSpeed[7] = ‐3
VehicleSpeed[8] = ‐3
VehicleSpeed[9] = ‐2
VehicleSpeed[10] = ‐2
VehicleSpeed[11] = ‐2
VehicleSpeed[12] = ‐2
For I = 1 to NumberOfVehicles Shapes.Move(Vehicle[I], VehicleX[I],
VehicleY[I]) EndFor
EndSub

Each vehicle requires a size (VehicleW, VehicleH), a position within the


panel (VehicleX, VehicleY), and a speed (VehicleSpeed). Vehicles in the top
lane are assigned a speed of +3 (moving to the right), vehicles in the middle
lane have a speed of -3 (moving to the left), and vehicles in the bottom lane
have a speed of -2 (moving to left). Each vehicle is placed to give a uniform
spacing within the lane. I found spacings by sketching things on a piece of
graph paper.

Save and Run the program. Click Start Game. The vehicles will appear on
a mainly empty window:
Notice the lane assignments, the directions and the nice initial spacing.
Check that the StartPauseButton caption properly reflects the current
status. Let’s get the vehicles moving.

The Timer object defines the motion of the vehicles (and all other motions
in the Leap Frog game). Add this code at the end of InitializeProgram:
Timer.Interval = 100
Timer.Tick = TimerTickSub Timer.Pause() This establishes the Interval,
assigns the TimerTickSub subroutine to the Tick event and turns off the
Timer initially.

We need code to turn the timer on and off at the proper times. Add the
shaded lines to the StartPauseButtonClick subroutine to accomplish this:
Sub StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus
= "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
PositionVehicles()
For I = 1 To NumberOfVehicles Shapes.ShowShape(Vehicle[I])
VehicleIsVisible[I] = "true"
EndFor
Timer.Resume()
ElseIf (GameStatus = "Playing") Then
Timer.Pause()
GameStatus = "Paused"
Controls.SetButtonCaption(StartPauseButton, "Restart Game")
Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton)
Timer.Resume()
EndIf
EndSub

Once the timer is on, with each Tick event, each vehicle is repositioned
using the Move method of the Shapes object (and the Speed property).
Eventually, a vehicle will leave the road panel. What do we do once a
vehicle leaves the road panel? One possibility would be to immediately
restart the vehicle at the opposite end of the panel. The problem with this
approach is that if a large vehicle (say a semi) leaves the panel followed
immediately by a smaller vehicle, the two vehicles will overlap as they are
redrawn on the opposite end of the panel. To avoid this overlap, we will
‘delay’ redrawing cars by 80 pixels and ‘delay’ drawing trucks by 40 pixels.
This way, each vehicle is in its own buffer of 120 pixels (the size of a semi)
and no overlap will occur.

Add this code to the TimerTickSub subroutine. This code moves each
vehicle (if its VehicleIsVisible property is “true”). If a vehicle leaves the
right side of the form, it is repositioned to the left side of the form (VehicleX
= - 120 pixels, to maintain the 120 pixel buffer zone). If a vehicle leaves the
left side of the form, it is repositioned to the right side of the form (VehicleX
dependent on vehicle width, maintaining a 120 pixel buffer): Sub
TimerTickSub
'Road Update
For I = 1 To NumberOfVehicles If VehicleIsVisible[I] Then
VehicleX[I] = VehicleX[I] + VehicleSpeed[I]
Shapes.Move(Vehicle[I], VehicleX[I], VehicleY[I]) If
(VehicleX[I] > GraphicsWindow.Width And VehicleSpeed[I] >
0) Then VehicleX[I] = ‐120
EndIf
If (VehicleX[I] < ‐VehicleW[I] And VehicleSpeed[I] < 0) Then
VehicleX[I] = GraphicsWindow.Width + (120 ‐ VehicleW[I])
EndIf
EndIf
EndFor
EndSub

Study this code to make sure you see how things work.

Save and Run the program. Click Start Game and you have moving
vehicles! Notice how there is never any overlap in vehicles:
Make sure you can pause and restart the motion. The Stop Game button
doesn’t work yet – let’s fix that.

When a player clicks Stop Game (the ExitStopButton in “Playing” mode),


the following should happen:

➢ Change GameStatus to “Stopped”


➢ Stop Timer.
➢ Change caption to Exit.
➢ Change caption of StartPauseButton to Start Game.

If the ExitStopButton is clicked when GameStatus is “Stopped”, the


program stops.
The ExitStopButtonClick subroutine is: Sub ExitStopButtonClick If
(GameStatus = "Playing") Then StopGame()
Else
Program.End() EndIf
EndSub

which uses the StopGame subroutine that implements the listed steps for
stopping: Sub StopGame
Timer.Pause() GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") EndSub

Save and Run the program. Make sure you can start, pause and stop the
game. Make sure you can stop the game and stop the program.

Before moving on, let’s make one more change. The Leap Frog game will
have levels of play, starting out easy (Level 1) and getting progressively
harder as you play. We will discuss these levels in more detail later. In the
first level, if all 12 vehicles are used, it makes it very hard for the frog to get
across the road. We will start the game with just 7 vehicles, removing
vehicles 1, 4, 5, 7 and 11 (some from each lane).

The vehicle removal is done in the StartPauseButtonClick subroutine


(changes are shaded): Sub StartPauseButtonClick If (GameStatus =
"Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
PositionVehicles()
For I = 1 To NumberOfVehicles Shapes.ShowShape(Vehicle[I])
VehicleIsVisible[I] = "true"
EndFor
'Clear vehicles for Level 1
Shapes.HideShape(Vehicle[1]) VehicleIsVisible[1] = "false"
Shapes.HideShape(Vehicle[4]) VehicleIsVisible[4] = "false"
Shapes.HideShape(Vehicle[5]) VehicleIsVisible[5] = "false"
Shapes.HideShape(Vehicle[7]) VehicleIsVisible[7] = "false"
Shapes.HideShape(Vehicle[11]) VehicleIsVisible[11] = "false"
Timer.Resume() ElseIf (GameStatus = "Playing") Then
Timer.Pause() GameStatus = "Paused"
Controls.SetButtonCaption(StartPauseButton, "Restart Game")
Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) Timer.Resume() EndIf
EndSub

Save and Run the program again, making sure only 7 vehicles appear. There
will be 2 vehicles in the top lane, 2 in the middle lane and 3 in the bottom

lane:
Let’s move to the next graphical element, the moving logs in the river panel.
You’ll see the coding process is nearly identical to that for the vehicles.
Code Design – River Panel

The logs move in the River panel and motion is governed by the same
Timer object. There are three size logs – there is no distinction between
direction motion. The images are found in the KidGamesSB\KidGamesSB

Programs\LeapFrog folder:

Small logs are 40 pixels by 40 pixels, medium logs are 80 pixels by 40


pixels and large logs are 120 pixels by 40 pixels. These images will be used
to create our Shapes objects. The program will assume these files are in your
program’s folder. Copy the three files to that folder.

The river panel will have three rows (each 40 pixels high). In the top and
bottom rows, logs will travel from left to right. In the middle row, logs will
travel from right to left. The river is 120 pixels high – there are no border
areas like we used in the road panel.

We will use 12 logs (at most, higher game levels will have fewer). There will
be five logs in the top row, four logs in the middle row and three in the
bottom row. The logs will be represented by an array (Log) of Shapes
objects. The assignments I made are: Log(1): Medium Log, Top Row
Log(2): Large Log, Top Row Log(3): Small Log, Top Row Log(4): Medium
Log, Top Row Log(5): Medium Log, Top Row Log(6): Small Log, Middle
Row Log(7): Large Log, Middle Row Log(8): Medium Log, Middle Row
Log(9): Large Log, Middle Row Log(10): Large Log, Bottom Row
Log(11): Medium Log, Bottom Row Log(12): Large Log, Bottom Row I put
more logs in the top row to make it easier for a frog to get home.

Let’s code the moving logs. Add this code to InitializeProgram to draw the
river and establish the Log Shapes objects: 'logs in river
RiverTop = 130
RiverHeight = 120
GraphicsWindow.BrushColor =
GraphicsWindow.GetColorFromRGB(128, 128, 255)
GraphicsWindow.FillRectangle(0, RiverTop, GraphicsWindow.Width,
RiverHeight) NumberOfLogs = 12
Log[1] = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[2] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[3] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\SmallLog.gif")) Log[4] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[5] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[6] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\SmallLog.gif")) Log[7] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[8] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[9] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[10] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[11] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[12] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) For I = 1 to 12
Shapes.HideShape(Log[I]) LogIsVisible[I] = "false"
EndFor

Notice the image files must be in your program’s folder. Like the vehicles,
the logs are hidden until the game begins. The array LogIsVisible is used to
indicate if a particular vehicle is visible.

Add the shaded lines to the StartPauseButtonClick subroutine to initially


position the logs using the PositionLogs subroutine: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
PositionVehicles()
'Clear vehicles for Level 1
Shapes.HideShape(Vehicle[1]) VehicleIsVisible[1] = "false"
Shapes.HideShape(Vehicle[4]) VehicleIsVisible[4] = "false"
Shapes.HideShape(Vehicle[5]) VehicleIsVisible[5] = "false"
Shapes.HideShape(Vehicle[7]) VehicleIsVisible[7] = "false"
Shapes.HideShape(Vehicle[11]) VehicleIsVisible[11] = "false"
PositionLogs()
For I = 1 To NumberOfLogs Shapes.ShowShape(Log[I])
LogIsVisible[I] = "true"
EndFor
Timer.Resume() ElseIf (GameStatus = "Playing") Then
Timer.Pause() GameStatus = "Paused"
Controls.SetButtonCaption(StartPauseButton, "Restart Game")
Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) Timer.Resume() EndIf
EndSub

The subroutine that does the positioning is:


Sub PositionLogs
GraphicsWindow.BrushColor =
GraphicsWindow.GetColorFromRGB(128, 128, 255)
GraphicsWindow.FillRectangle(0, RiverTop, GraphicsWindow.Width,
RiverHeight) 'top row
LogX[1] = 20
LogY[1] = RiverTop LogW[1] = 80
LogH[1] = 40
LogX[2] = 140
LogY[2] = RiverTop LogW[2] = 120
LogH[2] = 40
LogX[3] = 300
LogY[3] = RiverTop LogW[3] = 40
LogH[3] = 40
LogX[4] = 400
LogY[4] = RiverTop LogW[4] = 80
LogH[4] = 40
LogX[5] = 540
LogY[5] = RiverTop LogW[5] = 80
LogH[5] = 40
'middle row
LogX[6] = 60
LogY[6] = RiverTop + 40
LogW[6] = 40
LogH[6] = 40
LogX[7] = 180
LogY[7] = RiverTop + 40
LogW[7] = 120
LogH[7] = 40
LogX[8] = 360
LogY[8] = RiverTop + 40
LogW[8] = 80
LogH[8] = 40
LogX[9] = 500
LogY[9] = RiverTop + 40
LogW[9] = 120
LogH[9] = 40
'bottom row
LogX[10] = 40
LogY[10] = RiverTop + 80
LogW[10] = 120
LogH[10] = 40
LogX[11] = 280
LogY[11] = RiverTop + 80
LogW[11] = 80
LogH[11] = 40
LogX[12] = 480
LogY[12] = RiverTop + 80
LogW[12] = 120
LogH[12] = 40
'speeds
LogSpeed[1] = 5
LogSpeed[2] = 5
LogSpeed[3] = 5
LogSpeed[4] = 5
LogSpeed[5] = 5
LogSpeed[6] = ‐3
LogSpeed[7] = ‐3
LogSpeed[8] = ‐3
LogSpeed[9] = ‐3
LogSpeed[10] = 2
LogSpeed[11] = 2
LogSpeed[12] = 2
For I = 1 to NumberOfLogs Shapes.Move(Log[I], LogX[I], LogY[I])
EndFor
EndSub

Logs in the top row are assigned a speed of +5 (moving to the right), logs in
the middle row have a speed of -3 (moving to the left), and logs in the
bottom row have a speed of 2 (moving to right). Each log is initially placed
to give a uniform spacing within the row.

The code to move the logs is identical to that used to move the vehicles.
With each Tick event, each log is repositioned using the Move method of
the Shapes object (and the Speed property). When a log leaves the panel, it
wraps around to the other side (using the same 120 pixel buffer zone to
avoid overlap). Add this shaded code to the TimerTickSub subroutine: Sub
TimerTickSub
'Road Update
.
.
'River Update
For I = 1 To NumberOfLogs If (LogIsVisible[I]) Then LogX[I] =
LogX[I] + LogSpeed[I]
Shapes.Move(Log[I], LogX[I], LogY[I]) If (LogX[I] >
GraphicsWindow.Width And LogSpeed[I] > 0) Then LogX[I]
= ‐120
EndIf
If (LogX[I] < ‐LogW[I] And LogSpeed[I] < 0) Then LogX[I]
= GraphicsWindow.Width + (120 ‐ LogW[I]) EndIf
EndIf
EndFor
EndSub

Save and Run the program. Click Start Game and both the vehicles and
logs are moving!
Make sure you can pause and restart the motion. One more moving object to
code (the snake), then we can start programming our leaping frog!
Code Design – Grass Panel (Snake)

Just to make it a little more difficult for a frog to make the journey home, we
will have a snake randomly appear between the road and river. It will always
move from left to right. The snake moves in the Grass panel and motion is
governed by the Timer object. To give the snake a slithering effect, we will
alternate between two snake images (found in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder):

Each snake is 111 pixels by 24 pixels. These images will be used to define
our Shapes object. The program will assume these files are in your
program’s folder. Copy the two files to that folder.

The grass panel is 40 pixels high (to hold a frog eventually). We will
vertically center the snake image within this panel. The snake will have a
speed of 5 and randomly appear from the left side of the panel.

Place these lines in InitializeProgram: 'Snake


GrassTop = 250
GrassHeight = 40
Snake1 = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\Snake1.gif")) Snake2 =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\Snake2.gif")) Snake = Snake1
SnakeSpeed = 5
SnakeX = 0
SnakeY = GrassTop + 7
SnakeW = 111
SnakeH = 24
Shapes.HideShape(Snake1) Shapes.HideShape(Snake2) SnakeIsVisible =
"false"

This specifies the location of the Grass panel and defines the Shapes objects
(Snake1 and Snake2) we will use to display the snake. It also sizes,
positions and hides the snake.

The code to move the snake is in the TimerTickSub subroutine. Here’s the
code (shaded) I used: Sub TimerTickSub
'Road Update
.
.
'River Update
.
.
'snake update
If (SnakeIsVisible = "false") Then If (Math.GetRandomNumber(50))
= 1 Then SnakeX = ‐SnakeW
Snake = Snake1
Shapes.Move(Snake, SnakeX, SnakeY)
Shapes.ShowShape(Snake) SnakeIsVisible = "true"
EndIf
Else
Shapes.HideShape(Snake) If Snake = Snake1 Then Snake =
Snake2
Else
Snake = Snake1
EndIf
SnakeX = SnakeX + SnakeSpeed Shapes.Move(Snake, SnakeX,
SnakeY) Shapes.ShowShape(Snake) If (SnakeX >
GraphicsWindow.Width) Then Shapes.HideShape(Snake)
SnakeIsVisible = "false"
EndIf
EndIf
EndSub

The snake will appear randomly. To decide if a snake should appear, I used a
random number from 1 to 50. When that number is one, I start a snake
moving. This means a snake will start (on average) every 50 tick events.
Once a snake is started, it is positioned just off the left of the form and
drawn. Once a snake is moving (SnakeIsVisible is “true”), each subsequent
call to the subroutine updates its position using the Move method,
alternating between the two shape objects to give the slithering effect. Once
the snake leaves the right side of the form, it is removed from the screen
(there is no wrapping around like the logs and vehicles). At this point, the
program waits for another snake to appear.

Make the shaded change to the StopGame subroutine to clear the snake (if
there) when the game is stopped: Sub StopGame
Timer.Pause() GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Shapes.HideShape(Snake) SnakeIsVisible = "false"
EndSub

Save and Run the program. Click Start Game. The vehicles and logs start
moving and eventually a snake appears from the left side of the form:
Make sure you can pause and restart the motion. Now that we’ve
programmed the vehicles and snake for the frog to avoid and the logs to hop
on, it’s time to program the leaping frog.
Code Design – Moving the Frog

The frog will be able to leap from panel to panel and move horizontally
across panels. We will use a Shapes object to represent the frog. Four
images will be used to depict the frog depending on its direction of motion.
The images are in the KidGamesSB\KidGamesSB Programs\LeapFrog

folder):

Each frog is 40 pixels by 40 pixels. The program will assume these files are
in your program’s folder. Copy the four files to that folder.

The frog begins its journey on the Start panel at the bottom of the window
and ends its journey (if successful) on the Home panel at the top of the
window. In between, the frog traverses the three lanes in the Road panel, the
Grass panel with the moving snake and the three rows of logs in the River
panel. We define a variable (FrogLocation) to keep track of what panel (and
where on the panel in the case of the road and river) the frog is on. The
values for this variable and corresponding locations are (note FrogLocation
increases as the frog moves up the screen):

FrogLocation Location
8 Home
7 River (top row)
6 River (middle row)
5 River (bottom row)
4 Grass panel
3 Road (top lane)
2 Road (middle lane)
1 Road (bottom lane)
0 Start

For horizontal motion within a panel, the frog will leap in units of 40 pixels.
Hence, when a game begins, we want the frog to be near the center of the
start panel at an even multiple of 40 pixels. We choose an initial location of
320 pixels.

Let’s code the frog graphics and set up the start and home panels. Add this
code to InitializeProgram: 'Frogs
FrogUp = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogUp.gif")) FrogDown =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogDown.gif")) FrogLeft =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogLeft.gif")) FrogRight =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogRight.gif")) Shapes.HideShape(FrogUp)
Shapes.HideShape(FrogDown) Shapes.HideShape(FrogLeft)
Shapes.HideShape(FrogRight) FrogW = 40
FrogH = 40
StartTop = 430
StartHeight = 40
HomeTop = 50
HomeHeight = 80

This defines the Shapes object (Frog) we will use for the ‘current’ frog, the
four shapes (FrogUp, FrogLeft, FrogDown and FrogUp) to display the
frog, and variables defining the start and home panels, respectively. Again,
the graphics files must be in your program folder. For now, we treat the
home panel as an empty rectangular area. We will build a more complete
home area after discussing frog movement and collision detection (to see if a
frog makes it home).

Add a subroutine to your program (GetNewFrog) to initialize the frog in the


start panel (FrogLocation = 0): Sub GetNewFrog
FrogLocation = 0
FrogX = 320
FrogY = StartTop Frog = FrogUp Shapes.Move(Frog, FrogX, FrogY)
Shapes.ShowShape(Frog) EndSub

Make the shaded change to the StartPauseButtonClick subroutine to


initialize the frog (using GetNewFrog subroutine) in the start panel: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game") .
.
GetNewFrog()
Timer.Resume() ElseIf (GameStatus = "Playing") Then
Timer.Pause() GameStatus = "Paused"
Controls.SetButtonCaption(StartPauseButton, "Restart Game")
Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) Timer.Resume() EndIf
EndSub

Save and Run the program. Click Start Game. The ‘up frog’ will appear
ready to start its journey:
Let’s get the frog moving. For now, we’ll let it move with no worries about
getting hit by a vehicle or falling in the river. Later, we’ll code this
‘collision’ logic. To control motion of the frog, we will use the cursor control
arrows of the keyboard and the KeyDown event.

To move a frog from one panel to the next (changing the FrogLocation
variable) or left/right with a panel, we use the Shapes Move method. Within
a panel, we will move the frog 40 pixels in the appropriate direction (making
sure it stays on the panel). You may choose to change this value if you like.
We only allow frog movement if the game is not stopped or paused. We will
use the GameStatus variable to tell us if a game is in progress.

We’ll add a little ‘hop’ sound each time the frog moves. The sound file
Hop.wav is included in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder. Copy this file to your program’s folder.
Add this line at the end of InitializeProgram: GraphicsWindow.KeyDown =
KeyDownSub With this, each time a KeyDown event occurs, the subroutine
named KeyDownSub is called.

Now, add this code (there is a lot of it) to the KeyDownSub subroutine: Sub
KeyDownSub
KD = GraphicsWindow.LastKey If (GameStatus = "Playing") Then
'Clear from current location
Shapes.HideShape(Frog) If (KD = "Up") Then
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogUp
FrogLocation = FrogLocation + 1
If (FrogLocation > 8) Then FrogLocation = 8
EndIf
ElseIf (KD = "Left") Then Sound.Stop(Program.Directory +
"\Hop.wav") Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogLeft If FrogX > 0 Then FrogX = FrogX ‐ FrogW
EndIf
ElseIf (KD = "Down") Then Sound.Stop(Program.Directory +
"\Hop.wav") Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogDown FrogLocation = FrogLocation ‐ 1
If FrogLocation < 0 Then FrogLocation = 0
EndIf
ElseIf (KD = "Right") Then Sound.Stop(Program.Directory +
"\Hop.wav") Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogRight If (FrogX < GraphicsWindow.Width ‐ FrogW) Then
FrogX = FrogX + FrogW
EndIf
EndIf
'put in new location
DrawFrog()
EndIf
EndSub
This code uses a subroutine (DrawFrog) to do the movement. Add this: Sub
DrawFrog
If (FrogLocation = 0) Then FrogY = StartTop ElseIf (FrogLocation =
1 Or FrogLocation = 2 Or FrogLocation = 3) Then FrogY = RoadTop
+ 140 ‐ 45 * FrogLocation ElseIf (FrogLocation = 4) Then FrogY =
GrassTop ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or
FrogLocation = 7) Then FrogY = RiverTop + 120 ‐ 40 *
(FrogLocation ‐ 4) ElseIf (FrogLocation = 8) Then FrogY =
HomeTop + 40
EndIf
Shapes.Move(Frog, FrogX, FrogY) Shapes.ShowShape(Frog)
EndSub

Let’s look at what’s going on here. First, notice no key down events are
allowed unless the GameStatus is “Playing”. We hide the frog from its
current position. Next, we find which arrow key is pressed (variable KD).
The hop sound is played and the proper frog graphic is assigned. For vertical
motion, FrogLocation is adjusted accordingly (keeping it between 0 and 8).
For horizontal motion, the FrogX value is adjusted (either +40 pixels or -40
pixels, the value of FrogW), making sure the frog stays within screen
bounds. Then in DrawFrog, the frog is drawn (using Move) at its new
location. In particular, notice how FrogLocation is used to determine the
proper lane in the road panel and proper row in the river panel (using
FrogY).

One more change is needed. We want to make sure the frog is cleared from
the game screen when the game is stopped. Make the shaded change to the
StopGame subroutine: Sub StopGame
Timer.Pause() GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Shapes.HideShape(Snake) SnakeIsVisible = "false"
Shapes.HideShape(Frog)
EndSub
Save and Run the program. Click Start Game. Try out the arrow control
keys. Move the frog up and down the screen. Make sure it doesn’t go past
home or below the start panel. Try left and right motion. Make sure the frog
doesn’t leave the screen. Listen for the hop sound. Here’s my frog just sitting
in the river:

It’s pretty easy for the frog to make it home since there’s no danger from the
vehicles or snake and it can go right across the river to any location on the
home panel. We need logic to see if the frog collides with a vehicle or snake,
jumps on a log and makes it home safely. Each of these steps involves the
concept of collision detection.
Collision Detection

As the frog moves upward from one level to the next, we need some way to
see if it collides or overlaps with other objects. For example, in the road
panel, we need to see if a vehicle hits the frog. In the grass panel, we need to
check if the snake and frog collide. In the river, we want to see if the frog
overlaps with a log, so it can float down the river. And, once home (still to
be defined), we need to make sure the frog fits in the specific region. Each
shape is defined by a rectangle (known position, width and height). Hence,
we want to know if two rectangles overlap.

For the Leap Frog game, we can simplify the overlap decision. We know
what level (or panel) the frog is on, hence we know there is overlap with
objects in that panel in the vertical direction. Hence, we only need to look
for overlap in the horizontal direction. There are two possibilities – let’s look
at each. The first is when the frog overlaps a shape from the left:

In this case, we see the Frog overlaps the Shape (could be a car, a snake, a
log or a home position) if this condition holds: FrogX + FrogW > ShapeX
And FrogX + FrogW < ShapeX + ShapeW

where FrogW and ShapeW are widths of the frog and shape, respectively.

The other possibility of overlap is from the right:


In this case, we see the Frog overlaps the Shape, if this condition holds:
FrogX > ShapeX And FrogX < ShapeX + ShapeW

In the Leap Frog game, just because the frog overlaps a shape, we may not
want to declare a collision. Instead, we will compute the amount of overlap
(as a percentage of frog width). If this overlap is small, we won’t say there is
a collision. This will allow us to adjust how close a vehicle needs to be to the
frog before it disappears. Or, we can adjust how close to the edge of a log
the frog can get and still sit on it. Using the above previous two diagrams,
we see for the “left overlapping” case, the amount of overlap is: Overlap =
100 * (FrogX + FrogW ‐ ShapeX) / FrogW

And, for the “right overlapping” case, the amount of overlap is: Overlap =
100 * (ShapeX + ShapeW ‐ FrogX) / FrogW

The specified overlap logic is incorporated in this subroutine


(FindOverlap). Add this to your code: Sub FindOverlap
Overlap = 0
'check to see if Frog overlaps with shape defined by ShapeX, ShapeW
If (FrogX + FrogW > ShapeX And FrogX + FrogW < ShapeX +
ShapeW) Then Overlap = 100 * (FrogX + FrogW ‐ ShapeX) / FrogW
ElseIf (FrogX > ShapeX And FrogX < ShapeX + ShapeW) Then
Overlap = 100 * (ShapeX + ShapeW ‐ FrogX) / FrogW
EndIf
EndSub

Notice this returns an overlap value of zero if there is no overlap. Else it


returns the percentage of overlap.
Now, we’ll use the FindOverlap subroutine to see if the frog makes it across
the road, past the snake, across the river, then safely home.
Code Design – Vehicle Collisions

If the frog collides with a vehicle while crossing the road, its journey ends
(the frog is cleared and a new frog is placed in the home panel). We will
assume a collision when 10 percent of the frog intersects with a vehicle. This
will let the frog escape any close calls.

Collisions in Leap Frog will be monitored by the Timer object. We’ll play a
‘beep’ sound if the frog collides with a vehicle. The sound file Beep.wav is
included in the KidGamesSB\KidGamesSB Programs\LeapFrog folder.
Copy this file to your program’s folder.

Add the shaded code to the TimerTickSub subroutine: Sub TimerTickSub


'Road Update
.
.
'River Update
.
.
'snake update
.
.
'general status
'check for collisions
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
'vehicles in FrogLocation row
IFrog = 9 ‐ 4 * (FrogLocation ‐ 1) For I = IFrog To IFrog + 3
If (VehicleIsVisible[I]) Then ShapeX = VehicleX[I]
ShapeW = VehicleW[I]
FindOverlap()
If (Overlap > 10) Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
EndFor
EndIf
ExitTickSub:
EndSub

In this code, in the road panel (FrogLocation = 1, 2, 3), we see if frog has
collided with any visible vehicle (10 percent of the frog overlaps a vehicle).
If so, the subroutine NoMoreFrog is called to eliminate the frog. If there is
no overlap, nothing happens. Look at how IFrog is used to identify vehicles
in a particular FrogLocation.

The subroutine NoMoreFrog plays a beep, clears the frog in its current
location and gets a new frog: Sub NoMoreFrog
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
Sound.Stop(Program.Directory + "\Beep.wav")
Sound.Play(Program.Directory + "\Beep.wav") EndIf
Shapes.HideShape(Frog) GetNewFrog()
EndSub

Save and Run the program. Start the game. Try moving across the road. If
your frog is hit by a vehicle, you will hear a beep and a new frog will appear.
Code Design – Snake Collisions

If the frog successfully crosses the three lanes of vehicles, it must get past
the snake (if it’s there). If the frog collides with the snake, its journey ends.
We will assume a collision when the frog just touches the snake sprite. No
close calls allowed here!

We’ll play a ‘snake’ sound if the frog collides with the snake. The sound file
Snake.wav is included in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder. Copy this file to your program’s folder.

Place the shaded code in the TimerTickSub subroutine: Sub TimerTickSub


'Road Update
.
.
'River Update
.
.
'snake update
.
.
'general status
'check for collisions
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
.
.
.
'vehicles in FrogLocation row
IFrog = 9 ‐ 4 * (FrogLocation ‐ 1) For I = IFrog To IFrog + 3
If (VehicleIsVisible[I]) Then ShapeX = VehicleX[I]
ShapeW = VehicleW[I]
FindOverlap()
If (Overlap > 10) Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
EndFor
ElseIf (FrogLocation = 4) Then 'snake
If (SnakeIsVisible) Then ShapeX = SnakeX
ShapeW = SnakeW
FindOverlap()
If (Overlap > 1) Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
EndIf
ExitTickSub:
EndSub

In this new code, if any part of the frog (greater than 1 percent) overlaps
with the snake, the frog is cleared.

Make shaded changes to the NoMoreFrog subroutine: Sub NoMoreFrog


If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
Sound.Stop(Program.Directory + "\Beep.wav")
Sound.Play(Program.Directory + "\Beep.wav")
ElseIf (FrogLocation = 4) Then Sound.Stop(Program.Directory +
"\Snake.wav") Sound.Play(Program.Directory + "\Snake.wav")
EndIf
Shapes.HideShape(Frog) GetNewFrog()
EndSub

Following a snake collision, the snake sound is played, the frog is cleared
and a new frog appears.
Save and Run the program. Start the game. Successfully cross the road, then
sit in the grass panel until a snake appears. Make sure the snake collision
logic works (you’ll hear a sound and a new frog will appear).
Code Design - Log Collisions

Once the frog crosses the road and avoids the snake, it’s time to cross the
river. To do this, the frog must jump onto the floating logs as they go by. The
collision logic is different here. For the vehicles and the snake, if there is a
collision, the frog’s journey ends. Here, if there is a collision, we want the
frog to float with the log. If there is no collision, the frog’s journey ends with
a splash!

Before discussing the logic of floating on a log, let’s add the sound. We’ll
play a ‘splash’ sound if the frog misses a log. The sound file Splash.wav is
included in the KidGamesSB\KidGamesSB Programs\LeapFrog folder.
Copy this file to your program’s folder.

Once the frog enters the river, we need to see if it’s sitting on a log. If so,
with each timer update, the position of the frog will change with the position
of the log. To see if a frog is on a log, we use the FindOverlap subroutine. If
80 percent of the frog intersects with a log, we will say the frog is on the log
(this allows a little ‘hangover’ room). We will use a variable (OnLog) to
identify the ‘occupied’ log.

With each new frog, OnLog is initialized to zero. Add the shaded line to the
GetNewFrog subroutine to do this initialization: Sub GetNewFrog
OnLog = 0
FrogLocation = 0
FrogX = 320
FrogY = StartTop Frog = FrogUp Shapes.Move(Frog, FrogX, FrogY)
Shapes.ShowShape(Frog) EndSub

Each time the frog moves, we reset OnLog to zero to see if it stays on a log.
This is done with the shaded changes to the KeyDownSub subroutine: Sub
KeyDownSub
KD = GraphicsWindow.LastKey If (GameStatus = "Playing") Then
'Clear from current location
Shapes.HideShape(Frog) If (KD = "Up") Then
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogUp
FrogLocation = FrogLocation + 1
If (FrogLocation > 8) Then FrogLocation = 8
EndIf
ElseIf (KD = "Left") Then
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogLeft
If FrogX > 0 Then FrogX = FrogX ‐ FrogW
EndIf
ElseIf (KD = "Down") Then
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogDown FrogLocation = FrogLocation ‐ 1
If FrogLocation < 0 Then FrogLocation = 0
EndIf
ElseIf (KD = "Right") Then
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogRight If (FrogX < GraphicsWindow.Width ‐ FrogW)
Then FrogX = FrogX + FrogW
EndIf
EndIf
'put in new location
DrawFrog()
EndIf
EndSub
If OnLog is non-zero, we need to update the frog’s horizontal position as the
corresponding log moves. This is done in the TimerTickSub subroutine.
Make the shaded changes: Sub TimerTickSub
'Road Update
.
.
'River Update
For I = 1 To NumberOfLogs If (LogIsVisible[I]) Then LogX[I] =
LogX[I] + LogSpeed[I]
Shapes.Move(Log[I], LogX[I], LogY[I]) If OnLog = I Then
FrogX = FrogX + LogSpeed[I]
If (FrogX < 0 Or FrogX > GraphicsWindow.Width ‐
FrogW) Then NoMoreFrog()
Goto ExitTickSub
EndIf
Shapes.Move(Frog, FrogX, FrogY) EndIf
If (LogX[I] > GraphicsWindow.Width And LogSpeed[I] > 0)
Then LogX[I] = ‐120
EndIf
If (LogX[I] < ‐LogW[I] And LogSpeed[I] < 0) Then LogX[I]
= GraphicsWindow.Width + (120 ‐ LogW[I]) EndIf
EndIf
EndFor
'snake update
.
.
'general status
'check for collisions
.
.
ExitTickSub:
EndSub
In this code, the frog is moved in the same direction and the same amount as
the log it is on (Log array index is OnLog). If the frog goes off either end of
the river, it’s journey ends. Now, let’s see how to give a value to OnLog.

We check for log collisions later in the TimerTickSub subroutine. The


changes needed to set a value for OnLog are shaded: Sub TimerTickSub
'Road Update
.
.
'River Update
.
.
'snake update
.
.
'general status
'check for collisions
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
.
.
ElseIf (FrogLocation = 4) Then .
.
ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or FrogLocation = 7)
Then 'check if moved to log or already on a log
If OnLog = 0 Then If (FrogLocation = 5) Then ILog1 = 10
ILog2 = 12
ElseIf (FrogLocation = 6) Then ILog1 = 6
ILog2 = 9
ElseIf (FrogLocation = 7) Then ILog1 = 1
ILog2 = 5
EndIf
For I = ILog1 To ILog2
If (LogIsVisible[I]) Then ShapeX = LogX[I]
ShapeW = LogW[I]
FindOverlap()
If (Overlap > 80) Then OnLog = I Goto GotLog
EndIf
EndIf
EndFor
GotLog:
If OnLog = 0 Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
EndIf
ExitTickSub:
EndSub

The shaded steps are straightforward. If the frog is not on a log, it checks for
an ’80 percent’ overlap with any log in the current FrogLocation. If such an
overlap exists, OnLog is set. If no collision exists, the frog splashes away!
Notice if there is already a frog on a log (OnLog <> 0), no overlap checks
are made.

Make shaded changes to the NoMoreFrog subroutine: Sub NoMoreFrog


If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
Sound.Stop(Program.Directory + "\Beep.wav")
Sound.Play(Program.Directory + "\Beep.wav") ElseIf (FrogLocation
= 4) Then Sound.Stop(Program.Directory + "\Snake.wav")
Sound.Play(Program.Directory + "\Snake.wav")
ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or FrogLocation = 7)
Then Sound.Stop(Program.Directory + "\Splash.wav")
Sound.Play(Program.Directory + "\Splash.wav")
EndIf
Shapes.HideShape(Frog) GetNewFrog()
EndSub

When a frog misses a log (no collision), the splash sound is played, the frog
is cleared and a new frog appears.

Save and Run the program. Start the game. Successfully cross the road, then
get past the snake. Now try jumping onto a log. Here’s my screen after my
second jump:

Notice how the frog moves with the log. Check the logic that stops the frog’s
journey if it floats off the side of the window. Make sure you hear a splash.
Try to get a frog onto the home panel – not a real difficult task and you
won’t get a new frog! Right now, you can jump anywhere on the home
panel. Next, we’ll construct a home panel that only has five specific places
the frog can call home.
Code Design – Home Collisions

Currently, the frog can jump off at any location on the home panel. We’ll
make that task a little more difficult by specifying five rectangular ‘home’
regions. If the frog leaves a log and enters one of these regions (there is a
‘total overlap’) the frog is home safe. If he misses home, a splash is heard
and his journey ends. In either case, a new frog appears.

The home panel is 640 pixels wide (just like the other panels) and 80 pixels
high. We will define each home to be a yellow bordered rectangle, 60 pixels
wide by 60 pixels high. By making the homes 60 pixels wide, we give the
frog (40 pixels wide) a little leeway when jumping off a log. These homes
will be uniformly spread across the panel:

Each home is 60 pixels wide and separated by gaps of 50 pixels. The left and
right borders are 70 pixels wide. We make the borders wider to make it a
little easier for the frog to reach these homes. If you’d like, add the width of
five homes, four gaps and two borders to see you indeed get a total width of
640 pixels.

The home panel will be drawn in a subroutine DrawHome. In DrawHome,


each rectangle is defined and drawn as a filled area: Sub DrawHome
PadX[1] = 70
PadX[2] = 180
PadX[3] = 290
PadX[4] = 400
PadX[5] = 510
PadY = HomeTop + 15
PadW = 60
PadH = 60
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
For I = 1 To 5
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(PadX[I], PadY, PadW, PadH)
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
GraphicsWindow.DrawRectangle(PadX[I], PadY, PadW, PadH)
EndFor
EndSub

We’d like the home to show up when the game first starts, so add this single
line in InitializeProgram after the variables HomeTop and HomeHeight
are defined: DrawHome()

The home area should also be cleared and redrawn when a new game begins.
Add the shaded line to the StartPauseButtonClick subroutine: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game") .
.
PositionLogs()
For I = 1 To NumberOfLogs Shapes.ShowShape(Log[I])
LogIsVisible[I] = "true"
EndFor
GetNewFrog()
DrawHome()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
Else
'game restarted
.
.
EndIf
EndSub

Save and Run the program. The home area will be drawn:

Next, we add the logic to see if a frog is home safely.

When a frog jumps to the home panel, he is safe if there is not already a frog
in that home location and if he completely overlaps (we actually use 95
percent) with the home rectangle. In that case, we will play a ‘safe’ sound
and draw a ‘at home’ frog. That frog is represented by the FrogHome.gif
graphic (40 pixels by 40 pixels) found in the KidGamesSB\KidGamesSB

Program\LeapFrog folder:

The home sound is the Home.wav file found in that same folder. Copy these
two files (FrogHome.gif and Home.wav) to your program’s folder.

Add this line to InitializeProgram (with other frog graphics) to load the
FrogHome image: FrogHome = ImageList.LoadImage(Program.Directory +
"\FrogHome.gif") Add the shaded line to the DrawHome subroutine to
initialize the FrogIsHome array (used to show which home locations have a
frog in them) each time the home panel is redrawn: Sub DrawHome
PadX[1] = 70
PadX[2] = 180
PadX[3] = 290
PadX[4] = 400
PadX[5] = 510
PadY = HomeTop + 15
PadW = 60
PadH = 60
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
For I = 1 To 5
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(PadX[I], PadY, PadW, PadH)
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
GraphicsWindow.DrawRectangle(PadX[I], PadY, PadW, PadH)
FrogIsHome[I] = "false"
EndFor
EndSub
We can now add code to the TimerTickSub subroutine to check for
collisions in the home panel. Before doing this, add the two shaded lines to
the DrawFrog subroutine: Sub DrawFrog
If (FrogLocation = 0) Then FrogY = StartTop ElseIf (FrogLocation =
1 Or FrogLocation = 2 Or FrogLocation = 3) Then FrogY = RoadTop
+ 140 ‐ 45 * FrogLocation ElseIf (FrogLocation = 4) Then FrogY =
GrassTop ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or
FrogLocation = 7) Then FrogY = RiverTop + 120 ‐ 40 *
(FrogLocation ‐ 4) ElseIf (FrogLocation = 8) Then FrogY =
HomeTop + 40
EndIf
If (FrogLocation <> 8) Then
Shapes.Move(Frog, FrogX, FrogY) Shapes.ShowShape(Frog)
EndIf
EndSub

We will only draw the frog on the home panel if it reaches home
successfully. That code is added next.

When the frog reaches the home level, we do these checks:

➢ Is frog in home rectangle?


o If so, continue.
o If not, journey ends.
➢ Is there a frog already in home rectangle?
o If so, journey ends.
o If not, place ‘home’ frog in rectangle and play home sound.
➢ Are all frogs home?
o If so, clear the home and continue with a new frog.
o If not, continue with a new frog.

Make the shaded changes to the TimerTickSub subroutine to incorporate


these steps: Sub TimerTickSub
'Road Update
.
.
'River Update
.
.
'snake update
.
.
'general status
'check for collisions
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
.
.
ElseIf (FrogLocation = 4) Then .
.
ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or FrogLocation = 7)
Then .
.
ElseIf (FrogLocation = 8) Then 'moved to home level ‐ see if home
For I = 1 To 5
ShapeX = PadX[I]
ShapeW = PadW
FindOverlap()
If (FrogIsHome[I] = "false" And Overlap > 95) Then
FrogIsHome[I] = "true"
GraphicsWindow.DrawImage(FrogHome, PadX[I] + 10,
PadY + 10) Sound.Stop(Program.Directory +
"\home.wav") Sound.Play(Program.Directory +
"\home.wav") GetNewFrog()
'check if all found
For J = 1 To 5
If (FrogIsHome[J] = "false") Then goto ExitTickSub
EndIf
EndFor
DrawHome()
Goto ExitTickSub
EndIf
EndFor
NoMoreFrog()
EndIf
ExitTickSub:
EndSub

You should see how this code works. If the frog successfully maneuvers to
an empty home, it is drawn there and a sound played. If no overlaps are
found or the selected location is already filled, the frog’s journey ends. If all
homes are filled, they are cleared.

Make shaded changes to the NoMoreFrog subroutine: Sub NoMoreFrog


If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
Sound.Stop(Program.Directory + "\Beep.wav")
Sound.Play(Program.Directory + "\Beep.wav") ElseIf (FrogLocation
= 4) Then Sound.Stop(Program.Directory + "\Snake.wav")
Sound.Play(Program.Directory + "\Snake.wav") ElseIf (FrogLocation
= 5 Or FrogLocation = 6 Or FrogLocation = 7) Then
Sound.Stop(Program.Directory + "\Splash.wav")
Sound.Play(Program.Directory + "\Splash.wav")
ElseIf (FrogLocation = 8) Then Sound.Stop(Program.Directory +
"\Splash.wav") Sound.Play(Program.Directory + "\Splash.wav")
EndIf
Shapes.HideShape(Frog) GetNewFrog()
EndSub

When a frog misses home, the splash sound is played, the frog is cleared and
a new frog appears.
Save and Run the program. Start a game. You now have a completely
functional game. You can traverse the road, elude the snake, cross the river
and get home. Make sure when you get five frogs home (it may be tricky the
first few times you try it) that the home clears and the game continues.
Here’s my screen as I’m trying to get my last frog home:

As programmed, you can play Leap Frog forever. You have unlimited frogs
and the game stays at the same difficulty no matter how long you play. We’ll
change that now. First, we will limit the number of frogs available during a
game. Once your frogs are gone, the game will be over. Second, each time
all the frogs have reached home, we will increase the difficulty of the game
by speeding things up a bit, adding more vehicles and removing logs. This
idea of having increasing levels of difficulty is a fun feature of video games.
And, you may be wondering why we have no scoring? We’ll take care of
that soon.
Code Design – Game Levels

We start Leap Frog at Level 1 (indicated in the title area of the window).
This is the level we have been using (with 7 vehicles and all 12 logs). At this
initial level, you will begin with five available frogs. We will show the
number of frogs (using the FrogUp image) remaining in the upper right of
the window.

Modify the existing line of code in InitializeProgram that sets the window
title to indicate the level and add the line initializing the Level variable:
Level = 1
GraphicsWindow.Title = "Leap Frog ‐ Level 1"

Make the shaded changes to the StartPauseButtonClick event subroutine to


initialize new variables and draw the remaining frogs in the upper corner of
the form: Sub StartPauseButtonClick If (GameStatus = "Stopped") Then
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Level = 1
GraphicsWindow.Title = "Leap Frog ‐ Level 1"
FrogsRemaining = 4
For I = 1 To FrogsRemaining
GraphicsWindow.DrawImage(ImageList.LoadImage(Program.Dir
ectory + "\FrogUp.gif"), GraphicsWindow.Width ‐ I * FrogW ‐ 10,
5) EndFor
.
.
GetNewFrog()
DrawHome()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
Else
.
.
EndSub

This code resets the level (Level) and the number of frogs remaining
(FrogsRemaining). Why did we initialize FrogsRemaining at 4 if we said
there are five initial frogs? The first frog is on the window when we start, so
that frog plus the four remaining gives us five frogs.

Save and Run the program. Click Start Game. Notice the four little frogs in
the upper corner:

Each time a frog’s journey ends (hitting a vehicle or snake, or falling off a
log), we want to eliminate one of the remaining frogs and check to see if the
game has ended (no more frogs). When a game ends, we’ll play a game over
sound. The sound file GameOver.wav is included in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder. Copy this file to
your program’s folder.

Make the shaded changes to the NoMoreFrog subroutine to check on the


number of remaining frogs: Sub NoMoreFrog
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
Sound.Stop(Program.Directory + "\Beep.wav")
Sound.Play(Program.Directory + "\Beep.wav") ElseIf (FrogLocation
= 4) Then Sound.Stop(Program.Directory + "\Snake.wav")
Sound.Play(Program.Directory + "\Snake.wav") ElseIf (FrogLocation
= 5 Or FrogLocation = 6 Or FrogLocation = 7) Then
Sound.Stop(Program.Directory + "\Splash.wav")
Sound.Play(Program.Directory + "\Splash.wav") ElseIf (FrogLocation
= 8) Then Sound.Stop(Program.Directory + "\Splash.wav")
Sound.Play(Program.Directory + "\Splash.wav") EndIf
Shapes.HideShape(Frog)
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(GraphicsWindow.Width ‐
FrogsRemaining * FrogW ‐ 10, 5, FrogW, FrogH) FrogsRemaining =
FrogsRemaining ‐ 1
If FrogsRemaining >= 0 Then
GetNewFrog()
Else
ExitStopButtonClick() EndIf
EndSub

Notice how the location of the frog to delete is determined using


FrogsRemaining.

Make this one shaded change in the ExitStopButtonClick subroutine to


play the game over sound: Sub StopGame
Timer.Pause()
Sound.PlayAndWait(Program.Directory + "\GameOver.wav")
GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Shapes.HideShape(Snake) SnakeIsVisible = "false"
Shapes.HideShape(Frog) EndSub

Save and Run the program. Play recklessly until five frogs have been lost.
Make sure the game ends and the game over sound is heard.

So, now, the game is not endless – you have a limited number of frogs. Next,
we code the logic that increases the difficulty of the game as new levels are
achieved. A new level is achieved when you get five frogs home. At that
point, we’ll play another sound. The sound file NewLevel.wav is included in
the KidGamesSB\KidGamesSB Programs\LeapFrog folder. Copy this file
to your program’s folder.

We will write a new subroutine GoToNextLevel to handle level changes.


For now, just place these few lines in that subroutine: Sub GoToNextLevel
Sound.Stop(Program.Directory + "\NewLevel.wav")
Sound.Play(Program.Directory + "\NewLevel.wav") Level = Level +
1
GraphicsWindow.Title = "Leap Frog ‐ Level " + Level EndSub

Here, we play the new level sound and increment the Level.

The GoToNextLevel subroutine is called from the TimerTickSub


subroutine. Make the shaded change to implement: Sub TimerTickSub
.
.
'general status
'check for collisions
.
.
ElseIf (FrogLocation = 8) Then 'moved to home level ‐ see if home
For I = 1 To 5
ShapeX = PadX[I]
ShapeW = PadW
FindOverlap()
If (FrogIsHome[I] = "false" And Overlap > 95) Then
FrogIsHome[I] = "true"
GraphicsWindow.DrawImage(FrogHome, PadX[I] + 10,
PadY + 10) Sound.Stop(Program.Directory +
"\home.wav") Sound.Play(Program.Directory +
"\home.wav") GetNewFrog()
'check if all found
For J = 1 To 5
If (FrogIsHome[J] = "false") Then goto ExitTickSub
EndIf
EndFor
DrawHome()
GoToNextLevel()
Goto ExitTickSub
EndIf
EndFor
NoMoreFrog()
EndIf
ExitTickSub:
EndSub

Save and Run the program. Get five frogs home and make sure you move to
the next level. When testing the game, you’ll probably get a little tired of
trying to get all five frogs home. Here’s a trick. Look at the code where you
check if all five homes are filled (in TimerTickSub subroutine): For J = 1
To 5
If (FrogIsHome[J] = "false") Then goto ExitTickSub
EndIf
EndFor
Change the first line (temporarily of course) to:

For J = 3 To 3

With this change, you only need to get a frog in the middle home to
complete a level. This makes it much easier to achieve the higher levels to
test your code. Just be sure to change it back to: For J = 1 To 5

when your testing is complete.

We can now move to higher game levels with each group of frogs we get
home safely. With each level, we want the game to change (get more
difficult). Let’s establish those changes. These are just some rules I made up
– feel free to change them as you like. At higher levels, I decided game play
should get faster, vehicles should be added and logs should be removed.
And, to be nice, with every second level, you are given a new frog (up to a
maximum of five). The rules I developed for each level are:

➢ Increase magnitude of vehicle and log speeds by one (applying proper


sign).
➢ If odd number level (>1), add a frog (maximum number of 5).
➢ In Level 2, remove Log[1]
➢ In Level 3, remove Log[7] add Vehicle[1] and Vehicle[5]
➢ In Level 4, remove Log[12], add Vehicle[7] and Vehicle[11]
➢ In Level 5, add Vehicle[4]

So once we reach Level 5, all 12 vehicles are on the road and there 9 logs in
the river. By this level, speeds have increased significantly – things are really
moving. At each level, we also reposition the logs and vehicles to their
original starting positions to avoid the ‘overlap’ problem.

All of the above rules are implemented in the GoToNextLevel subroutine.


The shaded changes are: Sub GoToNextLevel
Sound.Stop(Program.Directory + "\NewLevel.wav")
Sound.Play(Program.Directory + "\NewLevel.wav") Level = Level +
1
GraphicsWindow.Title = "Leap Frog ‐ Level " + Level
'speed things up
For I = 1 To NumberOfVehicles If (VehicleSpeed[I] > 0) Then
VehicleSpeed[I] = VehicleSpeed[I] + 1
Else
VehicleSpeed[I] = VehicleSpeed[I] ‐ 1
EndIf
EndFor
For I = 1 To NumberOfLogs If (LogSpeed[I] > 0) Then LogSpeed[I]
= LogSpeed[I] + 1
Else
LogSpeed[I] = LogSpeed[I] ‐ 1
EndIf
EndFor
'add frog every 2nd level (maximum of 5)
If (Level ‐ 2 * Math.Floor(Level / 2) = 1) Then If FrogsRemaining <
5 Then FrogsRemaining = FrogsRemaining + 1

GraphicsWindow.DrawImage(ImageList.LoadImage(Program.Directory +
"\FrogUp.gif"), GraphicsWindow.Width ‐ FrogsRemaining * FrogW ‐ 10,
5) EndIf
EndIf
'reposition logs, vehicles
PositionLogs()
PositionVehicles()
'delete logs, add vehicles
If (Level = 2) Then Shapes.HideShape(Log[1]) LogIsVisible[1] =
"false"
ElseIf (Level = 3) Then Shapes.HideShape(Log[7]) LogIsVisible[7] =
"false"
Shapes.ShowShape(Vehicle[1]) Shapes.ShowShape(Vehicle[5])
VehicleIsVisible[1] = "true"
VehicleIsVisible[5] = "true"
ElseIf (Level = 4) Then Shapes.HideShape(Log[12])
LogIsVisible[12] = "false"
Shapes.ShowShape(Vehicle[7]) Shapes.ShowShape(Vehicle[11])
VehicleIsVisible[7] = "true"
VehicleIsVisible[11] = "true"
ElseIf (Level = 5) Then Shapes.ShowShape(Vehicle[4])
VehicleIsVisible[4] = "true"
EndIf
EndSub

We need to make a couple more changes. In the subroutines


PositionVehicles and PositionLogs, we set the speeds to initial (Level 1)
values. In this new subroutine (GoToNextLevel), these speeds are changed.
We need to make sure these modified speeds are not affected by recalling
PositionVehicles and PositionLogs to reset the vehicle and log positions.
The change is simple – add the shaded code to PositionVehicles and
PositionLogs to make sure speeds are initialized only when Level = 1: Sub
PositionVehicles
DrawRoad()
'top row
.
.
'speeds
If (Level = 1) Then
VehicleSpeed[1] = 3
VehicleSpeed[2] = 3
VehicleSpeed[3] = 3
VehicleSpeed[4] = 3
VehicleSpeed[5] = ‐3
VehicleSpeed[6] = ‐3
VehicleSpeed[7] = ‐3
VehicleSpeed[8] = ‐3
VehicleSpeed[9] = ‐2
VehicleSpeed[10] = ‐2
VehicleSpeed[11] = ‐2
VehicleSpeed[12] = ‐2
EndIf
For I = 1 to NumberOfVehicles Shapes.Move(Vehicle[I], VehicleX[I],
VehicleY[I]) EndFor
EndSub
Sub PositionLogs
GraphicsWindow.BrushColor =
GraphicsWindow.GetColorFromRGB(128, 128, 255)
GraphicsWindow.FillRectangle(0, RiverTop, GraphicsWindow.Width,
RiverHeight) 'top row
.
.
'speeds
If (Level = 1) Then
LogSpeed[1] = 5
LogSpeed[2] = 5
LogSpeed[3] = 5
LogSpeed[4] = 5
LogSpeed[5] = 5
LogSpeed[6] = ‐3
LogSpeed[7] = ‐3
LogSpeed[8] = ‐3
LogSpeed[9] = ‐3
LogSpeed[10] = 2
LogSpeed[11] = 2
LogSpeed[12] = 2
EndIf
For I = 1 to NumberOfLogs Shapes.Move(Log[I], LogX[I], LogY[I])
EndFor
EndSub
Save and Run the program. Notice how the game changes as you move to
higher levels. Just how high can you go? Here’s my screen at Level 5 (I got
there using the little cheat mentioned earlier):

Notice all the vehicles and the minimal number of logs.

In addition to achieving high levels in games, players like to achieve high


scores and see how they compare against other players. Let’s add some
scoring to Leap Frog.
Code Design - Scoring

Any time anyone plays a game, they like to know their score. And, they like
to see if they do better than others. Let’s add that capability to the Leap
Frog game. Like other rules used in this game, the scoring rules are
somewhat arbitrary – feel free to change them as you want.

We will use Score to track the current game score and HighScore to track
the highest score achieved. These values will be displayed at the top of the
game window.

Add these lines in InitializeProgram (after call to DrawHome) to initialize


the score variables and display them in Shapes (DisplayScore and
DisplayHighScore) on white rectangles: 'scoring
Score = 0
HighScore = 0
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
GraphicsWindow.DrawText(5, 5, "Score")
GraphicsWindow.DrawText(175, 5, "High Score")
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(65, 5, 90, 25)
GraphicsWindow.FillRectangle(280, 5, 90, 25)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
DisplayScore = Shapes.AddText(Score) Shapes.Move(DisplayScore, 80,
5) DisplayHighScore = Shapes.AddText(HighScore)
Shapes.Move(DisplayHighScore, 295, 5) UpdateScore()

One new subroutine is needed (UpdateScore): Sub UpdateScore


Shapes.SetText(DisplayScore, Score) If (Score > HighScore) Then
HighScore = Score Shapes.SetText(DisplayHighScore, HighScore)
EndIf
EndSub

Notice how the high score display is updated as needed.

We also want to insure the Score is reset to zero when starting a new game.
Add the shaded lines to the StartPauseButtonClick event subroutine to
reset the score with each new game: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Score = 0
UpdateScore()
Level = 1
GraphicsWindow.Title = "Leap Frog ‐ Level 1"
.
.
ElseIf (GameStatus = "Playing") Then .
.
Else
.
.
EndIf
EndSub

Add the shaded line to the StopGame subroutine to update the score when a
game stops. This line is needed in case the game stops before a score update
occurs: Sub StopGame
Timer.Pause() Sound.PlayAndWait(Program.Directory +
"\GameOver.wav") GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Shapes.HideShape(Snake) SnakeIsVisible = "false"
Shapes.HideShape(Frog)
UpdateScore()
EndSub

Save and Run the program. The initialized scores will appear at the top of
the window.

Now let’s establish and implement some rules for scoring.

The scoring rules I use are:

➢ Each successful upward jump – 100 points ➢ Each successful


downward jump – 50 points ➢ Each successful left or right jump – 1
points ➢ Each successful frog home – 200 points ➢ Each new level
achieved – 1000 points
Make the shaded changes to the KeyDownSub subroutine to add scoring for
jumps: Sub KeyDownSub
KD = GraphicsWindow.LastKey If (GameStatus = "Playing") Then
'Clear from current location
Shapes.HideShape(Frog) If (KD = "Up") Then
Score = Score + 100
OnLog = 0
.
.
ElseIf (KD = "Left") Then
Score = Score + 1
OnLog = 0
.
.
ElseIf (KD = "Down") Then
Score = Score + 50
OnLog = 0
.
.
ElseIf (KD = "Right") Then
Score = Score + 1
OnLog = 0
.
.
EndIf
'put in new location
DrawFrog()
EndIf
EndSub

The scores for getting a frog home safely and completing a level, as well as
updating the scores, is done in the TimerTickSub subroutine. Make the
shaded changes: Sub TimerTickSub
UpdateScore()
.
.
ElseIf (FrogLocation = 8) Then 'moved to home level ‐ see if home
For I = 1 To 5
ShapeX = PadX[I]
ShapeW = PadW
FindOverlap()
If (FrogIsHome[I] = "false" And Overlap > 95) Then
Score = Score + 200
FrogIsHome[I] = "true"
GraphicsWindow.DrawImage(FrogHome, PadX[I] + 10,
PadY + 10) ' Sound.Stop(Program.Directory +
"\home.wav")
'Sound.Play(Program.Directory + "\home.wav")
GetNewFrog()
'check if all found
For J = 3 To 3
If (FrogIsHome[J] = "false") Then goto ExitTickSub
EndIf
EndFor
DrawHome()
Score = Score + 1000
GoToNextLevel()
Goto ExitTickSub
EndIf
EndFor
NoMoreFrog()
EndIf
ExitTickSub:
EndSub

Save and Run the program. You now have scoring. Here’s a game I played
into the third level (without using my cheat):

I have the highest score, since this the only game I’ve played.

We’re nearly finished with Leap Frog. Have you noticed the High Scores
button at the bottom of the window? We’ve kind of ignored that button.
We’ll use it now. One last thing players like to see is how well they compare
to those who have played the game before. As programmed, only one high
score is saved – the highest score since the program was started. It would be
nice to be able to save high scores for future players to see. We do that next,
saving and displaying the 10 highest scores ever achieved. If a player
reaches the Top 10, he/she can add his/her name to this illustrious list. We
will add a text window to our program that displays the high scores. Then,
we will discuss how to write and read text files using Small Basic. This will
let us save and recall the high scores.
Window Design – High Scores

We will use a text window to display the sales results. Like the graphics
window, it helps to first make a sketch of the desired layout. Here is the
sketch for the High Scores window:

We will have room for the top ten scores. For each, we list a player’s name
and the corresponding score. For new high scores, we will allow the user to
type his/her name so it can be added to the list.
Code Design – Displaying High Scores

We want to write code for the High Scores button. First, make the shaded
changes to the StartPauseButtonClick and StopGame subroutines to
show/hide this button at proper times: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(HighScoresButton)
.
.
ElseIf (GameStatus = "Playing") Then .
.
Else
.
.
EndIf
EndSub

Sub StopGame
Timer.Pause() Sound.PlayAndWait(Program.Directory +
"\GameOver.wav") GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.Showcontrol(HighScoresButton)
Shapes.HideShape(Snake) SnakeIsVisible = "false"
Shapes.HideShape(Frog) UpdateScore()
EndSub

When a player clicks the High Scores button, we want that window to
display. Add this code to the HighScoresButtonClick event: Sub
HighScoresButtonClick GraphicsWindow.Hide() TextWindow.Show()
TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Title = "Leap Frog High Scores"
TextWindow.Clear() TextWindow.Pause() TextWindow.Hide()
GraphicsWindow.Show() EndSub

Save and run the program. Click High Scores and you will see the almost
blank window:

There are no scores yet. Let’s develop the code to add scores, save them and
re-display them. First, we look at saving information displayed on the High
Scores window.
Code Design – Saving High Scores

When we close the High Scores window, we want to save player names and
their high scores in a file. To do this, we look at how to write values of
variables to files. We use the Small Basic File object. To write a variable
named Variable to line N in a file MyFile.txt (in your program’s folder), use
the WriteLine method: File.WriteLine(Program.Directory + "\MyFile.txt",
Variable, N) This statement will write the variable on a single line in the file.
In the Leap Frog game, the file we use will have 20 lines. The first two lines
will be the name and score for the highest score, the next two lines the name
and score for the second highest score, and so on for all 10 pairs of names
and scores.

We will use two arrays to store player names and scores: PlayerName will
hold the names, while PlayerScore will hold the score. Initialize these
arrays near the end of InitializeProgram using: For I = 1 To 10
PlayerName[I] = ""
PlayerScore[I] = 0
EndFor

Use the shaded code in the HighScoresButtonClick subroutine to display


names and scores and then, when the window is closed, save the displayed
values to a file named HighScores.txt, located in your program’s folder. The
scores will be saved in descending order, highest to lowest. Once saved, the
window is closed and control is returned to the Leap Frog game: Sub
HighScoresButtonClick GraphicsWindow.Hide() TextWindow.Show()
TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Title = "Leap Frog High Scores"
TextWindow.Clear()
TextWindow.CursorTop = 1
TextWindow.WriteLine(" NAME SCORE") TextWindow.WriteLine("
‐‐‐‐ ‐‐‐‐‐") For I = 1 To 10
TextWindow.CursorTop = I + 2
TextWindow.CursorLeft = 4 ‐ Text.GetLength(I)
TextWindow.Write(I) TextWindow.CursorLeft = 5
TextWindow.Write(PlayerName[I]) TextWindow.CursorLeft = 30 ‐
Text.GetLength(PlayerScore[I])
TextWindow.WriteLine(PlayerScore[I]) EndFor
TextWindow.WriteLine("") TextWindow.WriteLine("")
TextWindow.Pause()
'write scores to file
For I = 1 To 10
File.WriteLine(Program.Directory + "\HighScores.txt", 2 * I ‐ 1,
PlayerName[I]) File.WriteLine(Program.Directory +
"\HighScores.txt", 2 * I, PlayerScore[I]) EndFor
TextWindow.Hide() GraphicsWindow.Show() EndSub

Notice how we position the player names and scores at known locations
(using CursorTop and CursorLeft). This will allow easier editing later.
And, note how the 20 lines in the HighScores.txt file are generated in the
file (odd numbered lines have names, even numbered lines have scores.

Save and Run the program. Click High Scores. The window will appear
with the initial high scores information:

As directed, press any key to close the window. Make sure control returns to
the Leap Frog game. Stop the game. Go to your program’s folder. Open the
file named HighScores.txt. It should have blank lines for each name and
zeroes for each score:

When the High Scores window is opened, we now want it to re-open


HighScores.txt and display any information located in the file. We just saw
the file we created is blank, so it wouldn’t be very interesting to open this
file again. Included with the Leap Frog program (in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder) is a sample
HighScores.txt file to test the program. You can open the file and look at it
to see the entries. Copy this file to your program’s folder. Now, let’s write
the code to open this file.
Code Design – Reading High Scores

To read variables (the high score information here) from a file, we


essentially reverse the write procedure. To read Variable from line N of
MyFile.txt (located in your program’s folder), use the ReadLine method:
Variable = File.ReadLine(Program.Directory + "\MyFile.txt", N) We want to
read in the high scores file (highscores.txt) when the high scores winod is
opened. Add the shaded code to the HighScoresButtonClick subroutine:
Sub HighScoresButtonClick GraphicsWindow.Hide() TextWindow.Show()
TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Title = "Leap Frog High Scores"
TextWindow.Clear()
'read scores from file
For I = 1 To 10
PlayerName[I] = File.ReadLine(Program.Directory +
"\HighScores.txt", 2 * I ‐ 1) PlayerScore[I] =
File.ReadLine(Program.Directory + "\HighScores.txt", 2 * I)
EndFor
.
.
EndSub

In this code, we read each player/score combination from the data file.

Save and Run the program. Click High Scores. If you copied the sample
HighScores.txt file into your program’s folder, you will see something like
this (some of the entries may have changed since these notes were written):

So, we can save and display the high scores file. But, how do we get entries
into the file? We need logic to see if an achieved score in the Leap Frog
game is high enough to be displayed in the Top 10 list. If it is, we need logic
to add it to the list. Let’s write that code.
Code Design – Adding to High Scores

When a Leap Frog game ends, we need to look at the achieved score and
see if it fits into the Top 10 scores list. To do this, we check if the score is
higher than the lowest score in the list. If so, it needs to be added to the list.
So a first task is to determine the minimum score (LowScore) a player
would have to achieve to enter the Top 10. This score is found by opening
HighScores.txt and finding the lowest value. We do this when first starting
the program.

Add the shaded code in InitializeProgram with other scoring code. Make
sure you put these lines (as shown) before the code displaying the scores.
This code opens HighScores.txt and finds the highest score (HighScore)
and lowest score (LowScore). The high score is displayed in the High Score
area:

'second line has high score


HighScore = File.ReadLine(Program.Directory +
"\HighScores.txt", 2) 'last line has lowest score
LowScore = File.ReadLine(Program.Directory + "\HighScores.txt", 20)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
DisplayScore = Shapes.AddText(Score) Shapes.Move(DisplayScore, 80,
5) DisplayHighScore = Shapes.AddText(HighScore)
Shapes.Move(DisplayHighScore, 295, 5) UpdateScore()

Run and Save the program. The high score (again, you may see a different
value) in the sample file will appear:
Finally, we need logic to check the score at the end of a game and see if it
belongs in the Top 10. We will use a variable (NewScore) to indicate if a
new Top 10 score has been achieved. When a new Top 10 score is achieved,
we will play a ‘tada’ sound. The sound file tada.wav is included in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder. Copy this file to
your program’s folder.

Add the shaded code to the StopGame subroutine to check the score against
LowScore: Sub StopGame
Timer.Pause() Sound.PlayAndWait(Program.Directory +
"\GameOver.wav") GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.Showcontrol(HighScoresButton) Shapes.HideShape(Snake)
SnakeIsVisible = "false"
Shapes.HideShape(Frog) UpdateScore()
'check if in top 10 scores
If (Score > LowScore) Then Sound.Stop(Program.Directory +
"\tada.wav") Sound.Play(Program.Directory + "\tada.wav") NewScore
= "true"
HighScoresButtonClick() EndIf
EndSub

If a new score is achieved, the sound is played. And, NewScore is set to


“true”. This variable will be used in the high scores window to indicate a
new score is to be added to the list. Lastly, the high scores window is
displayed by calling the HighScoresButtonClick subroutine.

Save and Run the program. Play until you achieve a fairly high score. Stop
the game. You should hear a ‘tada’ and the high scores window will appear.
You know you achieved a high score, but there is no way to enter your name
and score. Let’s fix that.

When the high scores window is opened, if NewScore is “true”, the current
score is to be entered into the Top 10 list. Once we know this, our coding job
is to determine where it fits in the list, enter the score in the appropriate
position and clear the area next for the corresponding player name to allow
the player to type his/her name.

The code to determine this position goes in the HighScoresButtonClick


subroutine. The changes are shaded: Sub HighScoresButtonClick
GraphicsWindow.Hide() TextWindow.Show()
TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Title = "Leap Frog High Scores"
TextWindow.Clear() 'read scores from file
For I = 1 To 10
PlayerName[I] = File.ReadLine(Program.Directory +
"\HighScores.txt", 2 * I ‐ 1) PlayerScore[I] =
File.ReadLine(Program.Directory + "\HighScores.txt", 2 * I)
EndFor
TextWindow.CursorTop = 1
TextWindow.WriteLine(" NAME SCORE") TextWindow.WriteLine("
‐‐‐‐ ‐‐‐‐‐") For I = 1 To 10
TextWindow.CursorTop = I + 2
TextWindow.CursorLeft = 4 ‐ Text.GetLength(I)
TextWindow.Write(I) TextWindow.CursorLeft = 5
TextWindow.Write(PlayerName[I]) TextWindow.CursorLeft = 30 ‐
Text.GetLength(PlayerScore[I])
TextWindow.WriteLine(PlayerScore[I]) EndFor
TextWindow.WriteLine("") TextWindow.WriteLine("")
If (NewScore) Then TextWindow.WriteLine(" Congratulations ‐ your
score puts you in the Top 10 High Scores!") TextWindow.WriteLine("
Type your name and press Enter to be recorded in history!") 'find
where current score fits in list
For I = 1 To 10
If (Score > PlayerScore[I]) Then Goto GotPosition
EndIf
EndFor
GotPosition:
NewScorePosition = I 'move all below NewScorePosition down
one position
If (NewScorePosition <> 10) Then For I = 10 To
NewScorePosition + 1 Step ‐1
PlayerName[I] = PlayerName[I ‐ 1]
PlayerScore[I] = PlayerScore[I ‐ 1]
'blank out name and score before rewriting
TextWindow.CursorTop = I + 2
TextWindow.CursorLeft = 5
TextWindow.Write(" ") TextWindow.CursorLeft = 5
TextWindow.Write(PlayerName[I])
TextWindow.CursorLeft = 25
TextWindow.Write(" ") TextWindow.CursorLeft = 30 ‐
Text.GetLength(PlayerScore[I])
TextWindow.WriteLine(PlayerScore[I]) EndFor
EndIf
'add new score ‐ get input at NewScorePosition
'blank out line before rewriting
PlayerScore[NewScorePosition] = Score TextWindow.CursorTop
= NewScorePosition + 2
TextWindow.CursorLeft = 25
TextWindow.Write(" ") TextWindow.CursorLeft = 30 ‐
Text.GetLength(PlayerScore[NewScorePosition])
TextWindow.Write(PlayerScore[I]) TextWindow.CursorLeft = 5
TextWindow.Write(" ") TextWindow.CursorLeft = 5
PlayerName[I] = TextWindow.Read() 'reset LowScore variable
LowScore = PlayerScore[10]
NewScore = "false"
EndIf
TextWindow.CursorTop = 22
TextWindow.CursorLeft = 3
TextWindow.Pause() 'write scores to file
For I = 1 To 10
File.WriteLine(Program.Directory + "\HighScores.txt", 2 * I ‐ 1,
PlayerName[I]) File.WriteLine(Program.Directory +
"\HighScores.txt", 2 * I, PlayerScore[I]) EndFor
TextWindow.Hide() GraphicsWindow.Show() EndSub

This is a lot of new code, but straightforward. A congratulatory message is


printed. We go through the Top 10 list seeing where the current game score
(Score) fits in the list (NewScorePosition). All scores below
NewScorePosition are moved down one position. Then the area for the
player name is cleared for input (using Read method). We also reset the
LowScore variable to the new last entry in the list (PlayerScore[10]) and
reset NewScore to “false”.

Save and Run the program again. Get a fairly high score and stop. You
should hear a ‘tada’, see the congratulatory message and given the
opportunity to type your name. Go ahead – add your name to history:

Would you believe the Leap Frog game is at long last complete? It’s been a
long journey, but well worth it. Before concluding, one word about the high
scores file. Notice we have not given you a way to easily delete high scores.
There is no Delete button on the form. The only way to do it is to delete the
HighScores.txt file from your program’s folder. This is by design. We have
found that if high scores are easily deleted, quite often friends or siblings
will wipe out another’s hard earned scores so they can get their own scores
entered. We didn’t want this to be an easy task. So, to start fresh with a new
high scores file, you will want to delete the sample file from your directory
before playing your game of Leap Frog.
A Possible Problem

As implemented, sometimes when the program is run, you may see an error
message like this:

This message is related to the playing of sounds within the TimerTickSub


subroutine.

A simple explanation is that there is a lot of computation going on in the


TimerTickSub subroutine and it has just 100 milliseconds (0.1 seconds) to
complete the tasks. Occasionally, especially when sounds are involved, it
cannot perform all tasks in the allotted 0.1 seconds. In such a case, the
current execution of the subroutine is halted and a new execution from the
beginning is started - a new “thread” (the word that appears in the error
message) begins. At that point, it has sounds playing and tries to start other
sounds, confusing the Small Basic language. All it can do is stop.

So, what can we do? I am assuming this is a problem that will be fixed in
later versions of Small Basic. We are currently working with Beta versions
and errors do exit. For now, the only solution I have is to comment out the
lines of code that stop/play sounds. I have found you can leave the hop
sounds in, but all others should not be played for now. You decide which
sounds you want.
Leap Frog Game Program Listing

Here is the complete listing of the Leap Frog Small Basic program: ' Leap
Frog
InitializeProgram()

Sub InitializeProgram 'graphics window


GraphicsWindow.Width = 640
GraphicsWindow.Height = 510
Level = 1
GraphicsWindow.Title = "Leap Frog ‐ Level 1"
GraphicsWindow.BackgroundColor = "DarkGreen"
GameStatus = "Stopped"
'define buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
StartPauseButton = Controls.AddButton("Start Game", 120, 475)
Controls.SetSize(StartPauseButton, 120, 31) ExitStopButton =
Controls.AddButton("Exit", 260, 475) Controls.SetSize(ExitStopButton,
120, 31) HighScoresButton = Controls.AddButton("High Scores", 400,
475) Controls.SetSize(HighScoresButton, 120, 31)
Controls.ButtonClicked = ButtonClickedSub 'Vehicles on road
RoadTop = 290
RoadHeight = 140
DrawRoad()
NumberOfVehicles = 12
Vehicle[1] = Shapes.AddImage(ImageList.LoadImage(Program.Directory
+ "\RightSemi.gif")) Vehicle[2] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightTruck.gif")) Vehicle[3] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightCar.gif")) Vehicle[4] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightCar.gif")) Vehicle[5] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[6] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[7] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[8] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[9] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[10] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftSemi.gif")) Vehicle[11] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[12] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) For I = 1 to 12
Shapes.HideShape(Vehicle[I]) VehicleIsVisible[I] = "false"
EndFor
'logs in river
RiverTop = 130
RiverHeight = 120
GraphicsWindow.BrushColor =
GraphicsWindow.GetColorFromRGB(128, 128, 255)
GraphicsWindow.FillRectangle(0, RiverTop, GraphicsWindow.Width,
RiverHeight) NumberOfLogs = 12
Log[1] = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[2] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[3] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\SmallLog.gif")) Log[4] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[5] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[6] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\SmallLog.gif")) Log[7] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[8] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[9] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[10] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[11] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[12] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) For I = 1 to 12
Shapes.HideShape(Log[I]) LogIsVisible[I] = "false"
EndFor
'Snake
GrassTop = 250
GrassHeight = 40
Snake1 = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\Snake1.gif")) Snake2 =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\Snake2.gif")) Snake = Snake1
SnakeSpeed = 5
SnakeX = 0
SnakeY = GrassTop + 7
SnakeW = 111
SnakeH = 24
Shapes.HideShape(Snake1) Shapes.HideShape(Snake2) SnakeIsVisible =
"false"
'Frogs
FrogUp = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogUp.gif")) FrogDown =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogDown.gif")) FrogLeft =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogLeft.gif")) FrogRight =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogRight.gif")) FrogHome = ImageList.LoadImage(Program.Directory
+ "\FrogHome.gif") Shapes.HideShape(FrogUp)
Shapes.HideShape(FrogDown) Shapes.HideShape(FrogLeft)
Shapes.HideShape(FrogRight) FrogW = 40
FrogH = 40
StartTop = 430
StartHeight = 40
HomeTop = 50
HomeHeight = 80
DrawHome()
'scoring
Score = 0
HighScore = 0
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
GraphicsWindow.DrawText(5, 5, "Score")
GraphicsWindow.DrawText(175, 5, "High Score")
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(65, 5, 90, 25)
GraphicsWindow.FillRectangle(280, 5, 90, 25) 'second line has high score
HighScore = File.ReadLine(Program.Directory + "\HighScores.txt", 2)
'last line has lowest score
LowScore = File.ReadLine(Program.Directory + "\HighScores.txt", 20)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
DisplayScore = Shapes.AddText(Score) Shapes.Move(DisplayScore, 80,
5) DisplayHighScore = Shapes.AddText(HighScore)
Shapes.Move(DisplayHighScore, 295, 5) UpdateScore()
For I = 1 To 10
PlayerName[I] = ""
PlayerScore[I] = 0
EndFor
Timer.Interval = 100
Timer.Tick = TimerTickSub Timer.Pause() GraphicsWindow.KeyDown =
KeyDownSub EndSub

Sub ButtonClickedSub
B = Controls.LastClickedButton If (B = StartPauseButton) Then ' start,
stop, pause button
StartPauseButtonClick() ElseIf (B = ExitStopButton) Then 'exit, stop
button
ExitStopButtonClick() ElseIf (B = HighScoresButton) Then 'high
scores button
HighScoresButtonClick() EndIf
EndSub

Sub StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus


= "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(HighScoresButton) Score = 0
UpdateScore()
Level = 1
GraphicsWindow.Title = "Leap Frog ‐ Level 1"
FrogsRemaining = 4
For I = 1 To FrogsRemaining
GraphicsWindow.DrawImage(ImageList.LoadImage(Program.Directo
ry + "\FrogUp.gif"), GraphicsWindow.Width ‐ I * FrogW ‐ 10, 5)
EndFor
PositionVehicles()
For I = 1 To NumberOfVehicles Shapes.ShowShape(Vehicle[I])
VehicleIsVisible[I] = "true"
EndFor
'clear vehicles for level 1
Shapes.HideShape(Vehicle[1]) VehicleIsVisible[1] = "false"
Shapes.HideShape(Vehicle[4]) VehicleIsVisible[4] = "false"
Shapes.HideShape(Vehicle[5]) VehicleIsVisible[5] = "false"
Shapes.HideShape(Vehicle[7]) VehicleIsVisible[7] = "false"
Shapes.HideShape(Vehicle[11]) VehicleIsVisible[11] = "false"
PositionLogs()
For I = 1 To NumberOfLogs Shapes.ShowShape(Log[I])
LogIsVisible[I] = "true"
EndFor
GetNewFrog()
DrawHome()
Timer.Resume() ElseIf (GameStatus = "Playing") Then Timer.Pause()
GameStatus = "Paused"
Controls.SetButtonCaption(StartPauseButton, "Restart Game")
Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) Timer.Resume() EndIf
EndSub

Sub ExitStopButtonClick If (GameStatus = "Playing") Then StopGame()


Else
Program.End() EndIf
EndSub

Sub StopGame
Timer.Pause() Sound.PlayAndWait(Program.Directory +
"\GameOver.wav") GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.Showcontrol(HighScoresButton) Shapes.HideShape(Snake)
SnakeIsVisible = "false"
Shapes.HideShape(Frog) UpdateScore()
'check if in top 10 scores
If (Score > LowScore) Then Sound.Stop(Program.Directory +
"\tada.wav") Sound.Play(Program.Directory + "\tada.wav") NewScore =
"true"
HighScoresButtonClick() EndIf
EndSub

Sub HighScoresButtonClick GraphicsWindow.Hide() TextWindow.Show()


TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Title = "Leap Frog High Scores"
TextWindow.Clear() 'read scores from file
For I = 1 To 10
PlayerName[I] = File.ReadLine(Program.Directory +
"\HighScores.txt", 2 * I ‐ 1) PlayerScore[I] =
File.ReadLine(Program.Directory + "\HighScores.txt", 2 * I) EndFor
TextWindow.CursorTop = 1
TextWindow.WriteLine(" NAME SCORE") TextWindow.WriteLine(" ‐‐‐‐
‐‐‐‐‐") For I = 1 To 10
TextWindow.CursorTop = I + 2
TextWindow.CursorLeft = 4 ‐ Text.GetLength(I) TextWindow.Write(I)
TextWindow.CursorLeft = 5
TextWindow.Write(PlayerName[I]) TextWindow.CursorLeft = 30 ‐
Text.GetLength(PlayerScore[I])
TextWindow.WriteLine(PlayerScore[I]) EndFor
TextWindow.WriteLine("") TextWindow.WriteLine("") If (NewScore)
Then TextWindow.WriteLine(" Congratulations ‐ your score puts you in
the Top 10 High Scores!") TextWindow.WriteLine(" Type your name and
press Enter to be recorded in history!") 'find where current score fits in list
For I = 1 To 10
If (Score > PlayerScore[I]) Then Goto GotPosition
EndIf
EndFor
GotPosition:
NewScorePosition = I 'move all below NewScorePosition down one
position
If (NewScorePosition <> 10) Then For I = 10 To NewScorePosition
+ 1 Step ‐1
PlayerName[I] = PlayerName[I ‐ 1]
PlayerScore[I] = PlayerScore[I ‐ 1]
'blank out name and score before rewriting
TextWindow.CursorTop = I + 2
TextWindow.CursorLeft = 5
TextWindow.Write(" ") TextWindow.CursorLeft = 5
TextWindow.Write(PlayerName[I]) TextWindow.CursorLeft =
25
TextWindow.Write(" ") TextWindow.CursorLeft = 30 ‐
Text.GetLength(PlayerScore[I])
TextWindow.WriteLine(PlayerScore[I]) EndFor
EndIf
'add new score ‐ get input at NewScorePosition
'blank out line before rewriting
PlayerScore[NewScorePosition] = Score TextWindow.CursorTop =
NewScorePosition + 2
TextWindow.CursorLeft = 25
TextWindow.Write(" ") TextWindow.CursorLeft = 30 ‐
Text.GetLength(PlayerScore[NewScorePosition])
TextWindow.Write(PlayerScore[I]) TextWindow.CursorLeft = 5
TextWindow.Write(" ") TextWindow.CursorLeft = 5
PlayerName[I] = TextWindow.Read() 'reset LowScore variable
LowScore = PlayerScore[10]
NewScore = "false"
EndIf
TextWindow.CursorTop = 22
TextWindow.CursorLeft = 3
TextWindow.Pause() 'write scores to file
For I = 1 To 10
File.WriteLine(Program.Directory + "\HighScores.txt", 2 * I ‐ 1,
PlayerName[I]) File.WriteLine(Program.Directory +
"\HighScores.txt", 2 * I, PlayerScore[I]) EndFor
TextWindow.Hide() GraphicsWindow.Show() EndSub

Sub PositionVehicles DrawRoad() 'top row


VehicleX[1] = 20
VehicleY[1] = RoadTop + 5
VehicleW[1] = 120
VehicleH[1] = 40
VehicleX[2] = 200
VehicleY[2] = RoadTop + 5
VehicleW[2] = 80
VehicleH[2] = 40
VehicleX[3] = 380
VehicleY[3] = RoadTop + 5
VehicleW[3] = 40
VehicleH[3] = 40
VehicleX[4] = 540
VehicleY[4] = RoadTop + 5
VehicleW[4] = 40
VehicleH[4] = 40
'middle row
VehicleX[5] = 40
VehicleY[5] = RoadTop + 50
VehicleW[5] = 80
VehicleH[5] = 40
VehicleX[6] = 220
VehicleY[6] = RoadTop + 50
VehicleW[6] = 40
VehicleH[6] = 40
VehicleX[7] = 360
VehicleY[7] = RoadTop + 50
VehicleW[7] = 80
VehicleH[7] = 40
VehicleX[8] = 520
VehicleY[8] = RoadTop + 50
VehicleW[8] = 80
VehicleH[8] = 40
'bottom row
VehicleX[9] = 60
VehicleY[9] = RoadTop + 95
VehicleW[9] = 40
VehicleH[9] = 40
VehicleX[10] = 180
VehicleY[10] = RoadTop + 95
VehicleW[10] = 120
VehicleH[10] = 40
VehicleX[11] = 380
VehicleY[11] = RoadTop + 95
VehicleW[11] = 40
VehicleH[11] = 40
VehicleX[12] = 520
VehicleY[12] = RoadTop + 95
VehicleW[12] = 80
VehicleH[12] = 40
'speeds
If (Level = 1) Then VehicleSpeed[1] = 3
VehicleSpeed[2] = 3
VehicleSpeed[3] = 3
VehicleSpeed[4] = 3
VehicleSpeed[5] = ‐3
VehicleSpeed[6] = ‐3
VehicleSpeed[7] = ‐3
VehicleSpeed[8] = ‐3
VehicleSpeed[9] = ‐2
VehicleSpeed[10] = ‐2
VehicleSpeed[11] = ‐2
VehicleSpeed[12] = ‐2
EndIf
For I = 1 to NumberOfVehicles Shapes.Move(Vehicle[I], VehicleX[I],
VehicleY[I]) EndFor
EndSub

Sub DrawRoad
GraphicsWindow.BrushColor = "DimGray"
GraphicsWindow.FillRectangle(0, RoadTop, GraphicsWindow.Width,
RoadHeight) 'draw road lines
GraphicsWindow.PenColor = "White"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawLine(0, RoadTop + 2, GraphicsWindow.Width,
RoadTop + 2) GraphicsWindow.DrawLine(0, RoadTop + RoadHeight ‐ 2,
GraphicsWindow.Width, RoadTop + RoadHeight ‐ 2)
GraphicsWindow.DrawLine(0, RoadTop + 92, GraphicsWindow.Width,
RoadTop + 92) GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.DrawLine(0, RoadTop + 47, GraphicsWindow.Width,
RoadTop + 47) GraphicsWindow.DrawLine(0, RoadTop + 49,
GraphicsWindow.Width, RoadTop + 49) EndSub
Sub TimerTickSub
UpdateScore()
'Road Update
For I = 1 To NumberOfVehicles If VehicleIsVisible[I] Then VehicleX[I]
= VehicleX[I] + VehicleSpeed[I]
Shapes.Move(Vehicle[I], VehicleX[I], VehicleY[I]) If (VehicleX[I]
> GraphicsWindow.Width And VehicleSpeed[I] > 0) Then
VehicleX[I] = ‐120
EndIf
If (VehicleX[I] < ‐VehicleW[I] And VehicleSpeed[I] < 0) Then
VehicleX[I] = GraphicsWindow.Width + (120 ‐ VehicleW[I])
EndIf
EndIf
EndFor
'River Update
For I = 1 To NumberOfLogs If (LogIsVisible[I]) Then LogX[I] =
LogX[I] + LogSpeed[I]
Shapes.Move(Log[I], LogX[I], LogY[I]) If OnLog = I Then
FrogX = FrogX + LogSpeed[I]
If (FrogX < 0 Or FrogX > GraphicsWindow.Width ‐ FrogW)
Then NoMoreFrog()
Goto ExitTickSub
EndIf
Shapes.Move(Frog, FrogX, FrogY) EndIf
If (LogX[I] > GraphicsWindow.Width And LogSpeed[I] > 0)
Then LogX[I] = ‐120
EndIf
If (LogX[I] < ‐LogW[I] And LogSpeed[I] < 0) Then LogX[I] =
GraphicsWindow.Width + (120 ‐ LogW[I]) EndIf
EndIf
EndFor
'snake update
If (SnakeIsVisible = "false") Then If (Math.GetRandomNumber(50)) = 1
Then SnakeX = ‐SnakeW
Snake = Snake1
Shapes.Move(Snake, SnakeX, SnakeY)
Shapes.ShowShape(Snake) SnakeIsVisible = "true"
EndIf
Else
Shapes.HideShape(Snake) If Snake = Snake1 Then Snake = Snake2
Else
Snake = Snake1
EndIf
SnakeX = SnakeX + SnakeSpeed Shapes.Move(Snake, SnakeX,
SnakeY) Shapes.ShowShape(Snake) If (SnakeX >
GraphicsWindow.Width) Then Shapes.HideShape(Snake)
SnakeIsVisible = "false"
EndIf
EndIf
'general status
'check for collisions
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
'vehicles in FrogLocation row
IFrog = 9 ‐ 4 * (FrogLocation ‐ 1) For I = IFrog To IFrog + 3
If (VehicleIsVisible[I]) Then ShapeX = VehicleX[I]
ShapeW = VehicleW[I]
FindOverlap()
If (Overlap > 10) Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
EndFor
ElseIf (FrogLocation = 4) Then 'snake
If (SnakeIsVisible) Then ShapeX = SnakeX
ShapeW = SnakeW
FindOverlap()
If (Overlap > 1) Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or FrogLocation = 7)
Then 'check if moved to log or already on a log
If OnLog = 0 Then If (FrogLocation = 5) Then ILog1 = 10
ILog2 = 12
ElseIf (FrogLocation = 6) Then ILog1 = 6
ILog2 = 9
ElseIf (FrogLocation = 7) Then ILog1 = 1
ILog2 = 5
EndIf
For I = ILog1 To ILog2
If (LogIsVisible[I]) Then ShapeX = LogX[I]
ShapeW = LogW[I]
FindOverlap()
If (Overlap > 80) Then OnLog = I Goto GotLog
EndIf
EndIf
EndFor
GotLog:
If OnLog = 0 Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
ElseIf (FrogLocation = 8) Then 'moved to home level ‐ see if home
For I = 1 To 5
ShapeX = PadX[I]
ShapeW = PadW
FindOverlap()
If (FrogIsHome[I] = "false" And Overlap > 95) Then Score =
Score + 200
FrogIsHome[I] = "true"
GraphicsWindow.DrawImage(FrogHome, PadX[I] + 10, PadY
+ 10) Sound.Stop(Program.Directory + "\home.wav")
Sound.Play(Program.Directory + "\home.wav") GetNewFrog()
'check if all found
For J = 3 To 3
If (FrogIsHome[J] = "false") Then goto ExitTickSub
EndIf
EndFor
DrawHome()
Score = Score + 1000
GoToNextLevel()
Goto ExitTickSub
EndIf
EndFor
NoMoreFrog()
EndIf
ExitTickSub:
EndSub

Sub PositionLogs
GraphicsWindow.BrushColor =
GraphicsWindow.GetColorFromRGB(128, 128, 255)
GraphicsWindow.FillRectangle(0, RiverTop, GraphicsWindow.Width,
RiverHeight) 'top row
LogX[1] = 20
LogY[1] = RiverTop LogW[1] = 80
LogH[1] = 40
LogX[2] = 140
LogY[2] = RiverTop LogW[2] = 120
LogH[2] = 40
LogX[3] = 300
LogY[3] = RiverTop LogW[3] = 40
LogH[3] = 40
LogX[4] = 400
LogY[4] = RiverTop LogW[4] = 80
LogH[4] = 40
LogX[5] = 540
LogY[5] = RiverTop LogW[5] = 80
LogH[5] = 40
'middle row
LogX[6] = 60
LogY[6] = RiverTop + 40
LogW[6] = 40
LogH[6] = 40
LogX[7] = 180
LogY[7] = RiverTop + 40
LogW[7] = 120
LogH[7] = 40
LogX[8] = 360
LogY[8] = RiverTop + 40
LogW[8] = 80
LogH[8] = 40
LogX[9] = 500
LogY[9] = RiverTop + 40
LogW[9] = 120
LogH[9] = 40
'bottom row
LogX[10] = 40
LogY[10] = RiverTop + 80
LogW[10] = 120
LogH[10] = 40
LogX[11] = 280
LogY[11] = RiverTop + 80
LogW[11] = 80
LogH[11] = 40
LogX[12] = 480
LogY[12] = RiverTop + 80
LogW[12] = 120
LogH[12] = 40
'speeds
If (Level = 1) Then LogSpeed[1] = 5
LogSpeed[2] = 5
LogSpeed[3] = 5
LogSpeed[4] = 5
LogSpeed[5] = 5
LogSpeed[6] = ‐3
LogSpeed[7] = ‐3
LogSpeed[8] = ‐3
LogSpeed[9] = ‐3
LogSpeed[10] = 2
LogSpeed[11] = 2
LogSpeed[12] = 2
EndIf
For I = 1 to NumberOfLogs Shapes.Move(Log[I], LogX[I], LogY[I])
EndFor
EndSub

Sub GetNewFrog
OnLog = 0
FrogLocation = 0
FrogX = 320
FrogY = StartTop Frog = FrogUp Shapes.Move(Frog, FrogX, FrogY)
Shapes.ShowShape(Frog) EndSub

Sub KeyDownSub
KD = GraphicsWindow.LastKey If (GameStatus = "Playing") Then
'Clear from current location
Shapes.HideShape(Frog) If (KD = "Up") Then Score = Score + 100
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogUp
FrogLocation = FrogLocation + 1
If (FrogLocation > 8) Then FrogLocation = 8
EndIf
ElseIf (KD = "Left") Then Score = Score + 1
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogLeft If
FrogX > 0 Then FrogX = FrogX ‐ FrogW
EndIf
ElseIf (KD = "Down") Then Score = Score + 50
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogDown
FrogLocation = FrogLocation ‐ 1
If FrogLocation < 0 Then FrogLocation = 0
EndIf
ElseIf (KD = "Right") Then Score = Score + 10
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogRight If
(FrogX < GraphicsWindow.Width ‐ FrogW) Then FrogX = FrogX
+ FrogW
EndIf
EndIf
'put in new location
DrawFrog()
EndIf
EndSub

Sub DrawFrog
If (FrogLocation = 0) Then FrogY = StartTop ElseIf (FrogLocation = 1
Or FrogLocation = 2 Or FrogLocation = 3) Then FrogY = RoadTop + 140
‐ 45 * FrogLocation ElseIf (FrogLocation = 4) Then FrogY = GrassTop
ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or FrogLocation = 7)
Then FrogY = RiverTop + 120 ‐ 40 * (FrogLocation ‐ 4) ElseIf
(FrogLocation = 8) Then FrogY = HomeTop + 40
EndIf
If (FrogLocation <> 8) Then Shapes.Move(Frog, FrogX, FrogY)
Shapes.ShowShape(Frog) EndIf
EndSub

Sub FindOverlap
Overlap = 0
'check to see if Frog overlaps with shape defined by ShapeX, ShapeW
If (FrogX + FrogW > ShapeX And FrogX + FrogW < ShapeX + ShapeW)
Then Overlap = 100 * (FrogX + FrogW ‐ ShapeX) / FrogW
ElseIf (FrogX > ShapeX And FrogX < ShapeX + ShapeW) Then Overlap
= 100 * (ShapeX + ShapeW ‐ FrogX) / FrogW
EndIf
EndSub

Sub NoMoreFrog
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
Sound.Stop(Program.Directory + "\Beep.wav")
Sound.Play(Program.Directory + "\Beep.wav") ElseIf (FrogLocation = 4)
Then Sound.Stop(Program.Directory + "\Snake.wav")
Sound.Play(Program.Directory + "\Snake.wav") ElseIf (FrogLocation = 5
Or FrogLocation = 6 Or FrogLocation = 7) Then
Sound.Stop(Program.Directory + "\Splash.wav")
Sound.Play(Program.Directory + "\Splash.wav") ElseIf (FrogLocation =
8) Then Sound.Stop(Program.Directory + "\Splash.wav")
Sound.Play(Program.Directory + "\Splash.wav") EndIf
Shapes.HideShape(Frog) GraphicsWindow.BrushColor =
GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(GraphicsWindow.Width ‐
FrogsRemaining * FrogW ‐ 10, 5, FrogW, FrogH) FrogsRemaining =
FrogsRemaining ‐ 1
If FrogsRemaining >= 0 Then GetNewFrog()
Else
ExitStopButtonClick() EndIf
EndSub

Sub DrawHome
PadX[1] = 70
PadX[2] = 180
PadX[3] = 290
PadX[4] = 400
PadX[5] = 510
PadY = HomeTop + 15
PadW = 60
PadH = 60
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
For I = 1 To 5
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(PadX[I], PadY, PadW, PadH)
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
GraphicsWindow.DrawRectangle(PadX[I], PadY, PadW, PadH)
FrogIsHome[I] = "false"
EndFor
EndSub

Sub GoToNextLevel
Sound.Stop(Program.Directory + "\NewLevel.wav")
Sound.Play(Program.Directory + "\NewLevel.wav") Level = Level + 1
GraphicsWindow.Title = "Leap Frog ‐ Level " + Level 'speed things up
For I = 1 To NumberOfVehicles If (VehicleSpeed[I] > 0) Then
VehicleSpeed[I] = VehicleSpeed[I] + 1
Else
VehicleSpeed[I] = VehicleSpeed[I] ‐ 1
EndIf
EndFor
For I = 1 To NumberOfLogs If (LogSpeed[I] > 0) Then LogSpeed[I] =
LogSpeed[I] + 1
Else
LogSpeed[I] = LogSpeed[I] ‐ 1
EndIf
EndFor
'add frog every 2nd level (maximum of 5)
If (Level ‐ 2 * Math.Floor(Level / 2) = 1) Then If FrogsRemaining < 5
Then FrogsRemaining = FrogsRemaining + 1

GraphicsWindow.DrawImage(ImageList.LoadImage(Program.Directory +
"\FrogUp.gif"), GraphicsWindow.Width ‐ FrogsRemaining * FrogW ‐ 10, 5)
EndIf
EndIf
'reposition logs, vehicles
PositionLogs()
PositionVehicles()
'delete logs, add vehicles
If (Level = 2) Then Shapes.HideShape(Log[1]) LogIsVisible[1] = "false"
ElseIf (Level = 3) Then Shapes.HideShape(Log[7]) LogIsVisible[7] =
"false"
Shapes.ShowShape(Vehicle[1]) Shapes.ShowShape(Vehicle[5])
VehicleIsVisible[1] = "true"
VehicleIsVisible[5] = "true"
ElseIf (Level = 4) Then Shapes.HideShape(Log[12]) LogIsVisible[12] =
"false"
Shapes.ShowShape(Vehicle[7]) Shapes.ShowShape(Vehicle[11])
VehicleIsVisible[7] = "true"
VehicleIsVisible[11] = "true"
ElseIf (Level = 5) Then Shapes.ShowShape(Vehicle[4])
VehicleIsVisible[4] = "true"
EndIf
EndSub

Sub UpdateScore
Shapes.SetText(DisplayScore, Score) If (Score > HighScore) Then
HighScore = Score Shapes.SetText(DisplayHighScore, HighScore) EndIf
EndSub
Leap Frog Game Program Review

The Leap Frog game program is now complete. Save and Run the program
and make sure it works as promised. Check that all options work correctly.

If there are errors in your implementation, go back over the steps of window
and code design. Go over the developed code – make sure you understand
how different parts of the program were coded. As mentioned in the
beginning of this chapter, the completed program is saved as LeapFrog in
the KidGamesSB\KidGamesSB Programs\LeapFrog folder.

While completing this program, new concepts and skills you should have
gained include:

➢ Proper steps in game design and game flow.


➢ More graphics capabilities.
➢ Reading keyboard inputs.
➢ Game scoring and level logic.
➢ Working with data files (for saving high scores).

This is the last program in these notes. By now, you should be a fairly
competent Small Basic programmer. There’s always more to learn though.
Consult the Internet and bookstores for more books about skills you might
want to gain.
Leap Frog Game Program Enhancements

There are some ways to change the Leap Frog program. Some possibilities
are:

➢ There are no time penalties in the game – you can play as long as you
like. Perhaps add a clock timer that rewards faster motion and causes
you to lose points or lose frogs if you dally.
➢ Add more features to the game. Perhaps, logs that randomly break or
alligators swimming in the river. Put random potholes in the road at
higher levels. Use your imagination.
➢ To make things a bit harder at higher levels, you might narrow down
the home rectangles a bit.
Appendix II. Sharing a Small Basic Program I bet
you’re ready to show your friends and colleagues some of the programs you
have built using Small Basic. Just give them a copy of your code, ask them
to install Small Basic and learn how to open and run a program. Then, have
them open your program and run it. I think you’ll agree this might be asking
a lot of your friends, colleagues, and, ultimately, your user base. We need to
know how to run a program without Small Basic.

To run a program without Small Basic, you need to create an executable


version of the program. So, how is an executable created? A little secret is
that Small Basic builds an executable version of a program every time we
run the program! This executable file is in the same folder you save your
program in. Open the folder for any program you have built and you’ll see a
file with your program name of type Program.

For example, if I open the program folder for the Leap Frog program we
just built:

The file named LeapFrog.exe of type Application (size 36 KB) is the


executable version of the program. If I make sure Small Basic is not
running and double-click this file, the following appears:

Voila! The Leap Frog program is running outside of the Small Basic
development environment! Go ahead and play the game if you like.

So distributing a Small Basic program is as simple as giving your user a


copy of the executable file (and the SmallBasicLibrary.dll file in your
program folder -this has some support code), having them place the files in
a folder on their computer and double-clicking the executable file to run it?
Maybe. This worked on my computer (and will work on yours) because I
have a very important set of files known as the .NET Framework installed
(they are installed when Small Basic is installed). Every Small Basic
program needs the .NET Framework to be installed on the hosting
computer.

The next question is: how do you know if your user has the .NET
Framework installed on his or her computer? And, if they don’t, how can
you get it installed? These are difficult questions. So, in addition to our
program’s executable file, we also need to give a potential user the
Microsoft .NET Framework files and inform them how to install and
register these files on their computer. Things are getting complicated. Let’s
look at an easier and very flashy solution – letting users access and run your
programs over the Internet!

Start Small Basic and take a look at the toolbar. There are two buttons there
we haven’t talked about yet. Between the buttons to open and save files and

the ones for editing are buttons marked Import and Publish:

These are remarkable buttons. Clicking Import will take you to a Microsoft
website where you can import and open a program stored on the Internet by
you or other users. Publish allows you to store your programs on the
Internet for others to use.

Make sure your computer is connected to the Internet. Go ahead and


click Import. You should see:

To import a program, you require a Program ID. How do you get such
an ID? It is assigned when you Publish a program, so let’s try that. Click
the Cancel button for now.

When you publish a program, it will be available for all to see and use.
And, for now, there is no way to “unpublish” a program. So, be careful
what you publish. You may be leary about just giving your hard work
away. For the example here, I will use a very simple two line program
just to show how things work. You can decide what you want to publish.

Here is the program I will use: GraphicsWindow.Show()


GraphicsWindow.DrawText(10, 10 , "I can publish!!") Type in this code
(or use some other program), then click Publish. You will see a message
something like this:

Your program is assigned a Program ID (remember we need this to


import a program).
Click Add More Details:

Here, you can describe what your program is and what it does. You can
provide a category. This will help users find your program Also listed in
this window is this very interesting piece of information: You can view
your program at: http://smallbasic.com/program/?BGF564

If you click this link (or give the link to others and let them click it),
“magic” occurs.
When I click the link, I am taken to this website hosted by Microsoft:

The running program is shown, along with a code listing.

I think you’ll agree this pretty neat. To share your programs with other
users, Publish them, then give them the program link given to you. If they
click the link, they can run the program. Well, almost. To use this feature, a
user’s computer must have a Microsoft product called Silverlight installed
on their computer. It can be downloaded from this website:
http://www.silverlight.net/

If a user attempts to access your Small Basic program via a provided link
and they do not have the required Silverlight product, they will be taken
through the installation steps.

Return to the website with your running program. In the upper right corner
is a box marked Embed this in your website. In this box is some code that
allows you to put your running application on your own website, if you
have one. The steps to do this are beyond this discussion, but I wanted you
to know such a step was possible.

Before leaving, lets return to the Import button in Small Basic. Click it
again and enter the program ID for your program (I used BGF564):

Click OK. The imported code will appear in your editor:

So, you have access to any code published to the Microsoft Small Basic
library. I’m guessing this library will be growing very quickly.
More Self-Study or Instructor-Led Computer
Programming Tutorials by Kidware Software

Small Basic For Kids is an illustrated introduction to computer programming that provides an
interactive, self-paced tutorial to the new Small Basic programming environment. The book consists
of 30 short lessons that explain how to create and run a Small Basic program. Elementary students
learn about program design and many elements of the Small Basic language. Numerous examples are
used to demonstrate every step in the building process. The tutorial also includes two complete
games (Hangman and Pizza Zapper) for students to build and try. Designed for kids ages 8+.

Programming Games with Microsoft Small Basic is a self-paced second semester “intermediate"
level programming tutorial consisting of 10 chapters explaining (in simple, easy-to-follow terms)
how to write video games in Microsoft Small Basic. The games built are non-violent, family-friendly,
and teach logical thinking skills. Students will learn how to program the following Small Basic video
games: Safecracker, Tic Tac Toe, Match Game, Pizza Delivery, Moon Landing, and Leap Frog. This
intermediate level self-paced tutorial can be used at home or school.
The Developer’s Reference Guide to Microsoft Small Basic While developing all the different
Microsoft Small Basic tutorials we found it necessary to write The Developer's Reference Guide to
Microsoft Small Basic. The Developer's Reference Guide to Microsoft Small Basic is over 500 pages
long and includes over 100 Small Basic programming examples for you to learn from and include in
your own Microsoft Small Basic programs. It is a detailed reference guide for new developers.

Basic Computer Games - Small Basic Edition is a re-make of the classic BASIC COMPUTER
GAMES book originally edited by David H. Ahl. It contains 100 of the original text based BASIC
games that inspired a whole generation of programmers. Now these classic BASIC games have been
re-written in Microsoft Small Basic for a new generation to enjoy! The new Small Basic games look
and act like the original text based games. The book includes all the original spaghetti code and
GOTO commands!
The Beginning Microsoft Small Basic Programming Tutorial is a self-study first semester
"beginner" programming tutorial consisting of 11 chapters explaining (in simple, easy-to-follow
terms) how to write Microsoft Small Basic programs. Numerous examples are used to demonstrate
every step in the building process. The last chapter of this tutorial shows you how four different
Small Basic games could port to Visual Basic, Visual C# and Java. This beginning level self-paced
tutorial can be used at home or at school. The tutorial is simple enough for kids ages 10+ yet
engaging enough for adults.

Programming Home Projects with Microsoft Small Basic is a self-paced programming tutorial
explains (in simple, easy-to-follow terms) how to build Small Basic Windows applications. Students
learn about program design, Small Basic objects, many elements of the Small Basic language, and
how to debug and distribute finished programs. Sequential file input and output is also introduced.
The projects built include a Dual-Mode Stopwatch, Flash Card Math Quiz, Multiple Choice Exam,
Blackjack Card Game, Weight Monitor,Home Inventory Manager and a Snowball Toss Game.
David Ahl's Small Basic Computer Adventures is a Microsoft Small Basic re-make of the classic
Basic Computer Games programming book originally written by David H. Ahl. This new book
includes the following classic adventure simulations; Marco Polo, Westward Ho!, The Longest
Automobile Race, The Orient Express, Amelia Earhart: Around the World Flight, Tour de France,
Subway Scavenger, Hong Kong Hustle, and Voyage to Neptune. Learn how to program these classic
computer simulations in Microsoft Small Basic.

JavaTM For Kids is a beginning programming tutorial consisting of 10 chapters explaining (in
simple, easy-to-follow terms) how to build a Java application. Students learn about project design,
object-oriented programming, console applications, graphics applications and many elements of the
Java language. Numerous examples are used to demonstrate every step in the building process. The
projects include a number guessing game, a card game, an allowance calculator, a state capitals
game, Tic-Tac-Toe, a simple drawing program, and even a basic video game. Designed for kids ages
12 and up.
Learn JavaTM GUI Applications is a 9 lesson Tutorial covering object-oriented programming
concepts, using an integrated development environment to create and test Java projects, building and
distributing GUI applications, understanding and using the Swing control library, exception handling,
sequential file access, graphics, multimedia, advanced topics such as printing, and help system
authoring. Our Beginning Java or Java For Kids tutorial is a pre-requisite for this tutorial

JavaTM Homework Projects is a Java GUI Swing tutorial covering object-oriented programming
concepts. It explains (in simple, easy-to-follow terms) how to build Java GUI project to use around
the home. Students learn about project design, the Java Swing controls, many elements of the Java
language, and how to distribute finished projects. The projects built include a Dual-Mode Stopwatch,
Flash Card Math Quiz, Multiple Choice Exam, Blackjack Card Game, Weight Monitor, Home
Inventory Manager and a Snowball Toss Game. Our Learn Java GUI Applications tutorial is a pre-

requisite for this tutorial


Beginning JavaTM is a semester long "beginning" programming tutorial consisting of 10 chapters
explaining (in simple, easy-to-follow terms) how to build a Java application. The tutorial includes
several detailed computer projects for students to build and try. These projects include a number
guessing game, card game, allowance calculator, drawing program, state capitals game, and a couple
of video games like Pong. We also include several college prep bonus projects including a loan
calculator, portfolio manager, and checkbook balancer. Designed for students age 15 and up.

Programming Games with JavaTM is a semester long "intermediate" programming tutorial


consisting of 10 chapters explaining (in simple, easy-to-follow terms) how to build a Visual C# Video
Games. The games built are non-violent, family-friendly and teach logical thinking skills. Students
will learn how to program the following Visual C# video games: Safecracker, Tic Tac Toe, Match
Game, Pizza Delivery, Moon Landing, and Leap Frog. This intermediate level self-paced tutorial can
be used at home or school. The tutorial is simple enough for kids yet engaging enough for beginning
adults. Our Learn Java GUI Applications tutorial is a required pre-requisite for this tutorial.
Visual Basic® For Kids is a beginning programming tutorial consisting of 10 chapters explaining (in
simple, easy-to-follow terms) how to build a Visual Basic Windows application. Students learn about
project design, the Visual Basic toolbox, and many elements of the BASIC language. The tutorial
also includes several detailed computer projects for students to build and try. These projects include a
number guessing game, a card game, an allowance calculator, a drawing program, a state capitals
game, Tic-Tac-Toe and even a simple video game. Designed for kids ages 12 and up.

Programming Games with Visual Basic® is a semester long "intermediate" programming tutorial
consisting of 10 chapters explaining (in simple, easy-to-follow terms) how to build Visual Basic
Video Games. The games built are non-violent, family-friendly, and teach logical thinking skills.
Students will learn how to program the following Visual Basic video games: Safecracker, Tic Tac
Toe, Match Game, Pizza Delivery, Moon Landing, and Leap Frog. This intermediate level self-paced
tutorial can be used at home or school. The tutorial is simple enough for kids yet engaging enough
for beginning adults.
LEARN VISUAL BASIC is acomprehensive college prep programming tutorial covering object-
oriented programming, the Visual Basic integrated development environment, building and
distributing Windows applications using the Windows Installer, exception handling, sequential file
access, graphics, multimedia, advanced topics such as web access, printing, and HTML help system
authoring. The tutorial also introduces database applications (using ADO .NET) and web applications
(using ASP.NET).

Beginning Visual Basic® is a semester long self-paced "beginner" programming tutorial consisting
of 10 chapters explaining (in simple, easy-to-follow terms) how to build a Visual Basic Windows
application. The tutorial includes several detailed computer projects for students to build and try.
These projects include a number guessing game, card game, allowance calculator, drawing program,
state capitals game, and a couple of video games like Pong. We also include several college prep
bonus projects including a loan calculator, portfolio manager, and checkbook balancer. Designed for
students age 15 and up.
Visual Basic® Homework Projects is a semester long self-paced programming tutorial explains (in
simple, easy-to-follow terms) how to build a Visual Basic Windows project. Students learn about
project design, the Visual Basic toolbox, many elements of the Visual Basic language, and how to
debug and distribute finished projects. The projects built include a Dual-Mode Stopwatch, Flash Card
Math Quiz, Multiple Choice Exam, Blackjack Card Game, Weight Monitor,Home Inventory Manager
and a Snowball Toss Game.

VISUAL BASIC AND DATABASES is a tutorial that provides a detailed introduction to using
Visual Basic for accessing and maintaining databases for desktop applications. Topics covered
include: database structure, database design, Visual Basic project building, ADO .NET data objects
(connection, data adapter, command, data table), data bound controls, proper interface design,
structured query language (SQL), creating databases using Access, SQL Server and ADOX, and
database reports. Actual projects developed include a book tracking system, a sales invoicing
program, a home inventory system and a daily weather monitor.
Visual C#® For Kids is a beginning programming tutorial consisting of 10 chapters explaining (in
simple, easy-to-follow terms) how to build a Visual C# Windows application. Students learn about
project design, the Visual C# toolbox, and many elements of the C# language. Numerous examples
are used to demonstrate every step in the building process. The projects include a number guessing
game, a card game, an allowance calculator, a drawing program, a state capitals game, Tic-Tac-Toe
and even a simple video game. Designed for kids ages 12+.

Programming Games with Visual C#® is a semester long "intermediate" programming tutorial
consisting of 10 chapters explaining (in simple, easy-to-follow terms) how to build a Visual C# Video
Games. The games built are non-violent, family-friendly and teach logical thinking skills. Students
will learn how to program the following Visual C# video games: Safecracker, Tic Tac Toe, Match
Game, Pizza Delivery, Moon Landing, and Leap Frog. This intermediate level self-paced tutorial can
be used at home or school. The tutorial is simple enough for kids yet engaging enough for beginning

adults
LEARN VISUAL C# is a comprehensive college prep computer programming tutorial covering
object-oriented programming, the Visual C# integrated development environment and toolbox,
building and distributing Windows applications (using the Windows Installer), exception handling,
sequential file input and output, graphics, multimedia effects (animation and sounds), advanced
topics such as web access, printing, and HTML help system authoring. The tutorial also introduces
database applications (using ADO .NET) and web applications (using ASP.NET).

Beginning Visual C#® is a semester long “beginning" programming tutorial consisting of 10


chapters explaining (in simple, easy-to-follow terms) how to build a C# Windows application. The
tutorial includes several detailed computer projects for students to build and try. These projects
include a number guessing game, card game, allowance calculator, drawing program, state capitals
game, and a couple of video games like Pong. We also include several college prep bonus projects
including a loan calculator, portfolio manager, and checkbook balancer. Designed for students ages
15+.
Visual C#® Homework Projects is a semester long self-paced programming tutorial explains (in
simple, easy-to-follow terms) how to build a Visual C# Windows project. Students learn about
project design, the Visual C# toolbox, many elements of the Visual C# language, and how to debug
and distribute finished projects. The projects built include a Dual-Mode Stopwatch, Flash Card Math
Quiz, Multiple Choice Exam, Blackjack Card Game, Weight Monitor,Home Inventory Manager and
a Snowball Toss Game.

VISUAL C# AND DATABASES is a tutorial that provides a detailed introduction to using Visual
C# for accessing and maintaining databases for desktop applications. Topics covered include:
database structure, database design, Visual C# project building, ADO .NET data objects (connection,
data adapter, command, data table), data bound controls, proper interface design, structured query
language (SQL), creating databases using Access, SQL Server and ADOX, and database reports.
Actual projects developed include a book tracking system, a sales invoicing program, a home
inventory system and a daily weather monitor.

You might also like