Wayback Machine
SEP JUL Aug
Previous capture 24 Next capture
2008 2011 2012
4 captures
24 Jul 08 - 24 Jul 11
sparklines
Close Help

PCOPY! Issue #40 ~ March 15th 2007
Covering All BASICs


In This Issue:


Contributors:


 Regular Columns:
  From Our Editing Desk (MystikShadows)
  Submitting to PCOPY! (MystikShadows)
  Letters To The Editors (Mixed Contributors)
  Quote Of The Month (E.K. Virtanen)
  In The News (Mixed Contributors)
  Exit Issue (MystikShadows)

 Special Corners:
  The Useless Corner (Hartnell)
  Contest : The Dumbest Game (Hartnell)

 Reviews And Presentations:
  Introducing Yabasic (MystikShadows)
  Introductory Article On XBLite (Guy (gl) Lonné)
  About thinBasic (Eros Olmi)
  Epic Crusade (Jare)

 Articles:
  A piece of history: Star Trek Game (E.K.Virtanen)
  The Evolution Of BASIC (MystikShadows)

 Tutorials:
  Programming Simulation Games (MystikShadows)
  Basic4GL Tutorial: Tile Maps (Linkage)
  Introduction to the FreeBasic Extended Types (Rick D. Clark)
  Simulating Polymorphic Methods... (Rick D. Clark)
  FreeBASIC File/Folder Management (MystikShadows)


 MystikShadows
 E.K. Virtanen
 Hartnell
 Richard D. Clark
 Guy (gl) Lonné
 Eros Olmi
 Linkage
 Jare


~ REGULAR COLUMNS ~

From the Editors: by Stephane Richard (MystikShadows)


Welcome to this 4th edition of PCOPY! As you might have noticed we're giving PCOPY! a new look. There's been alot of comments about how PCOPY! looked, How difficult the colors were on the eyes. So here is our attempt at making PCOPY! easier to read while remaining true to the PCOPY! tradition of monospaced characters.

On a personal note, I'd like to share with you that PCOPY! is broadening its horizon so to speak. Indeed users and creators of other basics are starting to notice PCOPY! which means that we are right on track with one of PCOPY!'s main goal which is to be a magazine for all basics. We'd like to thank all contributors of articles for any basic. we can't wait to get even more contributions about even more BASIC dialects.

We have yet another great line up of material for your reading pleasure. There is always something going on in the BASIC communities and as always we did our best to bring you the most current and up to date news on what's happening. We have our regular columns of course and your reviews and presentations section (which we now isolated as we plan to write a whole lot more presentations to help you learn more about what BASIC is out there).

So get yourself your favorite drink, sit back and enjoy the contents we've put together for you at your own pace.


Submitting to PCOPY!: by Stephane Richard (MystikShadows)


As you probably noticed, we have a list of contributors. Everyone that submits something gets his/her name added to this list for the particular issue the submission appears in. We can't claim to know every single BASIC dialect out there nor can we claim to know how to program in all of them. There are just too many of them. Hence, this is an official invitation to those of you that do know a specific BASIC dialect well enough to write about it. Help us make PCOPY! the most complete BASIC magazine there can possibly be by sending us submissions about them.

When we say submissions we mean anything that pertains to the specific BASIC dialect in question. Submissions can range from simple news item (a new version comes up, a new library is available and the likes), they can be personal reviews of a given BASIC interpreter/compiler, they can be tutorials, tips and tricks that shows readers how to accomplish a given task in the BASIC of your choice. The choice is yours. Submissions will help make PCOPY! even better than it is and the end result of that is that readers will have better BASIC related material to read in every issue that comes up.

So don't be shy, you know something others don't about a given BASIC, let us know about it, send us your submissions and we'll take it from there. If you're not sure how good a writer you are don't worry, if needed, we'll edit and format the submission accordingly. So please, submit whatever you have time to write.

All submissions can be sent to my email and will typically be added in the issue that is currently being worked on at the time the submission is sent to us.




Letters To The Editors: By Mixed Contribytors


Letter from Gandalf Parker

I love the PCopy magazine. Thanks for posting about in on the YaBasic forum. But Im wondering, I dont see any mention of YaBasic.

Im an old guy. I got into basic back when you had to. It was what your PC ran on. I got back into it because my linux server loaded yabasic. The only other basic it had was BW Basic. I stuck with YaBasic because it had a Windows version when meant I could use the same quickie little programs on my desktop and my server.

Now I use YaBasic for web CGIs, admin scripts, fancier batch files on my windows machine, just about anything where I need something working really quick.

Its still in the debian catalog for any admin to easily load and use, so Im thinking it maybe should be mentioned.


Thank you for your letter Gandalf, I'm going to use it here to explain how we define and decide which BASIC we'll talk about on an issue and/or in general.

As you know there are alot of different BASIC dialects out there. Anything ranging from interpreters, to gaming specific, to compilers. If it's a free BASIC dialect, whather it is Freeware or Open Source, whether an interpreter or a compiler, whether a general or specific purpose BASIC we want to cover it in PCOPY!. Can you imagine the size of each issue if we were to include everything about every single BASIC dialect out there?

The best thing to do if anyone using any BASIC dialect out there that want that basic to be featured in PCOPY! is to do just like you did right here (which is to tell us about it). This is because this way, we know that someone from that BASIC community (or user group) is reading the magazine and hence warrants it's presence in the magazine. As you can read here a presentation of yabasic has been made in this issue and from then on out who know what else can be added for contents in the future.

So to everyone reading this issue of PCOPY! the message has been sent, if you want the BASIC you love to use to be featured in PCOPY! let us know all about it.

MystikShadows

Quote Of The Month: By E.K. Virtanen


Quote of the Month

sid6.7, Z!re, E.K.Virtanen & {nathan}

E.K.Virtanen thanks Z!re for giving good laughs. ;D
Background of quote: in here and in here.
  • sid6.7: its just not gonna happen any time soon..so lets just move over to PCOPY
    for now guys...

  • Z!re: People hate pcopy because it sucks.
    People like QBE.
    You're locking the topic because you're a $$$ moron and dont think people can have an opinion on their own?

    Please, do explain why you locked this topic. Go on. In the meantime, I'm unlocking it.

  • E.K.Virtanen: People(s) <> Z!re.
    People(s) <> Your few friends at **.
    You start to sound like menno with your declarations.

  • {nathan}: I like pcopy.
    Z!re, go back to touching little boys, mmk?

  • changed to:

  • sid6.7: its just not gonna happen any time soon..so lets just move over to PCOPY
    for now guys...

  • Z!re: EDIT: By popular demand, topic locked. Sorry sid, you were right.

In The News: (Mixed Contributors)


FreeBASIC - Classic Art Slider Puzzle Game By Lachie Dazdarian
Lachie Dazdarian annonced in this post his new "classic" game creation. It is a classic slider puzzle game where the object of the game is to slide square pieces of a puzzle in order to form the finished picture. It features some "unique" classic art some of which isn't for the faint of heart. You can give this game a try by downloading it from here.

FreeBASIC - BLOC8 Created By BeBeliOuS
In This Post On The FreeBASIC Forum you can read that BeBeliOuS created this excellent game called BLOC8. Block is a "PuyoPuyo" style game as stated by the author. Someone similar to Tetris like games. The object is to position falling blocs (with different square colored patterns in them to align them and the likes. Have a look see, it looks like a great game.

FreeBASIC - Owen announces his FB CAD program created in FreeBASIC
Owen created possibly the very first FreeBASIC CAD (Computer Aided Design) program in the history of the language. FB CAD is the name and you can read the details of this application In this FreeBASIC forum post. Though one of the reason for this project was to learn to program in FreeBASIC I have to say that FBCAD is shaping up to be a great CAD program. Have a look at it the source code is right there in the post.

FreeBASIC - subxero has an excellent GUI project.
In this FreeBASIC forum post subxero announces his FreeBASIC GUI project. I have to say from the screenshots on the post that this GUI really warrants the post title "A Wicked Awesome GUI". The Visual Elements are coded in C but the main Engine of the GUI is 100 pure FreeBASIC. I think this will soon make it's duely warranted mark in the history of FreeBASIC development projects.

FreeBASIC - AFLIB2 Remixed created by Adigun A. Polack.
AFLIB2 everyone reading this here today knows what AFLIB and AFLIB2 are all about. Adigun has taken a big decision recently in moving AFLIB2 a step forward. AFLIB2 is doing away with 8bit graphic support to make room for 15, 16, 24 an 32 bit color depthness. With these new modes will come more advanced effects. You can read all about this excellent project in this Forum post on the FreeBASIC forum.

xbLite - Vixen 0.94p released.
This version of the Vixen system developed by Guy for xbLite has been released. It features mostly bug corrections from bugs reported to him so far. here's the link to the google group message post. Note that you'll have to join the group prior to getting a copy of this latest Vixen release.

BCX - Currently at version 5.11.
The BXC Basic To C translator project is still actively being developed though the original author, Kevin Diggins isn't work on it currently. Bugs get fixed, features get added to make BCX one of the more complete Basic dialects for Windows out there. Note that today BCX is current at version 5.11 in the SVN repository.

Decimal BASIC - Now at version 5.9.7.
Decimal BASIC is a ISO full BASIC programming language. For those that don't know Decimal BASIC you can get all the details about this dialect of BASIC from it's webpage. It is a very mature (at version 5.9.7) programming system and is worth the mouse click to learn about it. Their website is also where you'll find a link to download the latest version.

HotBasic 5.2a (14'th Mar. 2007) now integrates HotOptimize pre-processing merely by use of the -O switch (optimize), causing automatic call to hotoptim.exe followed by compile of the optimized code. The only requirement is hotoptim.exe (HotOptimize download) in your HotBasic directory.

KBasic Software Atelier (V1.6) is planned to be released on 30 March, 2007. V1.7 is expected in May 2007.

16'th Feb. 2007: Play Basic V1.65 DX7 ALPHA (Retail Compiler Only Beta) - (Available for Registered Users ONLY)

Some updates made at BBC BASIC website.

GW-BASIC forum was not dead as i told in last issue. It came back in the books of living ones right after last issue was released.

QBasic on Linux Club still swear in name of QBASIC. QB is an old warhorse and personally i love linux, so nice to see groups like this.

QBasic Gui Wiki. is still kicking. QB'rs, head yourself there.

CoolBASIC is not so dead than it was supposed to be. There is a group of peoples who are interested to invastigate possibilities to create an CoolBASIC compiler for linux platform. At same time, project to translate CB documents from Finnish to English has boosted a bit. New translated documents pop's out time to time.

Brutus2D V1.7 released March 7, 2007.





~ SPECIAL CORNERS ~

The Useless Corner: by Hartnell


Some things about Commodore BASIC and the C64 I find completely useless. Maybe its because time has erased my memory of what to do with these things. In The Useless Corner, I will challenge you to give me a practical purpose for a feature I think is Useless.

This issue's useless thing is LIST.

It's true, LIST is very useful. But, look at this completely useless use of LIST :

10 PRINT "THIS PROGRAM LISTS ITSELF"
20 LIST

The output of this program is :

THIS PROGRAM LISTS ITSELF
10 PRINT "THIS PROGRAM LISTS ITSELF"
20 LIST

Here's my challenge to you. Find a practical purpose for being able to LIST the code of the program that's running. You can send it to : shawn.Hartnell@gmail.com


Contest : The Dumbest Game by Hartnell


Every month we will be running a contest. This month's theme is the DUMBEST GAME EVER. Here are the rules:

  • Make a dumb game in Commodore BASIC.
  • Submit it to shawn.Hartnell@gmail.com
  • The winner will be announced in the next issue.

Even though PULL MY FINGER is just an example to get you started, it shows you how dumb a BASIC game can be. If the entries are as dumb as this, you have some stiff competition.

Hit Some Guy

10 REM HIT SOME GUY
20 PRINT CHR$(147)
30 PRINT "HIT SOME GUY WITH A STICK? (Y/N)
40 INPUT A$
50 IF A$ <> "Y" GOTO 80
60 PRINT "THE GUY SAYS 'OUCH!'" 
70 PRINT : GOTO 30
80 PRINT "COWARD"
90 END

Pull My Finger

10 REM PULL MY FINGER
20 PRINT CHR$(147)
30 PRINT "PULL MY FINGER? (Y/N)"
40 INPUT A$
50 FOR I = 1 TO 2000:NEXT I 
60 PRINT "PPPFFFFT."
70 END

Good luck. You'll need it.


~ REVIEWS AND PRESENTATIONS ~

Introducing Yabasic: by Stephane Richard (MystikShadows)


INTRODUCTION:

In today's world, it gets harder for new BASIC dialects to make their mark in the big pool of BASIC languages that exists today. I was introduced to Yabasic a few days ago by a reader that wondered why it wasn't covered in PCOPY! in any way. So I went to the website, downloaded a copy of the latest implementation of Yabasic and gave it a good try. As a result, I just had to present it to our readers.

Yabasic is what I like to call a good old BASIC. Here is a screenshot of yabasic executing the demonstration program provided in the installation:

This means that Yabasic is ready to run something. You can type commands in the environment or pass a file as a commaand line to yabasic.exe and it will execute the file (much like when using QBasic. Note that you can use an editor to edit source files as yabasic does not save them from within the environment. In Windows, the installation associates the .yab extension to yabasic.exe so that when you double click on the source file you created it will be executed automatically.

ABOUT YABASIC'S SYNTAX AND GRAMMAR:

Yabasic's syntax is very crisp and clear. It's a bit different than other BASICs but in my opinion it actually helps Yabasic set itself apart as well as remain a clear and fun to use syntax. Here's a small sample code to give you an idea:

clear screen
for a=1 to 200
  print color("red") "Hello !";
  print color("blue") "World !";
next a
r$=getscreen$(0,0,20,20)
for x=0 to 60
  putscreen r$,x,0
  sleep 0.1
next x
         

As you can see it definitaly looks and feels like basic. And as you might have noticed it has some nifty commands to get and restore the screen (or even parts of it). It can do some pretty cool things even just with the print command which combines color, screen location and contents to be printed into one command with everything optional so you don't have to enter empty parameters if you're not using part of the syntax.

Yabasic isn't limited to that either, it does graphics, it does them quite elegantly I might add. With statements like circle, rectangle, box and others which give it a complete set of graphic commands it's able to easily create some great graphics and graphic effects. It has a good set of string manipulation functions as well to allow to process strings it efficient and useful ways. Add to that some file manipulation statements and other useful construct like repeat loops and others and you have yourself a great BASIC dialect to have fun with. Here's another sample code that uses graphics commands:

open window 200,200
new curve
line to 100,50
line to 150,150
line to 50,150
close curve
         

New Curve essentially starts a series of lines (where each instructions starts from the end of the previous instruction allowing to draw lines that follow each other to form a shape. When you're done drawing your shape you simply issue a close curve to stop the process. I think this is one of the most intelligent ways of implementing this type of feature.

OTHER FUN YABASIC FEATURES AND FACTS:

One of the thing you can read on the website is that although Yabasic behances like an interpreter it is actually an interactive compiler. Indeed when it gets code from a file passed as a command line parameter or code you type in the environment. That code gets compiled before it gets executed. It uses a principle of a simple stack machine and the code is ready to execute. So essentially though it works like an interpreter it is actually rather fast in it's execution.

Yabasic was created using Flex Bison as it's main engine. So it's grammar is defined in BNF (Backus Naur Form) Which then creates 2 C programs which used together produces the yabasic program. Flex and Bison is a great way to create a grammar (and allow to validate it as well) so I think that using it in this project is a great decision in itself.

You'll be happy to learn that Yabasic is released as Open Source under the GPL licensing scheme. Hence it's free, you can download it all you want explore the source code, learn from it or do whatever you want that GPL allows (which is quite a lot).

WHERE TO FIND OUT MORE ABOUT YABASIC:

If you are as curious about Yabasic as I was when I learned about it. pay a visit to The Yabasic Website. From there you can take a look at the history of the creation of the project, the FAQ, you can download and try Yabasic for yourself and see for yourself how great a dialect of basic it is.

I also invite you to consult the yabasic manual where everything is pretty straightforwardly documented and easy to read. You'll see how rich the Yabasic syntax is and how everything works to make Yabasic do what you want it to do.

IN CONCLUSION:

BASICally speaking, Yabasic is one of the better implemetations of the BASIC language I've seen. I'm glad I was introduced to it and would like to thank Gandalf for letting me know about it. If there's one thing I can say against Yabasic is simply that since it's so close to a compiler (flex and bison based code) a compiler that produces executables int he classic sense of the word might not be that hard to do and I believe would open alot of doors for Yabasic in my opinion. Other than that, Yabasic is a great BASIC to use.

This article is of course based on my own personal experience using Yabasic. The best thing I can tell you is to grab a copy of it and try it for yourself. Be your own judge and see for yourself what Yabasic is all about. Yabasic is a great idea that can be turned into an even better implementation of that idea. Don't take my word for it. Have a look and see for yourself. Until next time, happy coding.

Introductory Article On XBLite: by Guy "gl" Lonné


Introduction

Stephane "MystikShadows", editor of PCOPY!, asked David Szafranski for a short presentation of XBLite to publish in the 3rd issue of his BASIC e-magazine "PCopy". Follow here the article, which I authored on behalf of David. In this personal article, I will try to convey the sheer pleasure that I have to develop in XBLite.

I. My encounter with XBLite

Dear Reader, you might want to skip my personal history and go directly to "II. What Can XBLite Do?" since the article is about XBLite, not my love affairs with languages.

I am a professional programmer since 1980. The first application I wrote (an accounting package) was on a Perkin-Elmer, using an interpreted Basic enhanced with some assembly routines. The following year, I met Her, COBOL, on a Triumph-Adler (with a Texas Instrument processor). O my Lady, after a quarter of a century long a relationship, you are still the love of my (programming) life!

But, life is life! I met this sexy Blonde in 1989: C. Boy! What a hot relationship! But no children. Coming from a COBOL background, I could not produce any program after a whole year trying hard. I looked for professional council and I attended a 1-year course at the New York University School of Continuing Education. I was lucky enough to have an outstanding teacher, who taught me all the tricks of the C trade. In 1991, I purchased from Tandy the DeskMate SDK and from Microsoft, MS C version 5. Unfortunately, (not for Bill G.) Windows™ outplayed all competition on Intel processors; so bye-bye DeskMate SDK and my investment in it! Then, Visual Basic crossed my path in 1999: pretty face and beautiful forms. I discovered a whole new world and I was back to the Basics! Getting tired of being so shielded from Windows™, I decided to explore the WIN32 API realm. I was thinking to go back to my old mistress, Miss C. But I discovered XBLite in 2005. And it was love at first sight: it was my Miss C, but with strings! Yes, C is so great at everything but handling strings, and here is XBLite, almost as good as C at everything, with her additional built-in string support! (The C-string model, by the way).

OK, Dear Reader, let's talk business, XBLite programming business!

II. What Is XBLite?

XBLite is a BASIC compiler, mainly for Windows™ GUI developments. Its syntax is clearer and easier to get to grips with than C, with almost matching performances (coined by phpbb's Michael, thanks M.!).

XBLite is free, open-source, and published under GPL and LGPL. Its workbench comes with the compiler, XSed, utilities, demos, source code and reference manual. XSed is a scintilla based programmer editor, meaning it has built-in syntax colorization, folding capability and is optimized to edit XBLite programs. The entire workbench can be downloaded from David Szafranski's site.

The compiler creates Win32 programs (GUI or console). Free add-on DLLs are available at David Szafranski's site, e.g. DLLs for sending email via SMTP, to embed a web-browser from within a program, to load and save JPG, GIF, BMP, DIB, RLE, TGA, PCX image files, to create card games, etc.

XBLite has a GUI designer: Vixen, © GPL 2006 by the Vixen Team: John "prujohn" Evans, Guy "gl" Lonne, Rhett "lzdude69" Thompson. Vixen is still underway by this article's Author. A downloadable version is posted regularly in the XBLite Google Group.

Follows an excerpt from David Szafranski's site.

(----------------------- Beginning of excerpt -----------------------)

III. What Can XBLite Do?

XBLite is as well suited to novices as programming wizards, and is appropriate for virtually all programming tasks. For science and engineering, XBLite has extensive math libraries, including complex number arithmetic. For business, XBLite has a 64-bit integer data type, user-defined types optimized for database I/O. XBLite can also connect to ODBC databases or use database libraries such as SQLite. For game developers, XBLite can call OpenGL, SDL, or DirectDraw libraries.

For all applications, XBLite designed to support rapid development of compact, efficient, reliable, readable, and well structured programs. And now, XBLite includes a very powerful colored syntax code editor, XSED, which allows the programmer to create and compile programs with ease.

IV. Why XBLite for Windows™?

XBLite is a "younger brother" of XBasic. XBasic was developed by Max Reason to be used under MS-Windows™ and LINUX OS's. In 2000, he made the entire language, compiler, and PDE freely available under an Open Source GPL. The XBasic language itself has not been altered so console programs in XBasic will run identically under XBLite. The XBLite compiler is also released under the same Open Source GPL license.

But XBLite has been enhanced for use under Windows™. It is now possible to:

  • Create true command line Win32 console programs.
  • Use the Windows™ common controls for creating GUI applications.
  • Easily add resources to your executable program.
  • Use inline assembly language in your program.
  • Modify and extend the XBasic language.

And, all of the Windows™ common controls and common dialogs are now available to create win32 native graphical user interfaces (GUIs).

(----------------------- End of excerpt -----------------------)

If David's website is the reference for xblite, it is because David is the one responsible for xblite. Without David, xblite would not exist. He was the one that stripped XBasic to the bare bones and collected all Windows code of it and made it work without a 1.5MB runtime DLL. Only he can tell you how much time and effort it took to transform an idea to a working compiler. Also xblite compiler benefited from the work of Greg aka "Bushpilot". Without his outstanding work, xblite would still use spasm as an assembler instead of the actual goasm. (Thank you efgee for pointing me this out).

The size of the runtime DLL, xb.dll has been reduced to 175kb from 1523kb. With a PE packer such as UPX, the XBLite runtime DLL can be reduced to around 50kb. This huge size reduction was accomplished by taking out the individual libraries in the runtime, Xui, Xgr, Xst, Xma, Xcm, Xin, etc., and making them external DLL libraries (except for the critical parts of Xst).

V. How I do use XBLite?

I always evaluate the size of a project before I start to get organized for my developments. My projects come in 4 sizes:

  • Small (S)
  • Medium (M)
  • Large (L)
  • Extra-large (XL)

As you will see, XBLite can address projects of all sizes, using the appropriate techniques though.

I. The small XBLite project

XBLite is extremely productive for S projects: like writing quick and dirty tools for the Windows™ environment. For example, having to fill an Excel sheet of amounts in dollars, when the original sheet was expressed in euros, I wrote in about an hour (I was still learning) a small XBLite program that accepted an amount in euro, computed the equivalent amount in dollars and placed the result into the Windows™ clipboard, ready for a Ctrl+V into the proper Excel cell. An advice: get familiar with XBLite standard library (here, for the clipboard-related functions).

Bruce M. A. asked: Why code the Euro to Dollars conversion in XBLite, when you could have used VBA and defined a function =ConvertToDollars()?

Because my rule book reads:

  • When you absolutely want to use a hammer, all your problems look like nails
  • Use S projects to experiment potential good programming habit
  • Good programming habits crop up to good programming practices

("You see, Bruce M. A., reasonably done, if not for the good reasons!")

XBLite shines over C because of the time saved not to declare the variables, and because the C function library is readily available (with an IMPORT "msvcrt").

An S project will remain less than a thousand lines, comments included. Comments are sparse, the code speaking for itself. A small project can serve as a prototype of a medium project, to experiment new techniques for instance. Using XSed as a programmer editor (as opposed to ConText for instance), all code can be typed in lower case since, if the auto-uppercase feature is active, all XBLite keywords are recognized and automatically changed in upper case.

Some technical characteristics:

  • All variables are implicit
  • Only 2 types of variable: XLONG and STRING
  • SHARED is implicit: #sharedVar

2. The medium XBLite project

An M project is a successful S project, with a code facelift. I design for reuse: hopefully, some functions will end up in a library (DLL), so I craft them carefully. Otherwise, it has the same technical characteristics as the S project. It will remain less than 5000 lines, comments included. The functions are well commented (that's the facelift). Keep in mind that an M project can also evolve into an L project when its size outgrows the 5000 lines. I use solely XSed as the programming editor and start an editing session with Alt+F8 to fold all functions. I also use Ctrl+Shift+B to "Show Function Browser".

3. The large XBLite project

Its size will grow up to tens of thousand lines. All functions are candidate to end up in a library (DLL), to keep the size manageable. Comments are proficient and are addressed to the XBLite community, because I will publish some general-purpose libraries at the XBLite Google group.

Some technical characteristics:

  • All variables are explicit
  • SHARED is explicit

4. The extra-large XBLite project

It is a team project, hopefully with an experienced project leader.

Some technical characteristics:

  • Good functional specifications
  • Good technical specifications
  • Tool libraries designed by experienced XBLiters with a "Librarian"
  • Coding standards established by experienced XBLiters and respected by the coding team

I would label XL projects those using:

  • Open GL
  • DirectX
  • MySQL
  • TCP/IP
  • Networking
  • Game libraries (Irrlicht, ...)
  • ...

Hopefully, as a collective effort, XBLite will reach the maturity of C in this area, including at pre-processing time, with the help of the M4 pre-processor.

VI. About code re-use

David Szafranski wrote:
In his marvelous book "The Mythical Man-Month", Fred Brooks paraphrases Euclid and says there is no royal road to programming success, or, as he also puts it, NSB ("no silver bullet"). But the closest thing to it is code re-use; this was not possible 20 years ago.

Today, there is a wide variety of libraries available on the net, both in DLL form and in source code form. XB is capable of calling C routines, so one could just use a package like GMP as a DLL, or download source code and re-write it; much simpler than starting from nothing.

Conclusion

With XBLite, I am offering you an adventure: do your programming work under the Windows™ environment and join a generous community, pulled upward by David Szafranski, whose endless energy and kindness kept baby Windows™ XBasic alive and maturing.

Related links:

XBLite contributions:

About thinBasic: by Eros Olmi


Introduction

Easy to install, easy to master, professional help, full features scripting language. All numeric and string data types available, dynamic strings up to 2Gb automatically managed, user defined data types, functions and subs, dynamic functions calling using function name composed at runtime, modular structure with dynamic modules loading, extensible language with external user defined modules, SDK to develop new thinBasic functionalities using different compilers, more than 1000 keywords, more than 3500 predefined constants, more than 15 modules covering many programming aspects already developed, specific editor/ide full of options and tools, plain text or obfuscated scripts and more important coherent Basic syntax, high execution speed, updated and fixed faster than any other development environment ever seen, active support forum with nice people always open to help each other. All this and much more is thinBasic.

A Little Bit About thinBasic Genesis

thinBasic project started as a little automation script engine, originally named AutoProc. At that time, I was searching for a tool to be able to run processes, interact with them, send mail and do ftp. Very few programs were available. Of the ones I tried, they were lacking one or more of the functionalities I needed. So, I decided to start making my own tool. After some time it turned into an interpreted language.

At first, I was alone in developing thinBasic. After 2 years a friend of mine, Roberto, joined the project. We share the same deep passion for computer programming and in particular programming to solve everyday real problems faced by company IT departments.

Ok, now stop with the history and back to thinBasic.

What Is thinBasic?

thinBasic is a script language. It means thinBasic is able to get a text file as input and execute it on the fly. No compilation, no intermediate code, just a plain text file and go. Text file is analyzed and executed immediately. Those text files are called script files. Here is a screenshot of the environment windows.


The ThinBasic Environment

How To Create A Script File

ThinBasic scripts can be created with any text editor able to create text only files. But thinBasic has its own editor/ide called thinAir. You can execute thinAir from the thinBasic menu under the windows applications menu. If you want to edit a thinBasic script file, just right click on it and choose edit from the menu. You will find that thinAir has a lot of unique features that will simplify thinBasic development.

Here is another screenshot featuring some games developed in thinBasic.


Some Game Screenshots

How To Execute A Script File

thinBasic is integrated with the Windows shell. It means that you can execute a script simply by double clicking on it like a standard compiled application. thinBasic scripts can have the following file extensions:

tbasic Plain text gui script.
tbasicc Plain text console script
tbasicx Obfuscated gui script
tbasiccx Obfuscated console script

Types Of Scripts

thinBasic can execute 2 type of scripts: plain text script files or obfuscated script files.

Plain text scripts are standard text files you can create with thinAir (thinBasic editor) or other text only editors like any other standard program.

Obfuscated scripts are plain text scripts transformed by thinAir (thinBasic editor) into crypted and compressed files. This version of script are useful when you need to distribute you application, but you do not want to share the source code, by choice, or because they contain sensible data like passwords or whatever you want to keep secret.

To create an obfuscated script, open your plain text script file into thinAir. Use menu Tools/Obfuscate. thinAir will create a new file in the same directory of the original script file with the same name but with .tbasicx or .tbasiccx extension.

Attention: always keep the original copy of the plain text script, because no one can decrypt an obfuscated script back into its original clean form.

How to get help

thinBasic help is continuously being updated. We try to do our best to create professional and easy to be used help material. When installed, thinBasic has a .chm help file under the thinBasic\Help directory. We also produce some downloadable help files both in html and a .chm format.

How to get support

thinBasic has its own support forum at: http://community.thinbasic.com/ You can post your requests, your code samples, your bug reports or your suggestions.

Where to download thinBasic and some words on thinBasic versioning

thinBasic can be downloaded from: http://www.thinbasic.com/index.php?name=CmodsDownload

We use 2 lines o development: stable and preview.
Stable line is a thinBasic version that has intensively been tested by the thinBasic team, by automatic scripts and by thinBasic users. If no evident bugs, after some time (about 1 month), we release it as stable.

Preview line is the ongoing development. Every time we fix a bug or add new functionalities or make interesting changes, we release thinBasic as a preview version. In this way everyone can immediately test, try and use new functionalities without a long wait. We are very transparent on this. Preview updates are quite frequent, 1/2 every week. Some times even more than once a day. It all depends on bugs found and features added.

thinBasic internal structure

thinBasic has a modular structure. This means that all main language functionalities are all together in a single DLL. All other specific functionalities are separated into external dlls that we call modules. The main thinBasic module is called the Core module and corresponds with the thinCore.dll file. This module is in charge of all main scripting functionalities like: script loading, parsing and execution, memory handling, script flow, string and numeric handling, load/unload of other modules when needed, interfacing with external dlls, interfacing with Windows API.

All other functionalities are handled by specific modules. For example: file and directory handling, Console, OpenGl, user interface, sounds, Ftp, SMTP, advanced math, crypto, Modules are loaded by the main Core engine only when needed by the script.

For example, when you need a function developed into a specific module, for example functions working on files like File_Load or File_Save, you first need to tell thinBasic you want to use the File module. To do this, add the following line into your script:

USES "FILE"

This will tell thinBasic your script needs the File module. thinBasic Core engine will load the File module and will add to the current script execution all the functionalities of the FILE module in terms of functions and equates (constants).

So, for example, if you need to use functions for Console, Files, Ftp and SMTP inside your script add the following 4 lines:

USES "FILE"
USES "Console"
USES "FTP"
USES "SMTP"

Supported data types and variables

thinBasic is a typed language. All variables must be declared before using and every variable must have a type. thinBasic natively supports the following data types:

numeric integer BYTE, INTEGER, WORD, DWORD, LONG, QUAD
numeric floating point SINGLE, DOUBLE, EXTENDED, CURRENCY
fixed string STRING * n, ASCIIZ * n (up to 2Gb)
dynamic strings STRING (up to 2Gb dynamically allocated)
user defined types TYPE/END TYPE
variants VARIANT

Single variables, arrays or matrix up to 3 dimensions can be declared using all the mentioned basic data types. Variables have global or local scope inside functions or subs.

Functions/Subs

thinBasic supports Functions and Subs (subroutines). Every Function or Sub can have up to 32 parameters. Parameters can be optional. Every parameter can be passed by reference or by value. Arrays and structures are always passed by reference.

Execution flow

The following program flow structures are supported

IF/THEN/ELSE/ELSEIF/END IF
FOR/NEXT/ITERATE FOR/EXIT FOR
WHILE/WEND/EXIT LOOP
DO/LOOP with WHILE or UNTIL clause
SELECT CASE/END SELECT 

Keywords

thinBasic has more than 1000 native keywords covering many different programming areas.
We are always very happy to add new functionalities. So, if something is not present in thinBasic language and you would like to add it, provide us with an explanation of the new functionality and we will try our best to add it.

Source Code Examples

A few source code examples to give you an idea of thinBasics power and simplicity.

Loading text csv files

How many times have you needed to load a csv data file? Those files with a comma (or other char) delimited fields? How many For/Next loops did you use?

uses "file"                 '---Tell thinBasic we need file module

'---Specify the csv file to be loaded and parsed
DIM FileToLoad  AS STRING VALUE APP_SOURCEPATH & "CSV_SampleData.csv"

DIM MyMatrix()  AS STRING   '---Will hold the data
DIM nLines      AS LONG     '---Number of lines loaded
DIM nCols       AS LONG     '---Number of colums loaded

'---Just one line do the job of loading file data,
'---parsing text lines, dimensioning and filling the matrix.
PARSE(FILE_LOAD(FileToLoad), MyMatrix(), $CRLF , ",")

'--Now get the number of lines and max number of columns parsed
nLines = UBOUND(MyMatrix(1)) ---Elements in dimension 1
nCols  = UBOUND(MyMatrix(2)) ---Elements in dimension 2

MSGBOX 0, "Loaded file: " & FileToLoad & " contains:" & $CRLF & _
          nCols & " columns" & $CRLF & _
          nLines & " lines"

Function evaluation at runtime

And what about solving y = f(x) equations, taking equations from a string? Can you imagine how many lines of code is needed to perform this kind of operations in other languages? This is a thinBasic example:

USES "CONSOLE"    '---We need Console module to write output
USES "EVAL"       '---We need Eval module to evaluate math strings

DIM t0, t1 AS DOUBLE = TIMER  '---Some timing variable
DIM MyFunction AS STRING      '---Will contain math function to eval

'---Define Y = f(X) ... function inside a string
MyFunction = "y = COS(x) * 10 + SIN(x)"

'---Tells eval engine to define new 2 variables: x and y
Eval_SetNumber("x", 0)
Eval_SetNumber("y", 0)

'---Define a looper and its max
DIM Count     AS LONG
DIM MaxCount  AS LONG VALUE 50

FOR Count = -MaxCount to MaxCount
  '---Set X value
  Eval_SetNumber("x", Count)
  '---Eval MyFunction
  Eval(MyFunction)
  '---Write some info output
  CONSOLE_WRITELINE(format$(Count, "0000") & " " & Eval_GetNumber("y"))
NEXT 

'---Measure the ending time
t1 = TIMER

'---Final results
CONSOLE_WRITELINE("------------------------------------------------------")
CONSOLE_WRITELINE("Time in seconds for " & str$(MaxCount * 2) & " loops: ")
CONSOLE_WRITELINE(FORMAT$(t1-t0, "#0.00000"))

'---Wait for a key to stop execution
CONSOLE_WAITKEY

OpenGl graphics

Here a sample working with TBGL module, thinBasics OpenGl module developed by Petr Schreiber using the thinBasic SDK. Just a rotating triangle but have a look at TBGL script in our forum and you will remain astonished.

USES "TBGL"                   '---Load TBGL module
USES "UI"                     '---Load User Interface module

DIM hWnd AS DWORD             '---This will contain handle of the window

'---Creates OpenGL window, it returns handle
hWnd = TBGL_CreateWindow("Rotating triangle - press ESC to quit")

TBGL_ShowWindow               '---Shows the window

TBGL_GetAsyncKeyState(-1)     '---Resets key status before checking

WHILE TBGL_IsWindow(hWnd)

  WIN_setTitle (hWnd, " ESC to quit (" & TBGL_GetFrameRate & " FPS)")

  TBGL_ClearFrame               '---Prepares clear frame
  TBGL_Camera 0,0,5,0,0,0       '---Setups camera to look from 0,0,5 to 0,0,0

  TBGL_Rotate GetTickCount/10,1,1,1 '---Rotates around all axis

  TBGL_BeginPoly %GL_TRIANGLES  '---Starts polygon definition based on triangles
    TBGL_Color 255,0,0          '---Sets RGB color - Red
    TBGL_Vertex -1,-1,0         '---Adds vertex

    TBGL_Color 0,255,0          '---Sets RGB color - Green
    TBGL_Vertex  1,-1,0

    TBGL_Color 0,0,255          '---Sets RGB color - Blue
    TBGL_Vertex  0, 1,0
  TBGL_EndPoly                  '---Ends polygon definition

  TBGL_DrawFrame                '---Swaps the buffers - displays rendered image

  IF TBGL_GetAsyncKeyState(%VK_ESCAPE) THEN EXIT WHILE

WEND

TBGL_DestroyWindow              '---Closes OpenGL window

MSGBOX 0, "Show is over", %MB_ICONINFORMATION or %MB_TOPMOST, "TBGL demo"

This particular module, TBGL does not offer just 1:1 translation of handy OpenGL commands, it does internal garbage collection, texture loading, model handling and animation too for example.

TBGL (thinBasic Graphic Library) uses it's own file format for 3D models called M15. Never heard of it? Files of this kind are produced by thinEdge, 3D editor developed especially for cooperation with thinBasic. And if you don't like this modeler or just don't want to learn another program more? What about model exporter for Blender application developed by Michael Hartlef (a Blender script create specifically to export Blender 3D models directly into M15 format), or taking advantage of thinEdge OBJ import ability? Wings3D, GMax ... you know them. Any modeler capable of producing OBJ files can be used to create art for your next thinBasic game.

Script Executable

Just recently we started development of thinBundle. It is still in its early stage but results seem really good. Using thinBundle, thinBasic users will be able to create independent thinBasic script executables. thinBundle IS NOT A COMPILER. No machine code will be produced.

thinBundle will create a kind of closed, compressed, crypted executable file containing all the resources a script needs in order to be executed without having thinBasic installed in the target machine. The .exe file produced will be like a box containing all the files needed to execute the script (dll, modules, sources, thinBasic exe, ...). When executed, all needed files will be extracted on disk in the same directory of the exe. All files will be system hidden. After execution, all extracted files will be deleted.

Conclusions

We hope this article expresses the power and simplicity of thinBasic. You will need to try it out to experience the other big feature thinBasic can give you.

Just one final word on thinBasic execution speed. thinBasic is fast! Every new thinBasic version has some improvement on script execution speed. We continually strive to improve optimizations and many users are surprised by the performance of this scripted language, most times it feels like the performance from a compiled application.

References

Website: http://www.thinbasic.com
Support forum: http://community.thinbasic.com
Download material: http://www.thinbasic.com/modules.php?op=modload&name=CmodsDownload
Online help: http://www.thinbasic.com/public/products/thinBasic/help/html/index.html
Whats new: http://www.thinbasic.com/public/products/thinBasic/help/html/whatsnew.htm
Videos with scripts working with OpenGl: http://www.youtube.com/profile?user=erosolmi



Epic Crusade by Jare


Epic Crusade is an RPG game project like Final Fantasy and Chrono Trigger and it is programmed with CoolBasic. The story begins so that the game's main character Rei is sitting in his home and he decides to leav his small house and go to find some adventures like beating dragons and monsters and so on. But then his granpa appears and commands him to go get a special herb from a cave for the town-healer so he could make some medicine out of it. The medicine is needed for grandpa's sore back. Grandpa gives Rei a little money. Rei has to go to buy some equipment from a nearby town so he could start a dangerous trip inside the cave for the herb.

At this point the project is at early development stage since its first introduction was on 6th of November in 2006. There is not yet very much information of this project but a little test version of the game proves that this is going to be one of the best RPG's coded with CoolBasic. Referring to the test version and screenshots, the game has great retro style graphics and effects. The fighting system is turn-based. You select the attack you want to use, then you point the attack to the enemy you want. After you have done your attack the enemies attacks you one by one against you. As the game advances you will get multiple characters into your party and the battles will become more strategical.

If you like some old school RPG games, you should try this one. The classical concept works in this game project and you just cannot wait until the developers get his master piece finished. See the links below!

Links referred to the game project:

Direct link to the test version:
http://students.osao.fi/~b6tujo01/Sourcecodes/EpicCrusade.zip

You can find some screenshots of the game at:
http://s99.photobucket.com/albums/l309/KuroNeko-/Epic Crusade/

The game story:
(you may have to find the notations starting from 14th of December in 2006)
http://doodlemoogle.deviantart.com/journal/?offset=30

Discussion about the project (unfortunately only in Finnish):
http://www.coolbasic.com/forums/index.php?showtopic=5321





~ ARTICLES ~

A piece of history - Star Trek Game: by E.K.Virtanen


To boldly go...



In 1971, Mike Mayfield probably didn't know what he was starting when he wrote his very first Star Trek game. In the course of the following year, he had already ported it to Hewlett Packard BASIC.

In 1973, David Ahl translated it to DEC BASIC and soon after that, with Mary Cole he had it ported for RSTS-11 (BASIC PLUS). In the same year, the game was also publishedint the very first edition of 101 BASIC Computer Games (David Ahl; July, 1973).

Soon after releasing source of this game in that book, various peoples started translating this game for multiple different computers and operating systems. To see the "consequences" of Mike Mayfield's game, we need to use an time line of the more known versions of this game in the 1970s.

  • 1971:
    • Mike Mayfield wrote first version of Star Trek in BASIC for the Sigma 7.

  • 1972:
    • Mike Mayfield rewrote it for Hewlett Packard BASIC.

  • 1973:
    • David Ahl translated the game for DEC BASIC.

    • David Ahd translated this same game for RSTS-11 (BASIC PLUS) with help from Mary Cole.

    • David Ahl published a book 101 BASIC Computer Games where this game was included with the name SPACWR (Space War).

    • Grady Hicks and Jim Korp published an extended version of the game for TAURUS.

  • 1973/1974:
    • Kay Fisher translates it for OS-8 BASIC converting it to PDP-8.

  • 1974:
    • Kay Fisher creates the first DEC FORTRAN-IV version of the game.

    • Graham Toal rescues simplified version of TREK73, written in IMP at The University of Edinburgh. There is no certainty as to who the author is but the name Dave Briggs is often mentioned as the author.

  • 1976:
    • HP 2000 version by Doug Quebbeman.

    • Lynn Cochran's version for Altairs.

    • Two small versions for Palo Alto TINY BASIC. Author unknown.

    • Ron Williams writes an intellect MDS version, adapted from the FORTRAN version.

    • 3-Dimensional version for a CDC 6000. Author unknown.

    • 3-Dimensional version for PR1ME BASIC/VM. Author unknown.

    • Bob Bishop writes Apple Star-Trek for Apple INTEGER BASIC.

    • C version for UNIX by Eric Allman.

  • 1978:
    • BASIC-80 for CP/M translation by Creative Computing.

    • INTEGER BASIC version for Apple ][, by W. Sander.

  • 1979:
    • Kurt Wilhelm writes the COBOL version.

The information listed above is just the tip of the iceberg. Numerous variations and translations were made back in the 1970s. Back in those days, games were considered as total waste of computing time so administrators usually removed games when they spotted them.

After 70's:

In the 80's, 90's and even in this millenium, there has been published new versions of this, probably one of the most ported games ever.

  • Chris Nystrom's C port of Mayfield-style StarTrek in 1995
  • 1998 Michael Baker wrote Palm Trek for the Palm Pilot.
  • December 2003, Jim Bat finished he's Super Star Trek as a Java applet.
  • OpenTrek is a 3D update of the classic Super Star Trek game.


    OpenTrek 3D

Eventhough i mention only four versions of this game here, it certainly does not mean that was all of them. Dozens of other variations are out there somewhere. Just search for them if you're interested.

Related Links:

  • trek.bas Mike Mayfield's original HP BASIC source from year 1972.
  • Star Trek game page Excellent website to learn more about this game. Also includes dozens of sources/binaries of different versions of this game.
  • OpenTrek is a 3d update of the classic "Super Star Trek" game. OpenTrek is open source, released under the GNU General Public License.
  • DigiBarn Books: BASIC Computer Games by David Ahl.
  • TREK73 Page Kermit Murray's page with links to other versions and websites.

The Evolution Of BASIC: by Stephane Richard (MystikShadows)


INTRODUCTION:

From the very start BASIC (Beginner's All purpose Symbolic Instruction Code) has always represented a language for anyone wanting to do programming. This was true wether the user was indeed a software developer or not. It was a language that has always been fun to use and quickly allowed a solution to a given problem to be created.

Looking at what BASIC was when it was created and where it stands today (in it's many implemented dialects). I have decided to define my vision of what BASIC will be (maybe should be) in the future. There's alot of different reasons certain things should be present in the language and we'll try to see what could be added to help the evolution of BASIC. Before we do that, let's take a look and what basic is, when it started and take it from there.

BASIC THE BEGINNING:

BASIC was created in 1963 by by John George Kemeny and Thomas Eugene Kurtz at Dartmouth College. The very first BASIC was hence named Darthmouth BASIC. It was when this first dialect of BASIC was made available that the eight principle of BASIC design were created. These principles were:

  • Be easy for beginners to use.
  • Be a general-purpose programming language.
  • Allow advanced features to be added for experts (while keeping the language simple for beginners).
  • Be interactive.
  • Provide clear and friendly error messages.
  • Respond quickly for small programs.
  • Not require an understanding of computer hardware.
  • Shield the user from the operating system.

Back then, BASIC had line numbers. These line numbers essentially governed the sequence of instruction to execute. It had branching such has GOTO and GOSUB to jump to different parts of the program as needed by the current structure of the program. Since back then, computers didn't have alot of memory the complexity of the programs that could be made were quite limited. But back then the need for computer software was also very limited in size and complexity.

THE HISTORY OF BASIC'S EVOLUTION:

Since it's first implementation, BASIC has gone through many additions and changes that made it the BASIC we are accustomed to seeing today. With the decades, the need for more complex programs that manipulated more data in more complex ways was getting more and more obvious. To follow the trends, basic was given more memory to work with (which allowed it to work on a bit more complex programs) to answer the needs of the era.

In the 70s different languages surfaced which seemed to be able to deal with bigger more complex programs and hence started being used more than BASIC. To accomodate that commands to execute more than one module from within a main source program were added to basic. Commands such as RUN, SHELL and CHAIN opened up new opportunities to create more complex programs in BASIC. But again BASIC didn't quite fit the bill as even more complex applications were starting to be in demand.

In the 80s BASIC started to do away with line numbers and offered a more modular approach to program development. The notion of SUBs and FUNCTIONS were added thus practically eliminating the need for the infamous GOTO statement which was the cause of the classic "spaghetti code" trend that had started. Not too far after that BASIC gained the ability to seperate code into different modules which helped the overall organization of programming projects a whole lot.

Not too long after that, a new trend in programming became popular (quite fast). Object Oriented Programming was one of the newer methodologies of the 80s and offered many advantages to complex programming projects that still today cannot be denied (on certain types of projects). OOP was hard to implement in BASIC while keeping true to the eight design principles of BASIC. So it wasn't until much later in the history of programming languages that OOP got added to some of the BASIC dialects. Of course the need for compiled code also became apparent as better performances were expected of a language like most other features getting added.

With the popularity of Windows growing in the late 80s / early 90s. A new notion called "event driven programming" started to manifest itself. BASIC gained features to help it deal with even driven programming. Products such as Visual BASIC for DOS and Windows appeared offering alot of what today's VB programmers are accustomed to. Controls on a form had certain properties and handle different types of events. And thus BASIC became a true event driven programming language.

BASIC AS IT STANDS TODAY:

BASIC evolved based on the needs and types of software development projects that were needed over the years. BASIC can now work with many mathematical functions integrated into the language. it has some good standard string manipulation functions as well. Event Driven Programming is still in there and typically rather easy to use. BASIC is now the result of the needs imposed by those needed certain types of programs developed. AS such, Database have been added to the repertoire of applications that can be developed with basic.

All in all BASIC has become a true "all purpose" language but not without some sacrifices. To use these new features some complexity were added to the language. The BASIC learning curve is growing. since you can do things in BASIC today that you simply couldn't do before. For example alot of BASICs now handle pointers and pointer arithmetics. This is a complex notion in itself that is hard to simplify to the level that the eight design principles of BASIC would hope them to be. As such, the learning curve gets affected when these new features get added.

However, these features are quite needed and cannot be ignored. Today, people want to see OpenGL, DirectX, music and multimedia programs of all kinds. Hence all this does need to be present in a language if the language is to make it's mark in any way. OOP is still optional but fast almost becoming a mandatory feature of a language. With all these new needs of today's users, BASIC needs to have them for today's needs and for the future as well.

THE FUTURE OF BASIC:

Of course, this is my own vision of the future of BASIC. I believe that you can only add so much to a language without changing the learning curve. However, the need to add to the language grammar itself is obviously present. So how can we counteract this newly added complexity in the future? How can we help keep BASIC simple to use while adding these complex notions and features to the language? I believe there are three ways to do just that.

  • Adding Simple Syntax to Complex Feature Translators:
    If we're going to add complexity to the BASIC language we should do so in such a way that learning to use the complexity doesn't mean learning a complex syntax. Hence, adding a translator to recognize simple terms for a syntax on top of the complex feature would help make that feature as simple to learn as possible. Of course, to begin with, any new syntax should be as simple to read and understand as possible from the very start.

  • Adding tools in the IDE to help with implementing the complex features:
    By that I mean adding interactive/visual design tools that will both help understand the complex feature being used as well as save the programmer time by generating alot of (if not most) of the code needed to implement the complex feature. Wizards as commonly called can help play a great role on how the complex feature is viewed and understood by the programmer. This would also help the user develop his/her knowledge and eventually be able to code the complex feature right in the code editor.

  • Adding "intelligent" Code Generators:
    Of course this could be good for any language. Just somehow more obviously needed to help keep BASIC like BASIC. There's alot of "routine code" in any given project. Alot of repetitive code as well. These could very well be generated by the IDE with minimal (or sometimes no) intervention from the user. We would just need to spot these situations and simply create generators for them. This has the advantage of saving time in many programming situations and still giving the programming complete control after the code is generated.

With these 3 principles in place I believe it will be more than possible to add any complex notion or feature to a BASIC dialect while following the eight design principles of BASIC as a language. It will also allow the language and the IDE to adapt to a given user's level of knowledge and help the IDE adapt to a user's way of working with the language.

IN CONCLUSION: (THE BOTTOM LINE):

BASIC should remain a language anyone can "quickly" learn and use. It definately should incorporate whatever feature that is in demand at the time since this helps BASIC be an "all purpose" programming language. It should continue to typically be the first language of any new programmer because it should remain the most "immediately" rewarding language. Hence have the ability to code things fast in it to get fast results without predefined structures or concepts to learn before coding.

Any new additions should typically be evaluated against the eight design principles of BASIC atleast to a minimum just to help keep BASIC in the confines of it's definition. Use of clear english like keywords instead of symbols would help alot for example. BASIC is a real language where saving keystrokes should be the job of the IDE, not the language. With all this in mind I see a great bright future for BASIC and I am open to discussions about it as well. Just email me with any comments and suggestions and we'll talk about it. Until next time, Happy reading, learning and coding.


~ TUTORIALS ~

Programming Simulation Games: by Stephane Richard (MystikShadows)


Introduction:

The best way to begin this tutorial on programming simulation games is to define exactly what a simulation game is. Tim Hartnell, in his 1986 book entitled Creating Simulation Games On Your Computer, offers the best definition of what a simulation is: "A simulation is a computer model of cause and effect. Event A is linked to event B by equation X. Modify B and C is affected by linking factor Y.". He then gives a simple example that goes like this:

        CAUSE ----------> EFFECT --------------> EFFECT
        SWITCH ON           CURRENT FLOWS            LIGHT GLOWS
         

This is of course a very simple model. But then again a simulation shouldn't be confused with the system it simulates. There are all kinds of simulations that we can find out there. They range from very simple simulations to highly advanced ones. For example, a flight simulator. The first thing to remember is that a simulation is a simplified model of the system or situation it is simulating. Stock Market simulations are another wide spread use of simulations. The best reason for the existance of simulation is that it allows you to experience high risk situations without causing any harm to anyone (especially yourself) or anything. For that reason simulations have been playing an important role in our recent history.

This tutorial will teach you the components of a simulation as well as a complete example of a simulation game (code and sample execution) so that you can get a feel of how these beasts work. Of course the example will be very simplified for the sake of this tutorial, but it will however include all aspects of a simulation game. So let's get started shall we?

The Types Of Simulations:

There are as many types of simulations as they are systems to be simulated. Physical items based simulations, people / population based simulation, real world situations (crisis or not) and so on. But in all cases, one thing we can notice is that all possible simulations fall into two groups. Each of these group represent different types of programming challenges, each have they use and their role in the world of simulations.

  • Simulation who's data is acted on in distinct groups:
    This typically involves a sequence of actions or situations that occurs on the subject being simulated. It involves a process or set of steps, a sequence of events if you will. In order to get the plan started, you must first to a checklist on the plane, start the engine and so on until you are accelerating on the runway ready to take off. To take off you'll need to lift your flaps to get altitude and so on and so forth. There are many simulations that fall into this category. In the real world for example, scientific simulations of molecules use this type of simulation to run a series of test on a molecule. Therre are also many aspects of simulation games that use this method when a certain order things (situations, events) need to be achieved before the expected end result occurs.

  • Simulations who's data values flow into each other:
    These are the more complex simulations out there. In these types of simulation there is always more than one thing to consider. and each of these things will typically affect, in one way or another, one or more other systems running at the same time. A nuclear powerplant for example definitaly has more than one factor that can cause problems. Also, different factors can cause different kinds of problems, these problems may, or may not cause other problems (such as a chain reaction that destroys the power plant). These are probably the more interesting and challenging types of simulations for a user since he/she would have to typically look over (and keep control of) more than one thing in the whole game.

Of course, in a game, anything can happen and it wouldn't exactly be beyond the scope of reality to include a combination of these two types of simulation to add challenge to the game. But typically, one of these two can offer plenty of challenge in itself. It's therefore important to plan the simulation ahead of time, figure out which group of simulation it falls under and determine, before you start coding, which type of data or process takes precedence over the rest of the simulation. Then the factors that can influence this data can be evaluated to see how it could/should affect the data as in if this influence is good or bad to the expected results of the simulation. A little planning goes a long way in this type of game.

Before we start coding anything, I'll start by explaining the components of a simulations. These are the different parts of a simulated system that either play a role in the outcome of the simulation or setup the complete system that is being simulated depending on the type of simulation being created.

The Components Of A Simulation:

In order to create a simulation, certain core elements need to exist to make it a complete simulation system. In essence, creating a simulation is like creating a small world. In that world, you need certain elements to call it a world and you need certain things to happen to call your world a simulation. Let's review these elements of a simulation.

  • The Simulated Model:
    This is essential to a simulation. A simulation simulates a real world system or situation. Hence, without such a system, it would never be a simulation. This can range from physical systems to simple rules that govern real world pratices. The important thing is that your simulation must start from something that exists and attempt to simulate it as faithfully as either possible or feasible based on the context of the simulation.

  • The Environment:
    This will depend on the simulation being done. For example, if simulating a stock market, the real world industry is a great environment to begin with. A great help to a simulation is it's ability to be convincing when simulating it's real world counterpart. This can be a physical object (an airplane in a flight simulator for example) or a set of strategies to be tested.

  • The Actors:
    A simulation typically involves something being tested upon or something testing something else. The important thing is that a simulation involves actors as I like to call them. These are the elements of the simulation that can be defined as independant entitites that will either react to the outside world or situation or being acted on by the outside world, it all depends on the nature of the simulation and the results desired or expected by the simulation.

  • The Controllable Events:
    Depending on the simulation itself controlled events can often be used to influence the simulation. These types or events are the known events that is controled by the user of the simulation. In a flight simulator, it is the flying of the airplane, with the controls that he can use in his flying experience and what he can do with them.

  • The Unexpected Events:
    Taking our flight simulation example above. The unexpected events could be, for example, creating a storm up ahead to see how it influences the pilot's ability to fly under those condition. It could also be to suddenly disable his plane's instrumentation to let the user fly by eye sight alone. They are the events on which the user of the simulation has no control over but would typically act or react on them as needed.

  • The Feedback Loops:
    Whether it's a real world simulation or a simulation game, user feedback is of course important. This can be expressed as how responsive the simulation is to user interaction as well as making sure that the known needed results are displayed to the user. To land a plane you need to know certain things like current speed, altitude, where the runway is, and so on, without proper feedback from the simulation it becomes near impossible to really experience the full effect of the simulation. And yes, I wrote loops because at times when analized simulations can be made of more than one feedback loop.

  • The Equilibrium Point:
    There is such a thing as balance of nature. The equilibrium point is that comfort zone. Call it the ideal condition of the simulation. For a flight simulation it's clear skies, no other airplanes, plenty of fuel and everything on the plane is working properly. For a life simulation it would be the right amount of people in a given populated area to maintain ideal population growth. Most simulations need this equilibrium point to tell the user where and why they are doing things right or wrong, they need a ideal situation to evaluate where the simulation is going.

  • The Negative And Positive Loops:
    These aren't just positive and negative numbers per se. Positive loops are positive actions so so speak. This means that they tend to bring a simulation back to the equilibrium point described above. On the other hand, negative loops then to bring the simulation away from the equilibrium point. This can be the direct results of user interaction or other uncontrollable factors added to the simulation to throw in unpredictable events to add complexity to the real world simulation.

  • The Time Against Action Factor:
    This should have probably been the first item in this list. But on the other hand, all Items in this list are pretty much equally important in relation to each other. Basically, all simulation, since they are simulating a real world system, typically have a time factor involved to some degree in their simulation purposes. Whether it's a real time system (1 second elapsed in the program = 1 second elapsed in the real world system) or not time is the basis of the simulation where things can happen in the course of the simulation. Hence, time is important to a big majority (if not all) of the types of simulations you'll want to make.

As you can see, all these factors will play an important part in most simulations you'll be making. Of course, based on the type of simulation and what one is trying to get out of the simulation not nevessarily all of these components will be needed. But in most cases, it's good to plan to have all of them (as a simulation template if nothing else) as they are typically all used.

The Life (Predator And Prey) Simulation Elaborated:

With this knowledge in mind, we can now begin to create our simulation. In the context of this tutorial we will create a rather simplistic life simulation. There will be predators and preys. As you might have guessed, the predators eat the preys. The object of this simulation will therefore be to keep the life of both predators and preys in balance so that there are always preys to feed on and always predators present to eat the preys.

In this simulation, If there's not enough preys, the predators will eat them all up and then die of starvation. If there are too many preys, the predators will eat more preys and new predators will be born. The idea is to find the real ideal number of predators and preys to keep the simulation running for as long as possible. The only user interaction will be to allow the user to specify the number of predators and preys to begin the simulation with. The simulation will then loop until atleast one of the two (predator or prey) dissapear (count down to 0).

How many preys predators eat in a cycle, how many new preys and predators are created I will leave to random to make it a bit harder to find those ideal numbers. These will change every time you run the program. But on each run you can play with different numbers so during that one session of running the simulation the number of preys eaten and so on will not change. So let's start to create some code for this.

Coding For The Predator/Prey model:

As you'll see from the code we'll create it will be a rather simple simulation but I will be giving tips along the way in case you want to make it more complex. The first thing we'll do is define a user defined type that we will use to generate a simulation report after a simulation is ended. This will essentially be generated as the simulation runs so for each time cycle a new entry will be added to an array we'll declare later of this user defined type.

As usual, you don't have to fool around with cut and pasting the code shown here, you can get it all right here, already typed and ready to go. Though I used FreeBASIC for this tutorial, this simulation should work on any basic that supports the RANDOMIZE and RND() statements. If your BASIC doesn't have those, chances are they have an equivalent so take a look at the help file and just replace these two statements with their equivalent in your flavor of BASIC.

' ----------------------------------------------
'         NAME: SimulationData
'  DESCRIPTION: Holds information about each
'               run cycle of a given simulation
' ----------------------------------------------
TYPE SimulationData
     CycleNumber          AS INTEGER
     TimeMark             AS INTEGER
     PredatorCount        AS DOUBLE
     TotalPopulation      AS DOUBLE
     PopulationDifference AS DOUBLE
     DifferencePredators  AS DOUBLE
     PercentagePredators  AS DOUBLE
     PreyCount            AS DOUBLE
     DifferencePreys      AS DOUBLE
     PercentagePreys      AS DOUBLE
END TYPE
         

There this should be sufficient information about the simulation to be able to extract some useful information from the simulation results. of course now, we will need variables including an array that will hold the information of the simulation. The other variables will be to hold the initial simulation parameters and the results of the formulas we will be using to determine the new population. Here are the variables.

' ---------------------------------------
'  Globally Shared Variable Declarations
' ---------------------------------------
DIM SHARED LongestRun        AS INTEGER
DIM SHARED AggressiveFactor  AS DOUBLE
DIM SHARED TotalPopulation   AS DOUBLE
DIM SHARED NumberOfPredators AS DOUBLE
DIM SHARED NumberOfPreys     AS DOUBLE
DIM SHARED RunCount          AS INTEGER
DIM SHARED Counter           AS INTEGER
DIM SHARED SimulationRuns()  AS SimulationData

         

LongestRun will be used to monitor the longest run reach so far in a session. AgressiveFactor will be used to determine how agressive the predators are vursus the preys. NumberOfPredators and NumberOfPreys will hold the results of the formulas during the simulation. RunCount jus tells us which cycle we are currently in. finally, SimulatioRuns is the array that will hold results of the simulation for each run.

The next step in our simulation will be to setup the initial data and variables. Basically.The agressive factor will be asimple randomly generated value from 0 to 1. The starting numbers of predator and preys will be what the user needs to enter into the system. and we'll also initialize the first element in our array to hold the initial data entered by the user.

' --------------------------------------------
'  Set up all initial data for the simulation
' --------------------------------------------
RANDOMIZE TIMER
RunCount        = 1
AgressiveFactor = RND(1)
' ------------------------------------
'  Inquire for the initial population
' ------------------------------------
INPUT "Enter the number of Predators: "; NumberOfPredators
INPUT "Enter the number of Preys:     "; NumberOfPreys
' -------------------------------------------------------
'  Prepare the array for it's initial data and assign it
' -------------------------------------------------------
REDIM SimulationRuns(1 TO RunCount) AS SimulationData
SimulationRuns(RunCount).CycleNumber          = RunCount
SimulationRuns(RunCount).TimeMark             = 0
SimulationRuns(RunCount).TotalPopulation      = NumberOfPredators + NumberOfPreys
SimulationRuns(RunCount).PopulationDifference = 0
SimulationRuns(RunCount).PredatorCount        = NumberOfPredators
SimulationRuns(RunCount).DifferencePredators  = 0
SimulationRuns(RunCount).PercentagePredators  = NumberOfPredators * 100 / TotalPopulation
SimulationRuns(RunCount).PreyCount            = NumberOfPreys
SimulationRuns(RunCount).DifferencePreys      = 0
SimulationRuns(RunCount).PercentagePreys      = NumberOfPreys * 100 / TotalPopulation
     

At this point we are ready to run the simulation itself. Remember that if we run out of predators or preys the simulation will stop since both are needed for the simulation to work. So it won't be a loop where we know how many times will will be looping. As such we will have to loop while neither of them is 0. The important thing to note in this next code section is the two formulas that calculate the number of population for predators and preys.

' ----------------------
'  Main Simulation Loop
' ----------------------
DO WHILE NumberOfPredators > 1 AND NumberOfPreys > 1
   ' ---------------------------------
   '  We first Increment the RunCount
   ' ---------------------------------
   RunCount = RunCount + 1
   ' -----------------------------------------------------------
   '  Next we calculate the new populations
   '  Note you can play with these formulas to see what happens
   ' -----------------------------------------------------------
   NumberOfPredators = NumberOfPredators + _
                       ((8 * NumberOfPredators - _
                             NumberOfPredators * NumberOfPreys / 3) * _
                             AggressiveFactor )
   NumberOfPreys     = NumberOfPreys + _
                       ((4 * NumberOfPreys - _
                             NumberOfPreys * NumberOfPredators ) * 0.01
   TotalPopulation   = NumberOfPredators + NumberOfPreys
   ' --------------------------------------
   '  Next we add the results to our array
   ' --------------------------------------
   SimulationRuns(RunCount).CycleNumber          = RunCount - 1
   SimulationRuns(RunCount).TimeMark             = RunCount - 1
   SimulationRuns(RunCount).TotalPopulation      = NumberOfPredators + NumberOfPreys
   SimulationRuns(RunCount).PopulationDifference = SimulationRuns(RunCount -1).TotalPopulation + _
                                                   ( NumberOfPredators + NumberOfPreys )
   SimulationRuns(RunCount).PredatorCount        = NumberOfPredators
   SimulationRuns(RunCount).DifferencePredators  = SimulationRuns(RunCount - 1).PredatorCount - _
                                                   NumberOfPredators
   SimulationRuns(RunCount).PercentagePredators  = NumberOfPredators * 100 / TotalPopulation
   SimulationRuns(RunCount).PreyCount            = NumberOfPreys
   SimulationRuns(RunCount).DifferencePreys      = SimulationRuns(RunCount - 1).PreyCount - _
                                                   NumberOfPreys
   SimulationRuns(RunCount).PercentagePreys      = NumberOfPreys * 100 / TotalPopulation
LOOP
     

We're nearing the end of the code right now. The next small part is to adjust the LongestRun variable if the current simulation ran for more cycles than any previous one. This is done with the following simple piece of code:

   ' ---------------------------------
   '  Adjust The Longest Run Variable
   ' ---------------------------------
   IF RunCount > LongestRun THEN
      LongestRun = RunCount - 1
   END IF
   

The next step is displaying the simulation report to the user. We'll start by clearing the screen. We will then display the report header and initial data for the current simulation. Here is the code to do that:

   ' -------------------------------
   '  Display The Simulation Report
   ' -------------------------------
   CLS
   ' ---------------------------
   '  Display The Report Header
   ' ---------------------------
   PRINT "   ========================================================================="
   PRINT "                       S I M U L A T I O N   R E P O R T"
   PRINT "   ========================================================================="
   PRINT
   PRINT "                   Aggressiveness Factor.......: ";
   PRINT USING "###.#####"; AggressiveFactor
   PRINT "                   Initial Predator Population.: ";
   PRINT USING "    #,###"; INT(SimulationRuns(1).PredatorCount)
   PRINT "                   Initial Prey Population.....: ";
   PRINT USING "    #,###"; INT(SimulationRuns(1).PreyCount)
   PRINT
   

We'll follow that with the printing of the column headers of the report. In this case everything is already adjusted to line up the values with the column headers. If you were to write your own reporting section. It would be good to give it a few runs to make sure everything is ligned up so the report looks good. Here is the code for the displaying of the column headers for the report.

   ' ----------------------------
   '  Display The Column Headers
   ' ----------------------------
   PRINT "   ========================================================================="
   PRINT "    CYCLE      TOTAL      PREDATORS          PREYS            PERCENTAGES
   PRINT "    COUNT POPULATION  TOTAL DIFFERENCE  TOTAL DIFFERENCE  PREDATORS   PREYS
   PRINT "   -------------------------------------------------------------------------"
   

Next comes the loop that will go through the elements of the SimulationRuns array to display each of the results in the report. As you can see here I am using the PRINT USING statement to keep all numbers right justified. I think right justifying numbers in a report helps the report look clean and that much more readable since we are reading numbers. Here is the code for this loop.

   ' -----------------------------------------------
   '  Loop through the array to display the results
   ' -----------------------------------------------
   FOR Counter = 1 TO UBOUND(SimulationRuns)
       PRINT USING "    ##### ";Counter - 1;
       PRINT USING "     ##### "; SimulationRuns(Counter).TotalPopulation;
       PRINT USING " ##### "; SimulationRuns(Counter).PredatorCount;
       PRINT USING "     ##### "; SimulationRuns(Counter).DifferencePredators;
       PRINT USING " ##### "; SimulationRuns(Counter).PreyCount;
       PRINT USING "     ##### "; SimulationRuns(Counter).DifferencePreys;
       PRINT USING "   ###.##%"; SimulationRuns(Counter).PercentagePredators;
       PRINT USING " ###.##% "; SimulationRuns(Counter).PercentagePreys
   NEXT Counter
   PRINT "   ========================================================================="
   PRINT
   

Finally, the last thing to do is display the longest run to date to the user and simply ask them if they want to run another simulation. Answering Y to this question will keep the Agressiveness Factor the same which will give the user the ability to test different population values for this particular aggressiveness factor to see how long they can keep the simulation going. Here's the final piece of code.

   ' --------------------------------------------
   '  Display The Longest Simulation Run To Date
   ' --------------------------------------------
   PRINT "   The sest simulation, so far, ran for " + STR$(LongestRun) + " cycles."
   PRINT
   ' --------------------------------------------------
   '  Enter Loop To Inquire for another Simulation Run
   ' --------------------------------------------------
   DO WHILE Answer = "" OR (UCASE$(Answer) <> "Y" OR UCASE$(Answer) <> "N")
      INPUT "   Run another simulation? (Y/N) "; Answer
      IF UCASE$(Answer) = "N" THEN
         CanExitSimulation = -1
      END IF
   LOOP
LOOP
     

And there you have it. Our program is over and ready to execute. As you can see, the code itself isn't all that complicated in this project. Everything really revolves around the agressiveness factor and the two formulas to calculate the new population for the predators and the preys. The rest of the program is essentially book keeping work.

Sample Simulation Executions:

Ok, now that we have our program it's time to give it a first test run. I compiled the program and executed it. It gave me an aggressiveness factor of 0.16597 and asked me for the number of predators and number of preys. In this first run, I entered 30 predators and 30 preys, a nice round number for starting a simulation. Here is the simulation report that it gave me:

   =========================================================================
                       S I M U L A T I O N   R E P O R T
   =========================================================================

                    Aggressiveness Factor.......:   0.16597
                    Initial Predator Population.:        30
                    Initial Prey Population.....:        30

   =========================================================================
    CYCLE      TOTAL      PREDATORS          PREYS            PERCENTAGES
    COUNT POPULATION  TOTAL DIFFERENCE  TOTAL DIFFERENCE  PREDATORS   PREYS
   -------------------------------------------------------------------------
        0         60     30          0     30          0     50.00%  50.00%
        1         45     20         10     25          5     44.31%  55.69%
        2         40     19          1     21          4     46.58%  53.42%
        3         39     21         -3     18          4     54.58%  45.42%
        4         42     29         -7     13          4     68.23%  31.77%
        5         53     46        -17      8          6     85.38%  14.62%
        6         88     86        -41      1          6     98.44%   1.56%
        7        193    195       -108     -1          3    100.64%  -0.64%
   =========================================================================

The best simulation, so far, ran for 7 cycles.

Run another simulation? (Y/N) ?
     

What this report mean? Let's take a look in details. We can see that for the first two cycles the population of predators was going down and so was the population of preys (but as you can see, the prey population went down continuously throughout the whole run of this simulation. At the third cycle the number of preys was abundant enough for the predators to reproduce (according to their aggressiveness factor) which turned the tables around and began augmenting the predator population. More predators need more preys to eat in order to survive and that's exactly what they did and you can see that by the increased drop in population of preys quantity. At the end of the simulation, all the preys vanished which means that the predators eventually died of starvation.

I then answered yes because I wanted to run another simulation (with the same aggressiveness factor). In this second run I entered 20 predators and 30 preys just to see what would happen. What do you believe would happen in tis second simulation? Well, let's have a look at the simulation report that got generated from this second run:

   =========================================================================
                       S I M U L A T I O N   R E P O R T
   =========================================================================

                    Aggressiveness Factor.......:   0.16597
                    Initial Predator Population.:        20
                    Initial Prey Population.....:        30

   =========================================================================
    CYCLE      TOTAL      PREDATORS          PREYS            PERCENTAGES
    COUNT POPULATION  TOTAL DIFFERENCE  TOTAL DIFFERENCE  PREDATORS   PREYS
   -------------------------------------------------------------------------
        0         50     20          0     30          0     40.00%  60.00%
        1         41     13          7     27          3     32.95%  67.05%
        2         36     11          2     25          2     30.32%  69.68%
        3         34     10          1     24          2     30.11%  69.89%
        4         33     10         -0     22          2     31.86%  68.14%
        5         32     11         -1     21          2     35.70%  64.30%
        6         32     14         -2     19          2     42.23%  57.77%
        7         34     18         -4     16          3     52.38%  47.62%
        8         38     25         -8     13          3     66.84%  33.16%
        9         49     41        -16      8          5     84.01%  15.99%
       10         80     78        -37      2          6     97.48%   2.52%
       11        172    174        -95     -1          3    100.82%  -0.82%
   =========================================================================

The best simulation, so far, ran for 11 cycles.

Run another simulation? (Y/N) ?
     

First thing you'll notice is that the second simulation ran four cycles longer than the first one. Is that what you anticipated would happen or did it go completely against what you were originally thinking? As you can see here, it wasn't until the 5th cycle than the predator population started to rise thus eating more and more preys bringing them right down to their extinction. You can finally also notice that once the predator population started to rise, that it took more cycles than before to eat up all the preys. What does all this tell you? That the right balance of preys predator can help with the existence of both (not just the predators per se).

How Things Could Be Done Differently

There are, of course, many things that we could have coded differently. This is, after all, a very simplified simulation model. Let's take a look at three of the things that we could have done differently.

  • The Aggressiveness Factor:
    This is currently a randomly generated value between 0 and 1. We could have used a completely different evaluation of this value. for example, if we know that tigers eat 5 rabbits per cycle, we could have entered that in data statements instead so we could offer a list of predators to use in the simulation. We could have done the same thing for the preys too.

  • The Population Calculation Formulas:
    The formulas used in the simulation loop I found on the Internet somewhere. they are rather straightforward as they are. You can experiment, as I stated, with the values in the formulas to see what happens with the simulation. You could also create some decay values based on predator type and and prey type and start calculations from there to see how differently things run. This is currently a randomly generated value between 0 and 1. We could have used a completely different evaluation of this value. for example, if we know that tigers eat 5 rabbits per cycle, we could have entered that in data statements instead so we could offer a list of predators to use in the simulation. We could have done the same thing for the preys too.

  • More Elements To The Scene:
    We know that predators eat the preys. But we have no consideration on the food supplies of the preys in this example. Adding this could also influence the outcome of simulation. We could have, depending on the animal type, add a factor where the predator would eat it's own kind if they run out of preys. Of course, we could have added different kinds of predators and preys with different configurations for each to see what could happen then. The possibilities are endless when you think about it.

In essence, everything depends on what you are simulating, Which group of simulation it falls under and of course how close to the real world you want it (or need it) to be. In the case of flight simulators aimed at training future pilots, you would typically want that simulation to be as close as possible to the real thing. And you'd also want a whole like of unpredictable factors to come into play of the future pilot's training (like landing on a bridge in the middle of a hurricane for example) if that's what it takes to keep the crew and passengers alive, wouldn't you be glad that he got that in his training? I thought so.

And For The Final Word

With this tutorial I really only touched the very tip of the iceberg. It's surprising how complex simulations can get no matter which group of simulations they fall under. Now if you were to make a simulation like the one shown here, it depends a little bit of planning ahead. But, if you are looking at making a full fledged flight simulator, It would of course be highly recommended that you sit down for a while and get a lot of initial data and formulas before even starting to code.

I'm always open to discussions and suggestions about this or any of my other tutorials. If you have ideas and suggestion for possibly a 2nd part to this tutorial, feel free to let me know about it. Simulation can go in all directions, on all types of subjects and to all degrees of complexity. So the sky really is the limit as far as simulation goes. So i am open to new ideas all the time. Until next time, I hope this tutorial was clear, but if you have a question, don't hesitate to ask me. Until next time, Happy reading, coding and in this case, happy simulating.

Basic4GL Tutorial; Tile Maps: by Linkage


So, you know how to use sprites, and want to make your own 2D game. But most of the time, such a game will require a level to move around, and you're not sure how to make it. You COULD make it one big sprite, or heaps of sprites put together, but that'd be annoying, and would probably slow the game down.

So what's a good way to make levels? Tile Maps.

Tile Maps are very similar to sprites, but are generally meant to be bigger. and don't require making a huge sprite. Instead, you take a picture that has multiple segments, referred to as tiles, and take each segment and place them where you want, kind of like a puzzle. This way, we can make a map using as little as 2 tiles.

So how do we make these Tile Maps? This tutorial will show you how, providing sample code and explanations of how it works to give you a good understanding of them. You don't really need to know too much about Basic4GL to get through this tutorial, but an understanding of the main basic things such as loops, variables etc. Is required.

OK, so here we go. First, we need a picture to use as our tiles. For now, we'll just use a very simple one, with only 2 tiles.

Here it is:

you'll need to save this picture into whatever directory you're running the finished program from.

As you can see, it's just divided into black and white sections. Seeing as the default background for Basic4GL programs is black, we're going to use the white area to show where something is, and the black area for blank space.

Now, we're going to write a section of code that we'll use later on to tell Basic4GL how to distribute the tiles for the Tile Map. For this we use a data table:

TileData:
    data 9,5
    data 1,1,1,1,1,1,1,1,1
    data 1,0,0,0,0,0,0,0,1
    data 1,0,0,0,0,0,0,0,1
    data 1,0,0,0,0,0,0,0,1
    data 1,1,1,1,1,1,1,1,1

If you've never seen the data command before, it is basically used to tell Basic4GL that anything after it is going to be read into the program later and used accordingly.

Now, from looking at the data there, we can see the general shape of a room, visualising the 1s as white space and the 0s as black space. It is useful when using data tables for tile maps to keep all the numbers aligned, so it makes it easier to see in the numbers your map. However, when you start using pictures with an amount of tiles that goes into double digits, they may become unaligned and harder to visualise. It's obviously not very good to restrict the variety of a tile map simply so that you can code it easier, so you'll have to either put up with it or leave the first 10 spaces blank, so that all of the tiles will have double digits (and if you go into triple digits, well... that's one big Tile Map!).

Also, you may be wondering why we have the 9 and the 5 up the top. We're going to use that laster to help tell the program just how much data to read.

Now, we have to actually store that data into a variable so that we can use it. For that we have to dim a few variables and go through a certain subroutine:

dim &tiles ()(), mapx, mapy, i, x, y

LoadTiles:
    read mapx, mapy
    alloc tiles, mapx -1, mapy - 1
    for y = 0 to mapy - 1
        for x = 0 to mapx - 1
            read i
            tiles (x)(y) = i
        next
    next
    return

You're probably a bit puzzled as to how this works, so I'll explain it bit by bit.

First, we dim a pointer variable. I don't know much about pointer variables, so I can't go into a proper explanation of them (although anyone who can and is willing to contribute one to this tutorial... please go ahead), but they must be dimmed with a & at the start, and the type we are dimming, which is going to have a 2D array of numbers, must have a ()() at the end. The other variables we are dimming are all integer variables.

OK, now to the more confusing bits. First, we use read. Read does more or less what it says- it reads data, starting from the top, and assigns the values it reads to the variables told. So in this case, it first reads the data 9, and assigns it to mapx, and then the 5, and assigns it to mapy. So now mapx = 9 and mapy = 5.

Then, we use alloc. We use this to allocate the values of mapx 1 and mapy 1 to the array dimensions of &tiles. So now, &tiles has the dimensions of (8) and (4). This means that it is divided up into 8 sections, each with 4 values.

Now we use two for loops to read the rest of the data. Because when we go through the first loop the first time, it executes all of the second for loop, in which it reads the next piece of data into i, and ends up doing that instruction the amount of times equal to 8 times 4, which equals 32. So that way, we get it to read all of the data we put in. Also in the second for loop is an instruction to make tiles (x)(y) equal the current value of i. So we end up storing all of our data values into tiles, which we will now use to make the actual map appear. So after that code we place this:

MakeMap:
    tilemap = LoadImageStrip("basictiles.png", 32)
    gosub LoadTiles
    map = NewTileMap(tilemap)
    SprSetYRepeat(false)
    SprSetXRepeat(false)
    SprSetTiles(tiles)

And we add some more variables to our dim statement:

dim &tiles ()(), mapx, mapy, i, x, y, tilemap(1), map

And one line of code after that dim statement:

goto MakeMap

To end up with a working program, which is this:

TileData:
    data 9,5
    data 1,1,1,1,1,1,1,1,1
    data 1,0,0,0,0,0,0,0,1
    data 1,0,0,0,0,0,0,0,1
    data 1,0,0,0,0,0,0,0,1
    data 1,1,1,1,1,1,1,1,1

dim &tiles ()(), mapx, mapy, i, x, y, tilemap(1), map

goto MakeMap

LoadTiles:
    read mapx, mapy
    alloc tiles, mapx -1, mapy - 1
    for y = 0 to mapy - 1
        for x = 0 to mapx - 1
            read i
            tiles (x)(y) = i
        next
    next
    return

MakeMap:
    tilemap = LoadImageStrip("basictiles.png", 32)
    gosub LoadTiles
    map = NewTileMap(tilemap)
    SprSetYRepeat(false)
    SprSetXRepeat(false)
    SprSetTiles(tiles)

So, if you run that, you can see the results, but first let me explain how the code we added works:

MakeMap:
    tilemap = LoadImageStrip("basictiles.png", 32)
    gosub LoadTiles
    map = NewTileMap(tilemap)
    SprSetYRepeat(false)
    SprSetXRepeat(false)
    SprSetTiles(tiles)

This area first assigns the variable tilemap the Image Strip of our tile picture. Then, we use gosub, which tells the program to skip to another labelled area of the program and run the code from there until it hits a return command, at which point it goes back to where it was. In this case, it sends it to the LoadTiles subroutine, where all the values of &tiles are set. Then, we use NewTileMap to make map a Tile Map, with the tiles in tilemap. SprSetXRepeat and SprSetYRepeat stop the map from being continuously displayed in both X and Y directions. Then we use SprSetTiles to set the map's tiles to those indicated in &tiles, at which point it displays it.

So, hopefully this tutorial has given you a good understanding of how to make Tile Maps. If not, let me know and I'll either try and address your questions personally or edit the tutorial to fit your needs. The most common thing I could think of is that maybe my explanations in some parts were a bit vague/confusing.

I'm also planning on making another one or two tutorials to do with Tile maps, such as collision detection with them.

EXTENSION: Loading Multiple Tile Maps

Loading multiple Tile Maps is not much different from loading a single tile map. For our example, we are simply going to add a second data table and make some changes to the section of code that makes the maps. Here's the second data table:

TileData2:
    data 7, 4
    data 1,1,1,1,1,1,1
    data 1,0,1,0,1,0,1
    data 1,0,1,0,1,0,1
    data 1,1,1,1,1,1,1

You should place that under the previous data table.

And here's the changes we need to make to the part that makes the maps:

MakeMap:
    tilemap = LoadImageStrip("basictiles.png", 32)
    reset TileData
    gosub LoadTiles
    map(0) = NewTileMap(tilemap)
    SprSetYRepeat(false)
    SprSetXRepeat(false)
    SprSetTiles(tiles)
    reset TileData2
    gosub LoadTiles
    map(1) = NewTileMap(tilemap)
    SprSetXRepeat(false)
    SprSetYRepeat(false)
    SprSetTiles(tiles)
    SprSetPos(300,100)

We also need to slightly change part of our dim statement, too, so that map looks like map(1).

So, what difference has our changes made? If you've run that, you'll see that it displays two Tile Maps in different sections of the screen. We do this by, apart from adding a second section to make a map, by adding in the reset function. The reset function resets the spot from which the program will read data to the label you tell it to. This is useful when you need the program to read sections of data from different places in the program. In this particular program, it's not actually necessary, but in proper 2D games it's important to have it before every time you run the LoadTile routine, as you will probably end up having to read certain sections of data multiple times. So by placing these commands in front of every time you run the LoadTiles routine, we make sure that the data we want to be read is read.

There is also one more function at the end of the program: SprSetPos. This just moves our second tile map to the designated position on screen, so we can see both at the same time.

Some changes that could be made to this program is to, while having multiple tile maps, to only display one at a time. Apart from a small section to decide which one to display, it's also good to add in some more pointer variables, so that rather than having multiple map-making sections, we only add an if statement to the section that sets its tiles. For this we'd have to add a line to, with the new pointer variables, set the pointer variable you want to mirror the current &tiles after each LoadTiles routine. But, I'll let you give that a try for yourself.

Introduction to the FreeBasic Extended Types: by Rick D. Clark


INTRODUCTION:

FreeBasic is moving towards implementing Object Oriented programming. While classes have not yet been added to the language, the Type definition has been extended to include some Object Oriented constructs as a first step towards full class support. This article introduces some of the concepts of Object Oriented design and explains some of the extended type constructs.

GETTING STARTED:

In order to use the new type constructs, you will need to download the CVS version of the compiler; Windows, Linux or DOS. You select the large version if you are updating for the first time. If you have not done so, download and install the last stable .17 release that you will find on the FreeBasic download page. Once .17 is installed, then unpack the CVS version in the same install folder, overwriting all files.

OBJECT ORIENTED PROGRAMMING:

Object Oriented Programming, usually shortened to OOP, is a methodology that enables the programmer to build code units called objects. An object is a thing; it is a unit of code that represents something that needs to be manipulated in a program. You can think of an object as a noun: a person, place or thing. An object could be a sprite, a drawing primitive or something more elaborate like a tank in a game. Any concrete entity that has a set of characteristics and actions can be represented as an object.

An object contains both the data needed by the object, and the methods (subroutines and functions) that act on the data. This grouping of data and methods into a single entity is called encapsulation. Encapsulation allows you to create modular units that can be reused in multiple programs. This idea of code reuse was the main motivation in the creation of the OOP paradigm.

Another beneficial consequence of encapsulation is information hiding. The data inside the object is shielded from the outside world so that unwanted changes to the data cannot occur. Instead of accessing a variable directly, the object has a public interface that the external program should use to access and change data members. By using an interface, you can control how the object behaves and ensure that its operation is consistent across many programs.

The interface also allows you to make internal changes to the code, without changing the way the object is accessed. As long as you don’t change the published interface, that is change any existing public methods, you can improve the object without breaking any existing code that relies on the object. In the cases where a program my need an improved method, you can leave the old method in place to maintain compatibility, and just add a new method with the improved functionality. New programs can use the new method, while old programs can still use the old method.

Another advantage of using a public interface is so that other programmers can use your object without worrying about the internal details of the object. As long as the published interface is stable and well documented, anyone should be able to use your object, even beginners.

THE PUBLISHED CONTRACT:

As already stated, OOP was designed to enable code reuse among programmers. In order for code reuse to be helpful, the published interface must remain stable. That is, once an object has been released and is being used in programs, the published interface should not change so that programs that use the object continue to work correctly. There is an implicit contract between you as the author of the object and the end-user of your object that you will maintain the published interface across changes that may need to be made to the object. This implicit contract between author and user is the main strength of the OOP paradigm, and is the main reason that OOP has become such a powerful programming methodology.

THE CHARACTERISTICS OF AN OBJECT:

As already mentioned, an object contains both data and methods. The data describes the properties of an object, while the methods describe what the object can do. A simple, and not-really-useful example will illustrate this concept.

Suppose you want to create an object that draws a rectangle on the screen. A rectangle can have several properties that would be contained within the data members of the object. A rectangle has an origin on the screen, normally the top left corner, which can be represented by x and y data members. A rectangle has a width and a height, so the object would have width and height data members. A rectangle can either be outlined or filled, so a filled flag data member can be added to the object. Of course, if you are going to draw a rectangle, you will want to draw it in a particular color, so the object will need to have a color data member, and to have the object be a bit more flexible, you can add a color member for the outline and a different color member for the fill. Of course you will need a method to actually draw the rectangle on the screen, so you can add a draw routine to the object definition.

So our rectangle object has the following preliminary properties and methods:

  • Property: x and y origin
  • Property: width
  • Property: height
  • Property: filled
  • Property: outline color
  • Property: fill color
  • Method: DrawRectangle
This list is called the object definition. In FreeBasic you define an object using the extended Type definition. The extended Type is similar to the standard Type, with some added language constructs that implements a subset of OOP features.

A RECTANGLE TYPE DEFINITION:

The following code snippet is a partial rectangle definition:

Type myRect
	Private:
	X As Integer
	Y As Integer
	Width As Integer
	Height As Integer
	Filled As Integer
	Otlncolor As Integer
	Fillcolor As Integer

	Public:
	Declare Sub DrawRect()
End Type

As you can see, the extended Type looks much like a standard Type except for the Private: and Public: keywords and the sub declaration. The Private: keyword tells the compiler that the data members that follow are private to the type, that is cannot be accessed outside of the type. The private state extends to all object members until a new qualifier is encountered, which in this case is the Public: qualifier just above the Sub declaration. All of the data members are hidden from the outside world and cannot be changed from outside the scope of the Type, a process called information hiding.

Information hiding is a way to maintain the integrity of the object. You should never allow an outside process to directly access a data member. All data access should be through the use of Property members so that you can control what is being passed to your object. Strict control over your object’s data will help prevent many errors that may occur when a programmer uses your object.

Type myRect
	Private:
	X As Integer
	Y As Integer
	Width As Integer
	Height As Integer
	Filled As Integer
	Otlncolor As Integer
	Fillcolor As Integer

	Public:
	Declare Sub DrawRect()
	Declare Property SetX(Byval xx As Integer)
	Declare Property GetX() As Integer
	Declare Property SetY(Byval yy As Integer)
	Declare Property GetY() As Integer
	Declare Property SetWidth(Byval w As Integer)
	Declare Property GetWidth() As Integer
	Declare Property SetHeight(Byval h As Integer)
	Declare Property GetHeight() As Integer
	Declare Property SetFilled(Byval f As Integer)
	Declare Property GetFilled() As Integer
	Declare Property SetOtlncolor(Byval oc As Integer)
	Declare Property GetOtlncolor() As Integer
	Declare Property SetFillColor(Byval fc As Integer)
	Declare Property GetFillColor() As Integer
End Type

The Declare statements following the Public: qualifier comprises the public interface to your object. Since the variables of the type are defined with the Private: keyword, the only way to access the variables is through the Property members. Each variable has a corresponding Set* and Get* property that sets and returns the variable values. While this may seem to be a lot of code for such a simple object, Property members protects the integrity of the object. Since you define the code in each Property member, you have full control over what is being put into your object. If you allowed unrestricted access to your data members, you would lose that control, and lose the integrity of the object.

In this example, the variables can be both written and read. To create a write-only variable you would add just a Set property. To add a read-only variable, you would just create a Get property. The names of the Property members are not reserved; you can name them anything you want, but using Get and Set or Write and Read in the Property name will document what the property does.

CREATINF WELL-BEHAVED OBJECTS:

The definition looks complete at this point, but there is a problem. What would happen if some or all of the variables were not initialized? The object would not perform correctly and potentially generate a runtime error. It would be better to have a set of default values for the object variables just in case one or more variables did not get initialized. You can initialize the object at the moment of creation by using a Constructor.

A Constructor is a subroutine that is called when the object is created using the Dim (or New) statement. Constructors are useful for initializing an object, either with default values, or values you pass to the Constructor. The updated type definition now looks like the following:

Type myRect
  	Private:
	X As Integer
	Y As Integer
	Width As Integer
	Height As Integer
	Filled As Integer
	Otlncolor As Integer
	Fillcolor As Integer

	Public:
	Declare Sub DrawRect()
	Declare Property SetX(Byval xx As Integer)
	Declare Property GetX() As Integer
	Declare Property SetY(Byval yy As Integer)
	Declare Property GetY() As Integer
	Declare Property SetWidth(Byval w As Integer)
	Declare Property GetWidth() As Integer
	Declare Property SetHeight(Byval h As Integer)
	Declare Property GetHeight() As Integer
	Declare Property SetFilled(Byval f As Integer)
	Declare Property GetFilled() As Integer
	Declare Property SetOtlncolor(Byval oc As Integer)
	Declare Property GetOtlncolor() As Integer
	Declare Property SetFillColor(Byval fc As Integer)
	Declare Property GetFillColor() As Integer
	Declare Constructor()
	Declare Constructor(xx As Integer, yy As Integer, w As Integer, _
                        h As Integer, f As Integer, oc As Integer, _
                        fc As Integer)
                        
End Type

You will notice in the definition that we have two Constructors, one that takes a set of parameters and one that doesn’t. This is called overloading and can be used not only with Constructors but also with other subroutines and functions. Overloading is useful for situations where you need to handle different parameter types with a single method call. The compiler will determine which method to call based on the parameters passed to the method. You can overload as many methods as you want, as long as the number and type of parameters for each method is unique.

In this instance, if the Constructor is not passed any parameter values, it will initialize the variables to a set of default values. If the Constructor is called with parameters, then it will use the passed values to initialize the object’s variables.

There is also a Destructor method that is called when the object is destroyed. You can use the Destructor to perform any cleanup tasks that must be carried out before the object is released from memory. If the object created any pointer references, or opened any files, then you would clean up those references in the Destructor. Since the Rectangle object doesn’t create any outside references, a Destructor is not needed.

FILLING IN THE OBJECT METHODS:

The type definition is a template for the object type and tells the compiler how to set up the object in memory. However, in order to actually use the object, you need to create the actual method calls, which is shown in the next listing.

Type myRect
	Private:
	X As Integer
	Y As Integer
	Width As Integer
	Height As Integer
	Filled As Integer
	Otlncolor As Integer
	Fillcolor As Integer

	Public:
	Declare Sub DrawRect()
	Declare Property SetX(Byval xx As Integer)
	Declare Property GetX() As Integer
	Declare Property SetY(Byval yy As Integer)
	Declare Property GetY() As Integer
	Declare Property SetWidth(Byval w As Integer)
	Declare Property GetWidth() As Integer
	Declare Property SetHeight(Byval h As Integer)
	Declare Property GetHeight() As Integer
	Declare Property SetFilled(Byval f As Integer)
	Declare Property GetFilled() As Integer
	Declare Property SetOtlncolor(Byval oc As Integer)
	Declare Property GetOtlncolor() As Integer
	Declare Property SetFillColor(Byval fc As Integer)
	Declare Property GetFillColor() As Integer
	Declare Constructor()
	Declare Constructor(xx As Integer, yy As Integer, w As Integer, _
                        h As Integer, f As Integer, oc As Integer, _
                        fc As Integer)
                        
End Type

	Sub myRect.DrawRect()
	Line (x, y)-(x + Width - 1, y + height - 1), Otlncolor
		If Filled <> 0 Then
    		Paint (x + 1, y + 1), Fillcolor, Otlncolor
		End If   
	End Sub

	Property myRect.Setx(Byval xx As Integer)
		x = xx
	End Property

	Property myRect.Getx() As Integer
		Return x
	End Property

	Property myRect.Sety(Byval yy As Integer)
		y = yy
	End Property

	Property myRect.Gety() As Integer
 		Return y
	End Property

	Property myRect.SetWidth(Byval w As Integer)
		Width = w
	End Property

	Property myRect.GetWidth() As Integer
		Return Width
	End Property

	Property myRect.SetHeight(Byval h As Integer)
		Height = h
	End Property

	Property myRect.GetHeight() As Integer
		Return Height
	End Property

	Property myRect.SetFilled(Byval f As Integer)
		Filled = f
	End Property

	Property myRect.GetFilled() As Integer
		Return Filled
	End Property

	Property myRect.SetOtlncolor(Byval oc As Integer)
		Otlncolor = oc
	End Property

	Property myRect.GetOtlncolor() As Integer
		Return Otlncolor
	End Property

	Property myRect.SetFillColor(Byval fc As Integer)
		Fillcolor = fc
	End Property

	Property myRect.GetFillColor() As Integer
		Return Fillcolor
	End Property

	Constructor myRect
		X = 0
		Y = 0
		Width = 10
		Height = 10
		Filled = 0  
		Otlncolor = 15
		Fillcolor = 7
	End Constructor

	Constructor MyRect (xx As Integer, yy As Integer, w As Integer, _
                        h As Integer, f As Integer, oc As Integer, _
                        fc As Integer)

		X = xx
		Y = yy
		Width = w
		Height = h
		Filled = f  
		Otlncolor = oc
		Fillcolor = fc
	End Constructor

The Methods and Properties are defined using the Sub/Function/Property methodname.TypeName syntax. This tells the compiler how to match up methods with the proper type definition. The Constructors are defined with the type name for the same reason.

USING YOUR OBJECT:

The object is now complete can be used in a program which is listed below.

Type myRect
	Private:
	X As Integer
	Y As Integer
	Width As Integer
	Height As Integer
	Filled As Integer
	Otlncolor As Integer
	Fillcolor As Integer

	Public:
	Declare Sub DrawRect()
	Declare Property SetX(Byval xx As Integer)
	Declare Property GetX() As Integer
	Declare Property SetY(Byval yy As Integer)
	Declare Property GetY() As Integer
	Declare Property SetWidth(Byval w As Integer)
	Declare Property GetWidth() As Integer
	Declare Property SetHeight(Byval h As Integer)
	Declare Property GetHeight() As Integer
	Declare Property SetFilled(Byval f As Integer)
	Declare Property GetFilled() As Integer
	Declare Property SetOtlncolor(Byval oc As Integer)
	Declare Property GetOtlncolor() As Integer
	Declare Property SetFillColor(Byval fc As Integer)
	Declare Property GetFillColor() As Integer
	Declare Constructor()
	Declare Constructor(xx As Integer, yy As Integer, w As Integer, _
                        h As Integer, f As Integer, oc As Integer, _
                        fc As Integer)
                        
End Type

	Sub myRect.DrawRect()
		Line (x, y) - (x + Width, y + height), Otlncolor, B
		If Filled <> 0 Then
    		Paint (x + 1, y + 1), Fillcolor, Otlncolor
		End If   
	End Sub

	Property myRect.Setx(Byval xx As Integer)
		x = xx
	End Property

	Property myRect.Getx() As Integer
		Return x
	End Property

	Property myRect.Sety(Byval yy As Integer)
		y = yy
	End Property

	Property myRect.Gety() As Integer
 		Return y
	End Property

	Property myRect.SetWidth(Byval w As Integer)
		Width = w
	End Property

	Property myRect.GetWidth() As Integer
		Return Width
	End Property

	Property myRect.SetHeight(Byval h As Integer)
		Height = h
	End Property

	Property myRect.GetHeight() As Integer
		Return Height
	End Property

	Property myRect.SetFilled(Byval f As Integer)
		Filled = f
	End Property

	Property myRect.GetFilled() As Integer
		Return Filled
	End Property

	Property myRect.SetOtlncolor(Byval oc As Integer)
		Otlncolor = oc
	End Property

	Property myRect.GetOtlncolor() As Integer
		Return Otlncolor
	End Property

	Property myRect.SetFillColor(Byval fc As Integer)
		Fillcolor = fc
	End Property

	Property myRect.GetFillColor() As Integer
		Return Fillcolor
	End Property

	Constructor myRect()
		X = 10
 		Y = 10
		Width = 100
		Height = 100
		Filled = 0  
		Otlncolor = 14
		Fillcolor = 0
	End Constructor

	Constructor MyRect (xx As Integer, yy As Integer, w As Integer, _
                        h As Integer, f As Integer, oc As Integer, _
                        fc As Integer)

		X = xx
		Y = yy
		Width = w
		Height = h
		Filled = f  
		Otlncolor = oc
		Fillcolor = fc
	End Constructor

	'Create a graphic screen
	Screen 18

	'Create an object using the default constrcutor
	Dim aRect As myRect
	'Create an object by explicitly setting the constructor values
	Dim bRect As myRect = myRect(200, 200, 200, 100, 1, 15, 9)

	'Draw the rectangles on the screen
	aRect.DrawRect
	bRect.DrawRect

	'Update aRect properties
	aRect.SetX = 90
	aRect.SetY = 20
	aRect.SetFilled = 1
	aRect.SetFillColor = 15

	'Draw new rect
	aRect.DrawRect
	Sleep
	End

To initialize the object using the default Constructor, you simply Dim the extended Type just as you would the standard type. If the Constructor only takes a single value then you can use the Dim var as Typename = value syntax. To initialize the object with a set of values, you Dim the type and then use the = typename(par1m parm1…) syntax. You can see that accessing the members of the object is just like accessing the member of a standard type.

In this tutorial, you saw how to define, create and use the new OOP features of the extended Type. Objects are a great way to create reusable code units, and provide a way to make your programs easier to manage and much less prone to errors. When FreeBasic has Classes, you will be able to transfer this knowledge to the Class object and be able to add even more functionality to your programs.

Simulating Polymorphic Methods Using FreeBasic Extended Types: by Rick D. Clark


Introduction:

Polymorphism is a powerful tool in object-oriented program. A polymorphic method (Sub or Function) behaves differently depending on the definition of the object. For example, an animal object may have a speak method that will issue a bark for a dog and a meow for a cat. FreeBasic doesn’t yet support true polymorphism; this will be added when classes are implemented. However, you can simulate polymorphic methods using method pointers.

Getting Started

In order to use the new type constructs, you will need to download the CVS version of the compiler; Windows, Linux or DOS.. You select the large version if you are updating for the first time. If you have not done so, download and install the last stable .17 release that you will find on the FreeBasic download page. Once .17 is installed, then unpack the CVS version in the same install folder, overwriting all files.

Polymorphism

Polymorphic methods are subroutines or functions that have the same type and parameter list, but behave differently when bound to different objects. An animal object may have a Speak method that will issue a bark for a dog and a meow for a cat. Since FreeBasic doesn’t yet have classes, you cannot implement true polymorphic methods, but you can simulate the behavior by using method pointers.

The following listing shows a couple of defines and an extended type declaration:

#define isdog 1
#define iscat 2

Type animal
    Public:
    speak As Sub()
    Declare Constructor (anid As Integer)    
End Type

The #defines are passed to the Constructor to signal what type of object is being created. The speak As Sub()definition defines the method pointer. As you will see, the address of two different subroutines will be passed to the speak method pointer. The following listing shows the different speak subroutines and the Constructor method:

'Speak method for dog object
Sub Bark()
    Print "Woof!"
End Sub

'Speak method for cat object
Sub Meow()
    Print "Meow!"
End Sub

'Set the proper method pointer based on animal id
Constructor animal(anid As Integer)
    If anid = isdog Then
        this.speak = @Bark
    Elseif anid = iscat Then
        this.speak = @Meow
    End If
End Constructor

The Bark subroutine will be called if the object is a dog and the Meow subroutine will be called if the object is a cat. You may be wondering why you can’t just overload the method? For overloaded methods, the type and parameter list must be unique, where in a polymorphic method, the type and parameter list must be the same. Since Bark and Meow have the same parameter list, that is no parameters, you cannot overload the method.

The Constructor code is where the program decides what method call to use. If anid is equal to isdog, then the Speak method pointer will be set to the address of the Bark subroutine. If anid is equal to iscat then Speak will be set to the address of the Meow subroutine. The addressof operator @ is used to pass the address of Bark and Meow to the Speak pointer.

The this object reference is a hidden parameter that is passed to the Constructor that references the type, which in this case is animal. You can use this to reference the internal variables within the type.

The only thing left to do is to create and initialize the object:

'Create a dog and cat object
Dim myDog As animal = isdog
Dim mycat As animal = iscat

Here myDog and myCat are created with the appropriate flags passed to the Constructor so that the proper references can be set up. Once the object are created you can call the speak method of each object.

'Have the animals speak
Print "My dog says ";
myDog.speak()
Print "My cat says ";
myCat.speak()

Notice that you are calling the same speak method, yet the output is different:

	My dog says Woof!
	My cat says Meow!

This is the essence of polymorphic methods. By using polymorphic techniques, you can enhance the capabilities of your objects, and when classes are implemented, you will be ready to use this powerful OOP tool.

Here is the complete program listing:

'Simulated Polymorphism Using Method Pointers
'Richard D. Clark
'Requires the CVS version of FreeBasic
'**********************************************

#define isdog 1
#define iscat 2


Type animal
    Public:
    speak As Sub()
    Declare Constructor (anid As Integer)    
End Type

'Speak method for dog object
Sub Bark()
    Print "Woof!"
End Sub

'Speak mehod for cat object
Sub Meow()
    Print "Meow!"
End Sub

'Set the proper method pointer based on animal id
Constructor animal(anid As Integer)
    If anid = isdog Then
        this.speak = @Bark
    Elseif anid = iscat Then
        this.speak = @Meow
    End If
End Constructor

'Create a dog and cat object
Dim myDog As animal = isdog
Dim mycat As animal = iscat

'Have the animals speak
Print "My dog says ";
myDog.speak()
Print "My cat says ";
myCat.speak()

Sleep
End

FreeBASIC File/Folder Management: by Stephane Richard (MystikShadows)


INTRODUCTION:

Many times when programming an application (or even games) you find yourself coming across the subject of creating files folders (or deleting them) for more than one reason. Luckily FreeBASIC has everything we need to help us with all of these functionalities.

In this tutorial I'll cover all of the file/folder oriented statements and functions that exist in freebasic and well see hwo and when they can be used in order to bring some good standard file and folder management functionality to your programming projects. So let's start off with a little reference of the commands we'll be using and take it from there.

FREEBASIC FILE AND FOLDER COMMANDS AND FUNCTIONS:

There are several commands and functions available to create, delete, maganage files and folders.

  • NAME:   CHDIR
    SYNTAX: CHDIR "Drive:\Path"
            Result = CHDIR("Drive:\Path")

    This function simply goes to the folder specified as a parameter. This path can include drive name and path.

  • NAME:   CURDIR | CURDIR$
    SYNTAX: CURDIR$
            CurrentPath = CURDIR$

    This function returns the current path that the system is currently in. If you change folder with the CHDIR command above and display CURDIR$ again you'll see that it changed to reflect the new folder location.

  • NAME:   DIR | DIR$
    SYNTAX: DIR FileSpec, AttribMask, OutAttrib
            CurrentFile = DIR("*.*", fbDirectory)

    This function looks in the current path (or in the specified folder) for the occurence of the file specification passed in the first parameter. If it finds it it will return the name of the first occurrence. If it does not find it it will return an empty string (""). Once a first file is found you can use the DIR() function without parameneters in a loop to get the following occurrences of the file specification you are looking for (more on this later. fbDirectory and other constants are defined in "dir.bi" include file.

  • NAME:   KILL
    SYNTAX: KILL "FileSpecification"
            Result = KILL("*.TMP")

    This function deletes the file specification from either the current folder or the folder specified in the paramenter. If the deletion went well, a 0 will be returned. If an error occured, that error number will be returned by the KILL function.

  • NAME:   MKDIR
    SYNTAX: MKDIR "FolderName"
            Result = MKDIR("MyNewFolder\MyNewSubFolder")

    This function creates a folder in the local file system. It will return zero (0) if it worked, or minus one (-1) if an error occured.

  • NAME:   NAME
    SYNTAX: NAME "OldName", "NewName"
            Result = NAME("OldName.Ext", "NewName.Ext")

    This function renames a file to a new given name. It can also rename a group of files using file masks. IF it works it will return zero (0). If some error occured and the file could not be renamed, an error number will be returned by the function.

  • NAME:   RMDIR
    SYNTAX: RMDIR "FolderName"
            Result = RMDIR("C:\TEMP\")

    This function will attempt to remove a directory from the specified path or current folder (if just a folder name is specified as a parameter). It will return zero (0) if everything worked or minus one (-1) if an error occured. RMDIR will not remove a folder in which a file exists.

And now that we have the reference material we need let's see what we can do with them. We will take each one and see how to use them in given situations and perhaps implement some safegards in code to help minimize errors that could occur. For this we will create our own little COMMAND.COM so to speak. A little program that will accept input from the user and perform the current actions required by the commands we'll enter in the system.

BUILDING OUR OWN COMMAND PROCESSOR:

As a first note, I'd like to point out that this will be a very simplistic command processor. it's purpose is to highlight the freebasic commands and functions for file/folder manipulation, so it will essetially be a simple loop with string manipulation to decipher the commands entered. But it will be something functional that can later be altered to perform as expected. It will not allow to execute other files for examples, just internal commands for the purpose of this tutorial. The sample program created here can be acquired from this link so you don't have to type or edit anything.

First off we'll create the core processor/command acquisition system and we'll add commands to it as we progress in this tutorial. The framework itself shown here has functions to get parts of the entered command, this is how we'll know which command has been entered and what to do with them.

' -------------------------------------
'  BASIC command processor application
'          by MystikShadows
' -------------------------------------

#INCLUDE "dir.bi"

' -------------------------------
'  Sub and Function Declarations
' -------------------------------
DECLARE SUB PrintApplicationInformation()
DECLARE SUB DisplayHelpScreen()
DECLARE SUB ProcessCommand(ToBeProcessed AS STRING)
DECLARE FUNCTION GetWordCount(WorkString AS STRING) AS INTEGER
DECLARE FUNCTION GetWordNumber(WorkString AS STRING, WordNumber AS LONG) AS STRING

' -----------------------------
'  Needed Constant Definitions
' -----------------------------
CONST False = 0
CONST TRue  = NOT False

CONST HeaderColor  = 15 ' White
CONST InfoColor    = 11 ' Light Cyan
CONST CommandColor = 14 ' Yellow
CONST ErrorColor   = 12 ' Light Red
CONST ResultColor  = 10 ' Light Green

' -------------------------
'  Needed Global Variables
' -------------------------
DIM SHARED CurrentCommand AS STRING
DIM SHARED CanExit        AS INTEGER

' ------------------------------------------------------
'  Start by displaying the title and general informaion
' ------------------------------------------------------
WIDTH 80, 50
COLOR 7, 1
CLS
CALL PrintApplicationInformation()

' -----------------------------------------------------
'  Main loop where commands are acquired and processed
' -----------------------------------------------------
DO WHILE CanExit = False
   ' ---------------------------
   '  Get command from the user
   ' ---------------------------
   COLOR CommandColor, 1
   PRINT "->";
   INPUT CurrentCommand
   CALL ProcessCommand(CurrentCommand)
   ' -------------------------------------------
   '  We Clear the command, ready for a new one
   ' -------------------------------------------
   CurrentCommand = ""

LOOP

' ========================================================
'  NAME........: PrintApplicationInformation()
'  PARAMETERS..: None
'  RETURN......: No value
'  ASSUMES.....: Nothing
'  CALLED FROM.: Main Program Loop
' --------------------------------------------------------
'  DESCRIPTION.: This Sub simply displays some regular
'                information to the user about this
'                current program
' ========================================================
SUB PrintApplicationInformation()

    COLOR HeaderColor, 1
    PRINT "MystikShadow's Command Processor Application"
    PRINT "Version 1.00a"
    PRINT
    COLOR InfoColor, 1
    PRINT "Type 'HELP' for a list of commands"
    PRINT "Type 'EXIT' to end the program"
    PRINT

END SUB

' ========================================================
'  NAME........: DisplayHelpScreen()
'  PARAMETERS..: None
'  RETURN......: No Value
'  ASSUMES.....: Nothing
'  CALLED FROM.: The Main Program Loop
' --------------------------------------------------------
'  DESCRIPTION.: This Sub displays a list of valid
'                commands available to the user. So that
'                he/she can learn the allowed commands.
' ========================================================
SUB DisplayHelpScreen()

    COLOR ResultColor, 1
    PRINT "Valid Commands Are:"
    PRINT
    PRINT "TIME                       Returns The Current Time"
    PRINT "DATE                       Returns The Current Date"
    PRINT "CD []            Returns Current Path or Changes to PathName"
    PRINT "DIR     Lists files that match FileSpecification
    PRINT "REN      Renames an existing file to a new name"
    PRINT "RENAME   Renames an existing file to a new name"
    PRINT "MD             Creates a Directory on the Disk"
    PRINT "RD             Removes a Directory from the disk"
    PRINT "DEL     Removes a Directory from the disk"
    PRINT "DELETE  Removes a Directory from the disk"
    PRINT
END SUB

' ========================================================
'  NAME........: ProcessCommand()
'  PARAMETERS..: ToBeProcessed AS STRING
'  RETURN......: NoValue
'  ASSUMES.....: ToBeProcessed Is Not Empty
'  CALLED FROM.: Main Program Loop
' --------------------------------------------------------
'  DESCRIPTION.: This Sub is the main core of the program
'                it will take the passed command in it's
'                parameter, parse it and perform the
'                corresponding action.
' ========================================================
SUB ProcessCommand(ToBeProcessed AS STRING)

    ' -------------------------------------
    '  First we take care of easy commands
    ' -------------------------------------
    COLOR ResultColor, 1
    SELECT CASE TRIM$(UCASE$(ToBeProcessed))
           CASE "HELP"
                CALL DisplayHelpScreen()
                EXIT SUB
           CASE "QUIT"
                CLS
                END
    END SELECT

END SUB

' ========================================================
'  NAME........: GetWordCount()
'  PARAMETERS..: WorkString AS STRING
'  RETURN......: 0 Or the number of words
'  ASSUMES.....: WorkString is valid string with contents
'  CALLED FROM.: ProcessCommand()
' --------------------------------------------------------
'  DESCRIPTION.: This function accepts a string as a
'                parameter, peruses it and accumulates
'                the number of words it finds in the
'                string.
' ========================================================
FUNCTION GetWordCount(WorkString AS STRING) AS INTEGER

    ' ----------------
    '  Work Variables
    ' ----------------
    DIM  Counter      AS LONG
    DIM  WordCounter  AS LONG
    DIM  Position     AS LONG
    DIM  Skipper      AS LONG

    ' ----------------------
    '  Initialize Variables
    ' ----------------------
    WordCounter  = 1
    Position     = 1
    ' ---------------------------------------------------------
    '  First we put ourselves at the beginning of the 1st word
    ' ---------------------------------------------------------
    IF MID$(WorkString, Position, 1) = " " THEN
       DO WHILE MID$(WorkString, Position, 1) = " "
          Position = Position + 1
       LOOP
    END IF
    ' --------------------------------------
    '  Then we start the Word Count Process
    ' --------------------------------------
    FOR Counter = Position TO LEN(WorkString)
        IF MID$(WorkString, Counter, 1) = " " THEN
           WordCounter = WordCounter + 1
           DO WHILE MID$(WorkString, Counter, 1) = " "
              Counter = Counter + 1
           LOOP
        END IF
    NEXT Counter
    ' ----------------------------------------
    '  Return the number of words accumulated
    ' ----------------------------------------
    GetWordCount = WordCounter

END FUNCTION

' ========================================================
'  NAME........: GetWordNumber()
'  PARAMETERS..: WorkString AS STRING
'                WordNumber AS LONG
'  RETURN......: "" Or the desired word Number
'  ASSUMES.....: WorkString has contents, WordNumber > 0
'  CALLED FROM.: ProcessCommand()
' --------------------------------------------------------
'  DESCRIPTION.: This function accepts a string and a
'                Word Number as paremeters, it then finds
'                the given word number and returns it to
'                the calling function.
' ========================================================
FUNCTION GetWordNumber(WorkString AS STRING, WordNumber AS LONG) AS STRING

    ' ----------------
    '  Work Variables
    ' ----------------
    DIM  Counter      AS LONG
    DIM  WordCounter  AS LONG
    DIM  Position     AS LONG
    DIM  Skipper      AS LONG
    DIM  ReturnString AS STRING

    ' ----------------------
    '  Initialize Variables
    ' ----------------------
    WordCounter  = 1
    Position     = 1
    ReturnString = ""
    ' ---------------------------------------------------------
    '  First we put ourselves at the beginning of the 1st word
    ' ---------------------------------------------------------
    IF MID$(WorkString, Position, 1) = " " THEN
       DO WHILE MID$(WorkString, Position, 1) = " "
          Position = Position + 1
       LOOP
    END IF
    ' --------------------------------------
    '  Then we start the Word Count Process
    ' --------------------------------------
    FOR Counter = Position TO LEN(WorkString)
        IF MID$(WorkString, Counter, 1) = " " THEN
           WordCounter = WordCounter + 1
           DO WHILE MID$(WorkString, Counter, 1) = " "
              Counter = Counter + 1
           LOOP
        END IF
        ' ----------------------------------------------------------
        '  If it's the wanted word number we put it in ReturnString
        ' ----------------------------------------------------------
        IF WordCounter = WordNumber THEN
           IF MID$(WorkString, Counter, 1) <> " " THEN
              ReturnString = ReturnString + MID$(WorkString, Counter, 1)
           END IF
        END IF
    NEXT Counter
    ' ---------------------------------
    '  Return the word in ReturnString
    ' ---------------------------------
    GetWordNumber = ReturnString

END FUNCTION
         

What this code so far is wait for the user to enter a command in the system. once entered, the ProcessCommand() subroutine is called. As you can see from the code to ProcessCommand() subroutine so far we manage two commands HELP and QUIT. The last two functions you see in the code are the string manipulation function we'll need to get the different parts of the command entered by the user. If you compile the program like it is now, run it and enter the help command. Here's what you will see on the screen:

After that, just enter EXIT to leave the program. The command list you see on the screenshot are the commands we will be implementing in this tutorial. Four of the commands (CLS, TIME, DATE and CD without parameters are very easy to code for so in the ProcessCommand we'll just add CASE statements for each of them. Here's what the ProcessCommand() subroutine should look like:

SUB ProcessCommand(ToBeProcessed AS STRING)

    ' -------------------------------
    '  We take care of easy commands
    ' -------------------------------
    COLOR ResultColor, 1
    SELECT CASE TRIM$(UCASE$(ToBeProcessed))
           CASE "TIME"
                PRINT TIME$
                PRINT
                EXIT SUB
           CASE "DATE"
                PRINT DATE$
                PRINT
                EXIT SUB
           CASE "CLS"
                COLOR 7, 1
                CLS
                EXIT SUB
           CASE "CD"
                PRINT CURDIR$
                PRINT
                EXIT SUB
           CASE "HELP"
                CALL DisplayHelpScreen()
                EXIT SUB
           CASE "EXIT"
                CLS
                END
    END SELECT
         

In the case of these commands, as you can see, what goes on is very straightforward. Simple code is executed in each of these cases. now we need to add validation and tell the user if they entered a command that isn't recognized. Since we already have the list of valid command it will be rather easy to know if the command entered is valid or not. So We'll add, at the beginning of the subroutine, a condition to ProcessCommand() to validate the command like so:

SUB ProcessCommand(ToBeProcessed AS STRING)

    DIM FirstWord AS STRING

    ' -------------------------------------------------
    '  First we test of the command is a valid command
    ' -------------------------------------------------
    FirstWord = TRIM$(UCASE$(GetWordNumber(ToBeProcessed, 1)))
    IF FirstWord <> "TIME"   AND FirstWord <> "DATE" AND _
       FirstWord <> "CLS"    AND FirstWord <> "CD"   AND _
       FirstWord <> "CD.."   AND FirstWord <> "CD\"  AND _
       FirstWord <> "DIR"    AND FirstWord <> "REN"  AND _
       FirstWord <> "RENAME" AND FirstWord <> "DEL"  AND _
       FirstWord <> "DELETE" AND FirstWord <> "MD"   AND _
       FirstWord <> "RD"     AND FirstWord <> "HELP" AND _
       FirstWord <> "EXIT"   THEN
       COLOR ErrorColor, 1
       PRINT "An Invalid Command Was Entered"
       PRINT
       EXIT SUB
    END IF

    ' ------------------------------------
    '  Next we take care of easy commands
    ' ------------------------------------
    COLOR ResultColor, 1
    SELECT CASE TRIM$(UCASE$(ToBeProcessed))
           CASE "TIME"
                PRINT TIME$
                PRINT
                EXIT SUB
           CASE "DATE"
                PRINT DATE$
                PRINT
                EXIT SUB
           CASE "CLS"
                COLOR 7, 1
                CLS
                EXIT SUB
           CASE "CD"
                PRINT CURDIR$
                PRINT
                EXIT SUB
           CASE "HELP"
                CALL DisplayHelpScreen()
                EXIT SUB
           CASE "EXIT"
                CLS
                END
    END SELECT

END FUNCTION
         

Note that I added "CD.." and "CD\" as valid commands because typical DOS users didn't put spaces for these two commands (just a hint of user consideration). Basically, if the command entered isn't one that appears in the if statement we will warn the user that an invalid command has been entered.

ADDING COMMANDS TO THE COMMAND PROCESSOR:

Now that we validate our commands it's time to get to the real part of the tutorial. This is were we start to really look at what the user wants to do. To do so, we'll need a few other variables in our ProcessCommand() subroutine. We will put them at the beginning of the subroutine after the first DIM statement already there.

    DIM SecondWord    AS STRING
    DIM ThirdWord     AS STRING
    DIM WorkFile      AS STRING
    DIM WordCounter   AS INTEGER
    DIM FolderCounter AS INTEGER
    DIM FileCounter   AS INTEGER
         

These variables will come in handly to implement the rest of the supported commands. As you can see from the screenshot SecondWord and ThirdWord are there get the 2nd and 3rd part of the statement (since 2 parameters will be the most we need to deal with we only need SecondWord and ThirdWord). First we'll Implement the CD family of commands. After the SELECT CASE that's already there, we will first add statements to get the second and third word if we need to in order to complete the statements entered by the user. Here is the code to add at the end of the ProcessCommand() subroutine:

    ' ---------------------------------------------
    '  We get the rest of the words in the command
    ' ---------------------------------------------
    WordConter = GetWordCount(ToBeProcessed)
    IF WordCounter = 2 THEN
       SecondWord = GetWordNumber(ToBeProcessed, 2)
    ELSEIF WordCounter = 3 THEN
       SecondWord = GetWordNumber(ToBeProcessed, 2)
       ThirdWord  = GetWordNumber(ToBeProcessed, 3)
    END IF
         

Now the first command we will implement is the CD command. Remember that CD by itself simply displays the current directory to the user and is already coded for. This part will take care of the other forms of CD commands. Typically the user will enter CD followed by a folder name, a .. or a \. Like I mentionned earlier DOS users don't usually enter spaces for .. and \ so we will add direect support for CD.. and CD\ without spaces. Here's the code to the CD command:

    ' -------------------------------------------------------------------------
    '  This SELECT CASE decides which code to executed for the command entered
    ' -------------------------------------------------------------------------
    SELECT CASE FirstWord
           ' -------------------------------
           '  THE CD command implementation
           ' -------------------------------
           CASE "CD", "CD..", "CD\"
                ' -----------------------------------------
                '  Test for the existence of the directory
                ' -----------------------------------------
                IF DIR$(SecondWord, fbDirectory) = "" AND SecondWord <> "\" THEN
                   ' -------------------------------------------------------
                   '  If the directory does not exist, we display a message
                   ' -------------------------------------------------------
                   COLOR ErrorColor, 1
                   PRINT "This Directory does not exist. Path remains unchanged."
                   PRINT CURDIR$
                   PRINT
                   COLOR ResultColor
                ELSE
                   ' ------------------------------------------------
                   '  Test to see if none spaced .. andn \ were used
                   '  Execute appropriate command in these cases.
                   ' ------------------------------------------------
                   IF FirstWord = "CD.." THEN
                      CHDIR ".."
                   ELSEIF FirstWord = "CD\" THEN
                      CHDIR "\"
                   ' ---------------------------------------------------
                   '  In all other cases we just CHDIR to the directory
                   ' ---------------------------------------------------
                   ELSE
                      ' -----------------------------------------------
                      '  If it does exist we CHDIR right to the folder
                      ' -----------------------------------------------
                      CHDIR SecondWord
                   END IF
                   PRINT CURDIR$
                END IF
                PRINT
                EXIT SUB
    END SELECT
         

You can note that we also added a test to see if the folder the user wants to change to actually exists. We warn them if it doesn't exist and nothing else happens. If the directory does exist, We use CHDIR to change to the specified directory. Using this code the user can enter any valid CHDIR statements after the CD command and it will perform as expected.

The next command on our list is the MD command. This command is a bit simpler to code for than the CD command because it doesn't have any variants to it. The user would simply type MD FolderName to create the desired folder. We will simply test to see if the folder they are trying to create already exists and warn them if it does. Here's the code for the MD command. It is added to the SELECT CASE statement we just created previously.

           ' -------------------------------
           '  The MD Command Implementation
           ' -------------------------------
           CASE "MD"
                ' -------------------------------------
                '  We test to see if the folder exists
                ' -------------------------------------
                IF DIR$(SecondWord, fbDirectory) <> "" THEN
                   ' ------------------------------------
                   '  If it does exist, we warn the user
                   ' ------------------------------------
                   COLOR ErrorColor, 1
                   PRINT "This Directory already exists, unable to create it."
                   PRINT
                   COLOR ResultColor, 1
                ELSE
                   ' -------------------------------------------------------
                   '  If it doesn't exist, we simply go ahead and create it
                   ' -------------------------------------------------------
                   MKDIR SecondWord
                END IF
                EXIT SUB
         

As you can see, the code is straight forward and rather clear we either create the folder or we don't (if the folder already exist). This is the only test we really need to do.

Up next on our list is the RD command which removes a directory from the disk. Remember that RD will not work if the directory to be removed already has files in it. Coding for the RD command should be quite similar to the MD command with the added test to see if there are files in the folder we want to remove. If there are, we'll warn the user that they are files. If no files exist in the directory we'll go ahead and use RMDIR to remove the folder.

           ' -------------------------------
           '  The RD Command Implementation
           ' -------------------------------
           CASE "RD"
                ' ------------------------------------
                '  First we test if the folder exists
                ' ------------------------------------
                IF DIR$(SecondWord, fbDirectory) = "" THEN
                   COLOR ErrorColor, 1
                   PRINT "This Directory does not exist hence cannot be removed."
                   PRINT
                   COLOR ResultColor, 1
                ' --------------------------------------------------
                '  Next we test if there are files in the directory
                ' --------------------------------------------------
                ELSEIF DIR$(CURDIR$ + "\" + SecondWord + "\*.*") <> "" THEN
                   COLOR ErrorColor, 1
                   PRINT "The Directory has files in it and cannot be removed."
                   PRINT
                   COLOR ResultColor, 1
                ' -----------------------------------------------------
                '  If all is good we go ahead and remove the directory
                ' -----------------------------------------------------
                ELSE
                   RMDIR SecondWord
                END IF
                EXIT SUB
         

Simply put we do two consecutive tests, the first to see if the folder exists in the first place, if it does, we're good we can go to the second test which is to test if the directory has any files in it. If there are files we warn the user since the directory won't be removed. if there are no files we go ahead and remove the directory.

The next command on the list is the DIR command. The DIR command lists files that match the specified File masks. Shortcuts can be used here such as the standard "*.*" and the "?" to filter out unwanted files. In this version I am doing two things when a DIR command is issued. I first list the folders (if any) that match the file mask and then I list the files that match the file mask. I will also accumlate the results to tell the user how many folders and files were found for the DIR command they issued. I added a little feature which if DIR is called without a file mask I default it to *.* instead of warning them of an invalid command. here's the code to the DIR command CASE STATEMENT (again to be added at the end of the SELECT CASE STATEMENT):

           ' --------------------------------
           '  The DIR Command Implementation
           ' --------------------------------
           CASE "DIR"
                FolderCounter = 0
                FileCounter   = 0
                ' ----------------------------------------------------
                '  We first list the folders in the current directory
                ' ----------------------------------------------------
                IF SecondWord = "" THEN
                   WorkFile = DIR$("*", fbDirectory)
                ELSE
                   WorkFile = DIR$(SecondWord, fbDirectory)
                END IF
                DO WHILE TRIM$(WorkFile) <> ""
                   IF LEFT$(WorkFile, 1) <> "." THEN
                      FolderCounter = FolderCounter + 1
                      PRINT WorkFile & "\"
                   END IF
                   WorkFile = DIR$()
                LOOP
                ' -------------------------------------------------
                '  We then list the files in the current directory
                ' -------------------------------------------------
                IF SecondWord = "" THEN
                   WorkFile = DIR$("*")
                ELSE
                   WorkFile = DIR$(SecondWord)
                END IF
                DO WHILE TRIM$(WorkFile) <> ""
                   FileCounter = FileCounter + 1
                   PRINT WorkFile
                   WorkFile = DIR$()
                LOOP
                ' --------------------------------------------------------------
                '  We finally display the folder and file counts we accumilated
                ' --------------------------------------------------------------
                PRINT
                PRINT "There were " + STR$(FolderCounter) + _
                      " directories and " + STR$(FileCounter) + _
                      " files listed."
                PRINT
                EXIT SUB
          

Basically, this code is created to show you examples (hopefully realword examples) on how to use these commands, the things to watch out for when using them and the likes. This is why I do things like check for the existence of a folder before I try to CHDIR to it or something. Nothing happens if there's no files to list. If there are files then they will be listed one after the other as long as the search yields a file. Quite straight forward.

And now we have the DEL and DELETE commands. Like DOS you can used both DEL or DELETE (whatever you are used to) to delete files on your disk. The only test we need to do here is to see if the file they want to delete actually exists, if so, then we use the KILL statement to delete the file. If it does not exist we'll simply warn the user about it and do nothing else. here's the CASE statement for the DEL, DELETE command (you guessed it, at the end of the SELECT CASE statement is where it goes):

           ' -------------------------------------------
           '  The DEL and DELETE Command Implementation
           ' -------------------------------------------
           CASE "DEL", "DELETE"
                ' ---------------------------------
                '  First we see if the file exists
                ' ---------------------------------
                IF DIR$(SecondWord) = "" THEN
                   COLOR ErrorColor, 1
                   PRINT "This file does not exist, unable to delete it."
                   PRINT
                   COLOR ResultColor, 1
                ' ----------------------------------------------------------
                '  If the file exists we go ahead and use KILL to delete it
                ' ----------------------------------------------------------
                ELSE
                   KILL SecondWord
                END IF
                EXIT SUB
          

Very simple test that basically says that if the file exists we can delete it, if it does not exist we just let the user know (in which case he will just repeat the command with the right file name the next time around, hopefully). Pretty simple isn't it? I thought so.

And we are at the final command to be implemented, the REN and RENAME commands. This is the only command that needs all three parameters, hence we'll have to do some validation on them to make sure everything is good to perform the renaming of the file in question. First test will be the old file name is not empty. If it is empty we let the user know and we do nothing else (EXIT SUB). The next test is to see that the new file name is not empty. if it is empty, once again, we warn the user and exit the subroutine. If it is not empty we go to the third test which is to see that the old file name actually exists on the current or specified folder. If we're still good after these 3 tests we go ahead and use the NAME statement to rename the old file name (SecondWord) to the new file name (ThirdWord). Here is the last CASE STATEMENT to be added to our codebase:

           ' -------------------------------------------
           '  The REN and RENAME Command Implementation
           ' -------------------------------------------
           CASE "REN", "RENAME"
                ' ----------------------------------------------
                '  First we test that Old Filename Is not empty
                ' ----------------------------------------------
                IF SecondWord = "" THEN
                   COLOR ErrorColor, 1
                   PRINT "The name of an existing file is needed to rename the file."
                   PRINT
                   COLOR ResultColor, 1
                   EXIT SUB
                ' ---------------------------------------------
                '  Next we test that New Filename Is not empty
                ' ---------------------------------------------
                ELSEIF ThirdWord = "" THEN
                   COLOR ErrorColor, 1
                   PRINT "A new name is needed to rename the file."
                   PRINT
                   COLOR ResultColor, 1
                   EXIT SUB
                ' ----------------------------------------------
                '  Finally we test that the old filename exists
                ' ----------------------------------------------
                ELSEIF DIR$(SecondWord) = "" THEN
                   COLOR ErrorColor, 1
                   PRINT "The file you are trying to rename does not exist."
                   PRINT
                   COLOR ResultColor, 1
                   EXIT SUB
                ' --------------------------------------------------------------
                '  If all went well we go ahead and use NAME to rename the file
                ' --------------------------------------------------------------
                ELSE
                   NAME SecondWord, ThirdWord
                   EXIT SUB
                END IF
          

As you can see, it's really all about implementing some basic tests before performing the actual command just to be sure everything is good, ready and safe to perform the actual command. With these in place the command processor becomes a bit more stable a tool to use for the user and for the user's files and folders of course.

A FEW NOTES:

Now remember this sample program is mean to illustrate the use of the file and folder commands provided by FreeBASIC. Hence the emphasis is on those commands. Of course I could have used another method than input to get the user's commands. I could have done things a bit different (like perhaps add some good Drive, Path and file name validation for example) but the important part is what I do with the file and folder commands themselves.

IN CONCLUSION

And there you have it, I believe we've covered all of the commands offered by FreeBASIC as far as files and folder management goes. Of course FreeBASIC has more commands (like CHAIN, EXEC, RUN and SHELL) that have the potential to add more functionality to a program such as this command processor sample. This sample is designed to respond to user commands but any of these commands could be coded in a subroutine and called for any purpose from any type of program really. The choice is yours.

As always, I hope this tutorial helped you in some way or another. I hope it was clear but readers tend to read things differently. So, if any of this isn't clear in your head, be sure to email me to let me know what parts is not clear or whatever other comments or questions you may have about this tutorial. Until next, happy coding (and command processing).


Exit Issue: by Stephane Richard (MystikShadows)


And there you have, a 4th release of the magazine, you've reached the final part of the magazine. Parting is such sweet sorrow isn't it?

We hope you liked this release of PCOPY! particularly because of it's contents of course but also because of it's new look and feel. So far, among the editors of the magazine we think that this is a much better color scheme and layout and we hope you agree. be sure to let us know what you think of this new layout we've created for you.

We're also completely opened to suggestions. If there's something you would like to see appear in PCOPY! if it's basic related chances are it can and will be included. So don't be affraid to tell us all about it and if it's worth being in PCOPY! you can bet that it will be included as soon as possible.

Don't forget to be on the lookout for the next release of PCOPY! where we'll do our very best to bring you news and other related contents about any and all BASIC dialects out there. There's a big list, going through each of these languages to get the news is a great task but I believe we're taking up this challenge head on to get you the good stuff. We hope you liked it and will continue to like in the future.

Until our next edition, this is PCOPY! signing off.