Copy Link
Add to Bookmark
Report
The Basix Fanzine issue 11
-IMPORTANT NOTE----------------------------------------------------------------
NOTE: Issues 1-8 of the Basix Fanzine were edited by Peter Cooper.
Issues 9-13 of the Basix Fanzine were edited by Alex Warren.
The new editor of the Basix Fanzine is David Groulx and the addresses for the fanzine
are:
ARTICLES: Basix_Fanzine@yahoo.com
OTHER ENQUIRIES ETC.: Basix_Fanzine@yahoo.com
WWW ADDRESS: http://www.come.to/basixfanzine
Please use these addresses in place of the out-of-date addresses in the Fanzine
below.
David Groulx
April 1999
-------------------------------------------------------------------------------
The Basix Fanzine
issue 11 · july 1998
email: basix@dewarr.globalnet.co.uk
www: http://come.to/basixfanzine
Welcome to issue 11 of the Basix Fanzine!
The fanzine is now available for download in a much more sophisticated HTML
format, but here is cutandpaste-over text format version for those of you who
want it. Soon, however, the fanzine may not become available in a text format
version at all and will ONLY be available in HTML. Note that this text version
may contain mistakes and ommissions, though hopefully it doesn't as (believe it
or not) I have compiled it carefully and proof-read it....
So, what's in this issue? Here's the rundown: Get the info on the new PB/CC
from PowerBasic Inc.... read how to do long filenames in your programs.... find
out about your copyright rights.... find out why most online tutorials suck in
Rude John's new regular editorial column.... read PCX files.... use the
modem.... speed up input and output.... and more besides. Enjoy!
-------------------------------------------------------------------------------
CONTENTS
Levels are represented in bold by B, I or A for Beginner, Intermediate and
Advanced respectively, or a combination. They aren't clear-cut definitions
though, so you might find something useful labelled (B) even though you've been
programming for 10 years, for example. Unless otherwise stated, the articles
apply to all major breeds of BASIC.
News:
- BASIX FANZINE AWARDS 1998
- POWERBASIC CONSOLE COMPILER FOR WINDOWS
- PROPOSAL FOR NEW POWERBASIC NEWSGROUP
Articles:
- NEW! Rude John's editorial: WHY (MOST) ON-LINE PROGRAMMING TUTORIALS SUCK!
- LONG FILENAMES FROM DOS by Alex Warren (I/A) (not QBasic)
- GRAPHICS IN QBASIC TUTORIAL (PART 2) by "Hacker" aka Damian Nikodem (I)
- TESTING MATRIX SOFTWARE, by Rude John (A)
- HIT-OR-MISS INTEGRATION, by Rude John (A)
- YOUR PROGRAMS - YOUR RIGHTS, by Alex Warren
From the newsgroups:
- INACCURACY IN GRAPHICS TUTORIAL IN ISSUE 10
- UNLOCKING GWBASIC PROGRAMS
- SORTING RANDOM NUMBERS
- FAST KEYBOARD INPUT
- CLEARING THE KEYBOARD BUFFER
- POKE-ING CHARACTERS TO THE SCREEN
- TREE/PLANT FRACTALS
- USING THE MOUSE IN QBASIC
- QBASIC COMMUNICATIONS
Internet Resources
How to contribute
Final words
-------------------------------------------------------------------------------
NEWS
*** BASIX FANZINE AWARDS 1998
Do you have a good BASIC website? Or have you seen one recently? If so, why not
nominate the site for an award?
To nominate a site for an award, just send an email to
basixawards98@dewarr.globalnet.co.uk and include the name of the site and the
URL. If you want to suggest a category the site could go in, include that as
well.
Alternatively, you could fill in the form at
http://www.users.globalnet.co.uk/~dewarr/basix-awards98.htm
The deadline for nominations has been moved back again (in the original Usenet
post I wrote about this, I suggested the end of May 1998 I think, and recieved
about five nominations) to the end of September 1998.
After the deadline, I will post a complete list of nominations the the BASIC
newsgroups and also include the list in the issue of the Basix Fanzine which
will be released after that date. Votes will be taken in and the winning site
will recieve a prominent position on the Internet Resources page, much
publicity in the Basix Fanzine, a lovely-looking GIF file to display on the
site, and much praise and other nice-ness.
Good luck!
Nominations accepted for all non-commercial DOS BASIC-oriented websites. The
editor reserves the right to disallow a nomination, for example if adult
content appears on a nominated site.
*** POWERBASIC CONSOLE COMPILER FOR WINDOWS
In a recent newsgroup post Dave Navarro hollered the following (slightly edited
for size, as tragically, I'm not paid for this kind of thing):
"Ever wished for a 32-bit BASIC compiler? One with the straightforward DOS
interface but megabytes and megabytes of memory? Ever wished for a 32-bit
Windows compiler that's truly easy to use? Well, now it's here. Today. The
PowerBASIC Console Compiler for Windows. With PB/CC, it's a whole new Windows!
Text mode for Win95, Win98, and WinNT!
The Console is a text mode interface connected right to the heart of 32-bit
Windows. With a console application, there's no fluff, no animated puppets,
just intense computing power. Port existing Basic code from DOS to Windows
today! Access a flat memory model that's practically unlimited. Boost
performance with true 32-bit code...
PB/CC supports PRINT, LOCATE, LINE INPUT, INKEY$, INSTAT, CLS, COLOR, and
LPRINT... then we added more. CURSOR, INSHIFT, PAGE, PCOPY, WAITKEY$ and
WAITSTAT... mouse handling routines... All the text tools you'll ever need...
PB/CC's high degree of compatibility with PowerBASIC, QuickBasic, GW-BASIC and
BASICA means that you can port existing DOS applications to Win32 with ease...
creating an array that uses 50 megabytes of RAM is as simple as:
DIM x%(0 to 26214400)
Create CGI applications for your web server... Get complete executables as
small as 10K! With no run-time requirements of any kind...
Access to the Win32 API, or any 32-bit DLL, is a breeze! Including ODBC,
Winsock, and the Internet controls. There's an inline assembler, support for
threads...
PB/CC Features:
- Array Sort, Scan, Insert, Delete
- Bit Shift, Rotate, Test Set, Reset and Toggle
- Built-in 32-bit assembler
- Code pointer variables (create your own callbacks)
- Compile to true machine code
- Complete access to the entire Win32 API, including ODBC and Winsock
- Conditional compilation ($If/$EndIf)
- Currency variables with two levels of precision
- Data pointer variables
- Extended-precision (80-bit) floating point variables
- Native support for I/O redirection (STDOUT and STDIN)
- Native support for multi-threading
- Peek/Poke, Peek$/Poke$ for memory access
- User-Defined Types and Unions
- Unsigned byte, word, and double word variables
- 64-bit quad-word integers
System Requirements:
- Personal computer with a 386 or higher processor
- Windows 95/98 or Windows NT 3.51 or later
- 2 MB of available memory
- One 3.5" high-density disk drive
- A hard disk with 3.0 MB available for installation"
Dave Navarro replied to a later post from Ernie Deel that:
"PB/CC is much more than "PB/DLL plus console support". I'm saddened that you
have no faith. The console compiler is the start of a new "genre" of compilers.
...Wouldn't you like to write your program on a single platform and simply
re-compile it for other platforms? Without having to spend hours (or days or
months or years) converting between API calls, calling conventions, etc...
With the console compiler, we provide a BASIC language which will work on all
platforms supported in the future. PRINT, LOCATE, COLOR, CLS, LPRINT, etc. can
be supported on all platforms and we will do all of the low-level work so that
you can concentrate on just writing code.
Of course, if you *WANT* to take advantage of platform specific features (such
as linking to DLLs in Windows) we don't prevent you from doing that. It's your
choice.
Certainly with PB/DLL you can never write code which will work on Linux, DOS,
or other platforms because the API/OS calls won't be the same on each
platform...
As for PB/DLL itself, we're certainly not done with that. We've been collecting
suggestions from thousands of users and together with some of our own ideas,
we'll certainly be updating it."
Later support for OS/2 is a "possibility" but they're "not going to commit to
it."
Apparently PowerBasic "plan to release many new BASIC compilers and BASIC
programming products over the next 6 to 7 months". So watch this space.
A demo of PB/CC is available at ftp://ftp.powerbasic.com/pub/pbcc/
PB/CC's RRP is $149 (not including shipping & handling). For more details,
check their website at http://www.powerbasic.com/products/pbcc/ or email
sales@powerbasic.com
*** PROPOSAL FOR NEW POWERBASIC NEWSGROUP
Marc van den Dikkenberg sent a formal Request For Discussion (RFD) to the
news.announce.newgroups newsgroup, proposing a new PowerBasic newsgroup in the
comp.lang.basic.* hierarchy, to be called comp.lang.basic.powerbasic - this
would be carried by more news servers and be more "official" than the existing
alt.lang.powerbasic. Marc said in the RFD that: "By now, well over a hundred
people have already expressed their desire for a widespread newsgroup
specifically aimed at PowerBasic products. Newsgroups in the comp.* hierarchy
are carried by most newsservers, as opposed to a lot of alt.* newsgroups. As
such, the comp.* hierarchy is preferable since it guarantees a much wider
distribution or your questions / answers." If you want to join in the
discussion, or read the full RFD including the proposed charter for the group,
visit the news.groups newsgroup.
After the discussion phase, a Call For Votes (CFV) will be issued if there is
enough support (judging by the response so far, there seems to be plenty). This
will be your chance to vote for the creation of the new group - 100 more "yes"
than "no" votes will be needed and more than two thirds of the votes need to be
in favour. So, keep your eyes peeled for the CFV - it will be posted in the
news.groups newsgroup as well as the regular BASIC ones, with full instructions
for what to do.
While I'm on the subject, the editor of this fanzine recently sent out an RFD
for some more Visual Basic newsgroups to split up the current mess of
comp.lang.basic.visual.misc - the discussion can be found in the news.groups
newsgroup. At the moment, there doesn't seem to be much interest though... :(
*** Got a BASIC news article? Want to announce a new product that will benefit
BASIC programmers? Then send it to basix@dewarr.globalnet.co.uk NOW! [The
editor reserves the right to edit or omit articles]
-------------------------------------------------------------------------------
ARTICLES
*** LONG FILENAMES FROM DOS, by Alex Warren · alexwarren@writeme.com
One of the very nice things that Microsoft did for us with Windows 95 was add
support for ridiculously long filenames, up to 256 characters in length, if I
remember correctly. No longer do we have to put up with cryptic filenames such
as "LETMRB01.DOC" - instead we be can more creative and save files with names
like "Letter to Mr Brown draft 1 about the boiler that exploded last March
which still hasn't ruddy well been fixed yet even though I've phoned them three
times I mean I despair I really really do something ought to be done about
it.doc" and other such silly things.
At least... almost. We can use long filenames from our Windows apps, but what
if we want to use long filenames from our QuickBasic programs? If we try
OPEN "THE SILLY LONG FILENAME.TXT" FOR INPUT AS #1
we get a "Bad Filename" error. But if you look at the version of EDIT included
with DOS 7, it's clearly a DOS program... but look! Look at all those lovely
long filenames! Isn't it amazing! Isn't it? Oh well...
Yes, it is possible - we can access long filename functions from DOS (well, a
Windows 95 DOS session anyway). But it's not very easy to do in QuickBasic -
though it can be done. Really. If you look in the ABC Packets you'll hopefully
see that I posted some code a few months back which will do just that, from QB.
A newer version of the program (v1.5) is contained within this fanzine, in
' LONG FILENAMES FROM DOS DEMONSTRATION v1.5
' by Alex Warren, June 1998
' Released into the Public Domain
' This program is intended to show you how to use the long filename
' functions. It's not particularly neat but it should be good enough to
' show you how to incorporate long filenames in your applications without
' having to use the incredibly messy method of using SHELL.
' New in version 1.5 - new neater screen layout, "Create File" added (was
' in menu in 1.0 but forgot to implement it <g> )
DECLARE SUB drawwindow (x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS
INTEGER, col AS INTEGER)
DECLARE SUB centreprint (y AS INTEGER, s$)
DECLARE SUB setdirectory ()
DECLARE SUB getfileattribs ()
DECLARE SUB showdirectory ()
DECLARE SUB createfile ()
DECLARE SUB createdirectory ()
DECLARE SUB getvolumeinfo (drive$)
DECLARE FUNCTION truncate$ (s$)
DECLARE FUNCTION getcurrentdir$ ()
DECLARE SUB int21 ()
'$INCLUDE: 'qb.bi'
DIM SHARED inregs AS RegTypeX, outregs AS RegTypeX
DIM SHARED filesystem$, casesensitive%, preservecase%, unicode%, lfnfunctions%,
compressed%
DIM SHARED searchhandle%, returnedlfn$, returnedsfn$
DO
CLS
drawwindow 5, 1, 75, 5, 0
centreprint 2, "Long Filenames from DOS Demonstration, by Alex Warren"
centreprint 3, "version 1.5, June 1998"
centreprint 4, "Released into the Public Domain"
drawwindow 15, 12, 65, 22, 9
centreprint 12, "[ MENU ]"
centreprint 13, "Current directory is " + getcurrentdir$
centreprint 15, "1 - Create directory"
centreprint 16, "2 - Change to directory"
centreprint 17, "3 - View directory"
centreprint 18, "4 - Create file"
centreprint 19, "5 - Change drive"
centreprint 20, "6 - Exit"
' Not included but worth investigating are:
' - Remove directory (service 713Ah)
' - Delete file (7141h)
' - Move/Rename file (7156h)
' - Get/Set file attributes (7143h)
' +++ others on Ralf Brown's Interrupts List
DO: a$ = INPUT$(1): LOOP UNTIL a$ >= "1" AND a$ <= "6"
selected = VAL(a$)
COLOR 7, 0: CLS
SELECT CASE selected
CASE 1
createdirectory
CASE 2
setdirectory
CASE 3
showdirectory
CASE 4
createfile
CASE 5
INPUT "Enter drive letter: ", driveletter$
driveletter$ = driveletter$ + ":"
SHELL driveletter$
CASE 6
END
END SELECT
LOOP
SUB centreprint (y AS INTEGER, s$)
x% = 40 - LEN(s$) / 2
LOCATE y, x%: PRINT s$
END SUB
SUB createdirectory
DIM pathname AS STRING * 255
INPUT "Enter FULL path of sub-directory to create: "; p$
pathname = p$
' inregs:
' .ax: service - 7139h
' .ds: segment of pathname
' .dx: offset of pathname
inregs.ax = &H7139
inregs.ds = VARSEG(pathname)
inregs.dx = VARPTR(pathname)
int21
END SUB
SUB createfile
DIM createfilename AS STRING * 255
INPUT "Enter name and path of file to create: ", f$
createfilename = f$
' inregs:
' .ax: service - 716Ch
' .bx: access mode and sharing flags
' .dx: action (bits: 0=open; 1=truncate; 4=create)
' .ds: segment of pathname
' .si: offset of pathname
inregs.ax = &H716C
inregs.dx = (2 ^ 4)
inregs.ds = VARSEG(createfilename)
inregs.si = VARPTR(createfilename)
int21
' When the file has been created you could get its short filename and
' write to it. I think that you may need to close the file using an
' interrupt before you do that though... I don't know what it is. Sorry!
END SUB
SUB drawwindow (x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS INTEGER, col
AS INTEGER)
COLOR 7, col
FOR i% = y1 TO y2
LOCATE i%, x1
PRINT STRING$(x2 - x1, " ")
NEXT i%
' draw corners
LOCATE y1, x1: PRINT CHR$(218)
LOCATE y1, x2: PRINT CHR$(191)
LOCATE y2, x1: PRINT CHR$(192)
LOCATE y2, x2: PRINT CHR$(217)
' draw edges
LOCATE y1, x1 + 1: PRINT STRING$(x2 - x1 - 1, 196)
LOCATE y2, x1 + 1: PRINT STRING$(x2 - x1 - 1, 196)
FOR y% = y1 + 1 TO y2 - 1
LOCATE y%, x1
PRINT CHR$(179);
NEXT y%
FOR y% = y1 + 1 TO y2 - 1
LOCATE y%, x2
PRINT CHR$(179);
NEXT y%
END SUB
FUNCTION getcurrentdir$
DIM thedir AS STRING * 255
' inregs:
' .ax: service - 7147h
' .dx: 0=default, 1=A:, 2=B:, 3=C:, 4=D: etc.
' .ds: segment of buffer
' .si: offset of buffer
inregs.dx = &H0
inregs.ax = &H7147
inregs.ds = VARSEG(thedir)
inregs.si = VARPTR(thedir)
int21
' This line truncates thedir up to the first null character:
d$ = truncate$(thedir)
' This line adds the backslash if not present, as the backslash may or may
' not be present already. If you don't want the backslash there ever, modify
' this line:
IF RIGHT$(d$, 1) <> "\" THEN d$ = d$ + "\"
getcurrentdir$ = d$
END FUNCTION
SUB getvolumeinfo (drive$)
' inregs:
' .ax: service - 71A0h
' .ds: segment of rootname
' .dx: offset of rootname
' .es: segment of buffer for file system name
' .di: offset of buffer for file system name
' .cx: size of file system name buffer
DIM rootname AS STRING * 4
DIM filesysname AS STRING * 255
rootname = drive$ + CHR$(0)
inregs.ax = &H71A0
inregs.ds = VARSEG(rootname)
inregs.dx = VARPTR(rootname)
inregs.es = VARSEG(filesysname)
inregs.di = VARPTR(filesysname)
inregs.cx = 255
int21
IF outregs.ax = &H7100 THEN
BEEP
PRINT "LFN functions are not supported; exiting program..."
END
END IF
filesystem$ = truncate$(filesysname)
IF outregs.bx AND 2 ^ 0 THEN casesensitive% = 1 ELSE casesensitive% = 0
IF outregs.bx AND 2 ^ 1 THEN preservecase% = 1 ELSE preservecase% = 0
IF outregs.bx AND 2 ^ 2 THEN unicode% = 1 ELSE unicode% = 0
IF outregs.bx AND 2 ^ 14 THEN lfnfunctions% = 1 ELSE lfnfunctions% = 0
IF outregs.bx AND 2 ^ 15 THEN compressed% = 1 ELSE compressed% = 0
END SUB
SUB int21
CALL INTERRUPTX(&H21, inregs, outregs)
END SUB
SUB setdirectory
DIM pathname AS STRING * 255
INPUT "Enter FULL path of sub-directory: "; p$
pathname = p$
' inregs:
' .ax: service - 713Bh
' .ds: segment of pathname
' .dx: offset of pathname
inregs.ax = &H713B
inregs.ds = VARSEG(pathname)
inregs.dx = VARPTR(pathname)
int21
END SUB
SUB showdirectory
' get volume label
DIM vollable AS STRING * 500
DIM filespec AS STRING * 4
filespec = "*.*" + CHR$(0)
inregs.ax = &H714E
inregs.ds = VARSEG(filespec)
inregs.dx = VARPTR(filespec)
inregs.es = VARSEG(vollable)
inregs.di = VARPTR(vollable)
inregs.cx = &H808
inregs.si = &H0
int21
vol$ = truncate$(MID$(vollable, &H2D, 260)) ' truncate string to null char.
vol$ = LEFT$(vol$, 8) + RIGHT$(vol$, 3) ' get rid of the dot
COLOR 9: PRINT "Volume label is "; vol$; "."
COLOR 7
quitloop = 0
' What's done:
' first, call 714Eh to find first matching file, then call 714Fh to find
' next matching file and so on. Use 71A1h to stop the search.
' Attributes masks:
' Bit: 4 = directory
' 3 = volume label
' 2 = system
' 1 = hidden
' 0 = read-only
' ax=&h714E (service)
' ds:dx = filespec, e.g. *.*
' es:di = finddata record (see below)
' cl = allowable attributes mask, set here to F7, i.e ALL attributes allowed
' except for volume label.
' ch = required attributes mask, set here to 00 so NO attributes required
DIM finddatarecord AS STRING * 500
' filespec must be DIMmed as STRING * x, this is already done above.
filespec = "*.*" + CHR$(0)
inregs.ax = &H714E
inregs.ds = VARSEG(filespec)
inregs.dx = VARPTR(filespec)
inregs.es = VARSEG(finddatarecord)
inregs.di = VARPTR(finddatarecord)
inregs.cx = &HF7
inregs.si = &H0
int21
filefindhandle = outregs.ax
numfiles = 1
DO
' finddatarecord$ is now filled with loads of information about the file
' we've retrieved (info from Ralf Brown's Interrupts List):
' offset 00h bits 0-6 are standard DOS file attribs
' 04h QWORD file creation time
' 0Ch QWORD last access time
' 14h QWORD last modification time
' 1Ch DWORD file size (high 32 bits)
' 20h DWORD file size (low 32 bits)
' 2Ch 260bytes ASCIZ full filename
' 130h 14bytes ASCIZ short filename
' If required, you could interpret all that stuff but we're only interested
' in the filenames for now:
longfilename$ = truncate$(MID$(finddatarecord, &H2D, 260))
shortfilename$ = truncate$(MID$(finddatarecord, &H131, 14))
' NOTE that shortfilename$ will contain nothing if the short filename
' is *exactly* the same as the long file name.
PRINT longfilename$; TAB(30); shortfilename$
' If longfilename$ is null, we've reached the end of the list.
IF longfilename$ = "" THEN PRINT "*** END OF LIST; PRESS A KEY ***": EXIT DO
' reset finddatarecord
finddatarecord = STRING$(500, 0)
inregs.ax = &H714F
inregs.bx = filefindhandle
int21
IF numfiles MOD 20 = 0 THEN
COLOR 14
PRINT ">> Press a key <<"
COLOR 7
a$ = INPUT$(1)
IF a$ = CHR$(27) THEN quitloop = 1
END IF
numfiles = numfiles + 1
LOOP UNTIL quitloop = 1
IF quitloop = 0 THEN a$ = INPUT$(1)
' It's important to reset the filefind handle:
inregs.ax = &H71A1
inregs.bx = filefindhandle
int21
END SUB
SUB showinfo
getvolumeinfo ("C:\")
PRINT "File system is: "; filesystem$
PRINT
PRINT "Searches are case sensitive:"; casesensitive%
PRINT "Preserves case in directory entries:"; preservecase%
PRINT "Uses unicode chars in file and dir names:"; unicode%
PRINT "Supports DOS LFN functions:"; lfnfunctions%
PRINT "Compressed volume:"; compressed%
END SUB
FUNCTION truncate$ (s$)
' Truncates s$ to first null character
truncate$ = LEFT$(s$, INSTR(s$, CHR$(0)) - 1)
END FUNCTION
If you run this rather un-user-friendly program from Windows 95 (it won't work
with QBasic, you'll need QB4.5 or better loaded with /L) you'll see that it
works.
How? Well, it's all quite simple really, though it took me a while to figure it
out - maybe because I'm stupid, I dunno... anyway: basically, all each
subroutine does is call interrupt 21h (that means the hexadecimal number 21)
with the required service (specified by inregs.ax) and the required tags
(specified by the other inregs thingies). Usually these tags include a string,
and to pass a string to an interrupt you need to use a pointer to that string.
A pointer is basically a number referring to a specific part of the computer's
memory, and is a concept that will familiar to the C++ programmers amongst us,
though it's not often used in BASIC unless you're writing more complex programs
using C++ libraries and such. If you look at the information for interrupts you
see in books and on Ralf Brown's list, you'll see things such as "DS:DX - ASCIZ
pathname". This means a string where DS (i.e, inregs.ds) specifies the segment
in memory of the string, and DX specifies the string's location within that
segment. ASCIZ just means a string with a null character at the end - you can
get one of these in BASIC by using CHR$(0).
In QB, we can get the segment of the string using VARSEG and the string's
location within that segment with VARPTR. This appears to work for fixed-length
strings only - if you want to do the same with a variable length string you
must use SADD in place of VARPTR.
For example, if pathname is a string containing a pathname, we can pass it to
the interrupt using this:
inregs.ds = VARSEG(pathname)
inregs.dx = VARPTR(pathname)
Note that other services may want the pathname/filename to be in other places
instead of DS:DX, so check your documentation. (If you have the time you can
download the entire of Ralf Brown's interrupts list from his website - it's
about 8mb).
So, this program should be enough to get you started using long filenames from
QB. It wouldn't be too hard to make a library from it if you wanted to, and it
would be quite a useful library to have. However, these long filename functions
obviously won't work in anything less than Windows 95. There are equivalent
functions though, that work with short filenames. It would be a good idea to
make a library that detected whether LFN functions were available, and if not
then replace the LFN services with the equivalent SFN service. This is (almost)
really easy - the equivalent of an LFN service 71xxh is xx00h, so all you would
need to do hopefully would be to add that to the int21 subroutine. (To detect
whether LFN functions are available, look at the program - this detects for LFN
functions when it starts). That would keep users of Windows and users of DOS
(however rare they are these days) happy. Also, bear in mind that LFN functions
require Windows to be running - if you are running in MS-DOS mode (not in an
MS-DOS window from Win95) then the LFN functions won't work.
Have fun!
*** GRAPHICS IN QBASIC TUTORIAL (PART 2), by "Hacker" aka Damian Nikodem ·
Hacker@alphalink.com.au
For todays lesson we will be covering PCX images! Now because we are covering a
FILE FORMAT I will split the Tutorial into Diffrent Sections. The sections
needed for PCX images are:
HEADER
IMAGE DATA
PALETTE
HEADER:
The header is ALWAYS 128 bytes and most of the data you will not even use so I
will not cover it here. But if you really want it you can goto:
www.alphalink.com.au/~hacker/pcxinfo.htm for all of the information but trust
me its not really worth the download time but there is a slight bit of
information that is very useful and that is the X and Y sizes of the image. But
that would make the program a LOT larger than I would want to send (I have a
VERY slow conection to my mail server) but here is the formula for figuring out
the size of the image:
' Start CODE
TYPE pcxheader
MAN AS STRING * 1: VER AS STRING * 1: ENC AS STRING * 1: bit AS STRING * 1
xls AS INTEGER: yls AS INTEGER: xms AS INTEGER: yms AS INTEGER
HRE AS INTEGER: VRE AS INTEGER: col AS STRING * 48: RES AS STRING * 1
PLA AS STRING * 1: BYT AS INTEGER: pal AS INTEGER: FIL AS STRING * 58
END TYPE
DIM dat AS pcxheader
file$ = "Image1.pcx"
OPEN file$ FOR BINARY AS #1
GET #1, , dat
PRINT dat.XMS - dat.XLS + 1; " Is the size of the X plane"
PRINT dat.YMS - dat.YLS + 1; " Is the size of the Y plane"
' End CODE
All of that just to see what the size of the image is. This wouldnt be to hard
to implement into a normal pcx loader but the problem is that my loader writes
to memory (like I explained in part 1) and because it is only designed to
handle 320x200 it works a LOT faster.
IMAGE DATA:
The data in the image is easy to handle A pcx image is almost a direct screen
to memory dump with 1 single execption. If the number that is read is over 192
and under or equal to 255 then it starts a small loop and this lets us get a
small compression ratio (1/1.2) on the average image without much work being
done. Well heres the code to load a 320x200 image:
' START CODE
h$ = string$(128,32)
file$ = "IMAGE1.PCX" 'Image you want to load
screen 13
DEF SEG = &HA000
OPEN file$ FOR BINARY AS #1
GET #1, 1, h$ ' Gets rid of header (We dont need it)
FOR c = 1 TO 64000 ' Starts a loop with 64000 (the number of pixels) repeats
GET #1, , dat$ ' Gets image data
IF ASC(dat$) > 192 AND ASC(dat$) <= 255 THEN ' If data > 192 continue
lps = ASC(dat$) - 192 ' Take 192 away from number we got store number in LPS
GET #1, , dat$ ' Get more data
VALUE = ASC(dat$) ' Convert data into number
FOR cnum = lps TO 1 STEP -1 ' start loop with LPS repeats
POKE x, VALUE ' put 1 pixel to the screen at position X
x = x + 1 ' add 1 to X
NEXT cnum ' goto start of loop if its not done
ELSE ' If the first data we got was < 192 then we get put here
POKE x, ASC(dat$) ' Put that first data to the screen at position X
x = x + 1 'increment X
END IF ' End If (duh!!)
NEXT c ' goto start of loop if its not done
'PAUSE CODE
Now what have you notaiced about that code apart from you cant make heads or
tails of it??? If you run it the colors off. Do you remember what I said in
part one about the palette and how you can redefine the colors well you can now
put it into action!
PALETTE:
The palette in a PCX file is not all ways the exact same palette as the
standard so the last 768 bytes of a pcx image are just palette data. The format
for the pallete data is quite simple. it contains 256 * 3 ascii charecters.
Each charecter is one part of the color so the first charecter is the red value
for color 0 the second is the Green value for the color 0, the third charecter
is the blue value for color 0,and so on this is repeated until color 255 is
reached. Here is the final piece of code for the PCX loader:
' START CODE
h$ = string$(128,32)
file$ = "IMAGE1.PCX" 'Image you want to load
screen 13
DEF SEG = &HA000
OPEN file$ FOR BINARY AS #1
GET #1, 1, h$ ' Gets rid of header (We dont need it)
FOR c = 1 TO 64000 ' Starts a loop with 64000 (the number of pixels) repeats
GET #1, , dat$ ' Gets image data
IF ASC(dat$) > 192 AND ASC(dat$) <= 255 THEN ' If data > 192 continue
lps = ASC(dat$) - 192 ' Take 192 away from number we got store number in LPS
GET #1, , dat$ ' Get more data
VALUE = ASC(dat$) ' Convert data into number
FOR cnum = lps TO 1 STEP -1 ' start loop with LPS repeats
POKE x, VALUE ' put 1 pixel to the screen at position X
x = x + 1 ' add 1 to X
NEXT cnum ' goto start of loop if its not done
ELSE ' If the first data we got was < 192 then we get put here
POKE x, ASC(dat$) ' Put that first data to the screen at position X
x = x + 1 'increment X
END IF ' End If (duh!!)
NEXT c ' goto start of loop if its not done
GET #1, LOF(1) - 768, dat
FOR c = 0 TO 255
GET #1, , dat
r& = INT(ASC(dat) / 4)
GET #1, , dat
b& = INT(ASC(dat) / 4)
GET #1, , dat
g& = INT(ASC(dat) / 4)
OUT &H3C8, c
OUT &H3C9, r&
OUT &H3C9, g&
OUT &H3C9, b&
NEXT c
CLOSE
'END CODE
Now you know how to load PCX images in basic! Keep this code (The entire
loader) because next issue I will be discussing RANDOMIC GRAPHICS. The jpg
loader is being postponed until I fully understand the format this may be a few
months ( or years have you seen the size of the DOCS)
NOTE:
Also go down to the store and BUY quake 2 it is well worth it! if you dont have
the money at least download the shareware (11 Mb) from www.quake2.com I will be
using screen shots from the game in the next part also
- Hacker hacker@alphalink.com.au
*** YOUR PROGRAMS - YOUR RIGHTS, by Alex Warren · alexwarren@writeme.com
I've written this article to explain to you about copyright laws and how they
affect you and your programs - I hope it will be of help to some of you. I'm
not an expert on this subject - all information has been gathered from various
copyright FAQs I've researched. If you require more information I suggest you
visit one of the copyright newsgroups, or better, consult your lawyer.
Copyright:
EVERY program you have already written yourself is copyrighted - to you. You do
not need to register it with anyone - you already own the rights to it.
Copyright registration is unneccessary and is only a good idea in circumstances
where you're likely to need to prove copyright ownership, which isn't often.
So, the quick and easy step to ensure that your software is copyrighted in all
countries of the world is to do nothing! OK, so a sentence such as "Copyright ©
1998 Whatever Software" isn't going to hurt - in fact, it's a good idea to add
a statement as it reinforces the applicable laws by demonstrating copyright
ownership.
Most countries in the world share copyright laws. If you're a resident of the
US, your software is still protected even when used in the UK, or France, for
example.
So, the message is: Your software, and in fact anything that you write or
compose or draw, is already your own intellectual property. You have rights to
it already.
Public domain and Freeware:
Just because you distribute something as freeware does not mean that you've
abandoned your rights to it. If you give away your applications for free, it is
still illegal for others to distribute them without permission. This makes it
technically illegal to distribute even a freely distributed piece of software
such as QBasic, if Microsoft has not given permission for you to do so
(permission could take the form of a letter to you, or a statement in the help
file giving permission to distribute the software free of charge, etc.) If you
want your application to be distributed freely by others then it's usually a
good idea to put in a phrase such as "This software may be distributed freely
on provision that no charge is made for it", etc.
"Public domain" software is different. You can release something into the
public domain by saying something like "This software is hereby released into
the public domain" somewhere in the software or in its documentation. If you
put something in the public domain then you abandon all your copyright rights
to it. So, don't say "public domain" when you really mean "freeware" - you
won't be able to stop people selling it, giving it away, etc. - other people
will have just the same copying rights to it as you do. If you ever see a
notice on some software you've downloaded saying "This software is released
into the public domain for non-commercial use", then don't believe it. That
sentence contradicts itself. By donating the software to the public domain, the
programmer has abandoned all rights to the software, making it theoretically
possible for anybody to sell it on for trillions of dollars/pounds/etc. (not
that anybody is neccessarily going to buy it, though). So, always remember -
there is a massive difference between "public domain" and "freeware". The two
terms are not inter-changable. So, even though QBasic is given away freely, it
is not "Public domain".
Copyright expiration:
Copyright doesn't last forever. In the case of individuals, it expires 75 years
after the death of the creator (I think - though I did read somewhere that it
was only 70 years within the EC so I may well be completely wrong). This means
that, in 1998, anything written by anybody who died before 1923 is now in the
public domain, and anything written by anybody who died after 1923, or is still
alive, is still under copyright. The case is different with computer programs,
however - this expires 50 years from the date of creation, if my sources are
correct. This means that you will be able to distribute QuickBasic freely and
legally any time after the year 2038, whether or not Mr. Gates is still
around... still, I'm sure you'll be able to find a way to pass the time.
*** WHY (MOST) ON-LINE PROGRAMMING TUTORIALS SUCK!
Disclaimer
The opinions expressed by RudeJohn do not necessarily reflect the opinions of
the Basix Fanzine or its staff. In fact, they probably disagree with me
entirely. Everyone else does. <grin>
Forward
Regardless of the title, this editorial is not an attack upon any person or
persons. Rather, it is an attack upon the ill-conceived approach to writing
on-line programming tutorials which the internet continues to engender.
It's Geek to Me!
If I had a nickel for every Usenet post that said something like this:
"I've never programmed before, but I want to learn how to program in
<language>. Can anyone tell me if there is a free tutorial on the internet that
will teach me how to program in <language>?"
Didn't Yoda warn Luke that the dark side of the force was "easier, more
seductive"? Well, that's the warning I would give anyone who thought that they
could learn how to program from a language-specific tutorial. Although the
reader will no doubt learn something about programming in <language>, he may
never appreciate the simple fact that learning to program, and learning to
program "in", are just not the same thing.
It's been said that the most famous algorithm in history is Euclid's algorithm
for calculating the greatest common divisor of two integers. Correct me if I'm
wrong, but I don't think that Euclid knew the difference between an Intel
processor and a 3-pack of rubbers. Yet, without benefit of MMX technology or
prophylactics, Euclid formulated an idea which today exemplifies the nature of
procedural programming. Obviously, an algorithm is not a computer program. An
algorithm is a description of a method, and a program is an implementation of
that method. While programming languages are limited by their syntax , an
algorithm is limited by nothing less than the imagination.
Learning to program "in" burdens the hobbyist with all of the baggage peculiar
to a specific language. On the other hand, learning to program in spite of a
specific language enables the hobbyist to recognize what different languages
have in common. Once that commonality is established, it becomes far easier to
take advantage of the differences between programming languages because those
differences become features rather than obstacles.
It's unlikely that any hobbyist would want to learn programming from a purely
theoretical point of view. Who can resist the lure of writing and running a
working program? Nonetheless, a little practical application is good for the
ego. The sensible approach lies somewhere between the extremes of theory and
application. IMHO, a healthy dose of theory should proceed a first attempt at
programming "in", while further doses of theory should be endured at regular
intervals as the hobbyist becomes more facile with his language(s) of choice.
End Game
IMHO, learning to program should not be sacrificed for the sake of learning to
program "in." If the reader is going to depend upon language-specific tutorials
to teach him how to program, then he is -- as far as I am concerned -- in very
deep fertilizer. Every concept that a language-specific tutorial presents must
be filtered through the syntax of that programming language. As a result, the
tutorial will discourage the reader from pursuing any idea which is beyond that
language's ability to express.
Q: How would you illustrate an idea using a programming language which was
designed to ignore that idea?
A: Badly.
C'ya,
RudeJohn
"I'm rude. It's a job."
*** TESTING MATRIX SOFTWARE
Disclaimer
This paper is the result of an elementary exercise in combinatorics.
This program (aka 11-ctln.bas) was play-tested in the QB 4.5 IDE:
DECLARE FUNCTION Cat# (n AS INTEGER)
DIM Number AS INTEGER
CLS
LOCATE 2, 1
PRINT STRING$(40, "=")
PRINT " Calculate the Catalan number for n"
PRINT STRING$(40, "-")
LOCATE 18, 1
PRINT STRING$(40, "-")
PRINT " Enter 0 to Exit"
PRINT STRING$(40, "=")
VIEW PRINT 6 TO 16
DO
INPUT "Enter n: ", Number
SELECT CASE Number
CASE IS <= 0
END
CASE IS = 1
PRINT "You're a business major, right?"
PRINT
CASE IS = 2
PRINT "How's the lobotomy working out?"
PRINT
CASE ELSE
PRINT "Cat("; Number; ") ="; Cat#(Number)
PRINT
END SELECT
LOOP
FUNCTION Cat# (n AS INTEGER)
DIM Denom AS DOUBLE
DIM Numer AS DOUBLE
DIM Result AS DOUBLE
DIM I AS INTEGER
' Cat(n) was derived from the following identity:
'
' (2n - 2)! (n + 1)(n + 2) ... (2n - 2)
' ----------- = ---------------------------
' (n - 1)! n! (n - 1)!
' First, we calculate the numerator.
Numer = n + 1
FOR I = (n + 2) TO ((2 * n) - 2) ' Condition: n >= 3
Numer = Numer * I
NEXT I
' Next, we calculate the denominator.
Denom = 1
FOR I = 2 TO (n - 1) ' Condition: n >= 3
Denom = Denom * I
NEXT I
' Taking a/b directly for large integers is inefficient. However,
' it's good enough to make the point that a brute-force approach
' is inadequate to the task of finding the best case for chained
' matrix multiplication.
Result = Numer / Denom
' Obviously, using floating-point numbers is going to cause a
' problem so we filter Result accordingly.
IF (Result - INT(Result)) >= .499999999999998# THEN
Cat = INT(Result) + 1
ELSE
Cat = INT(Result)
END IF
END FUNCTION
Notation
Let A[x,y] represent a matrix of dimensions x and y.
If A and B are matrices, then AB represents their product such that
(A[x,y])(B[y,z]) = (AB)[x,z].
By the Numbers
For any two integer matrices A[x,y] and B[y,z], the direct method of
calculating (AB)[x,z] requires y multiplications for each element of AB. Since
AB has x*z elements, the total number of multiplications required to calculate
AB is given by x*y*z.
Matrix multiplication is associative, i.e., A(BC) = (AB)C. If we multiply four
matrices then the product may be grouped in five different ways:
((AB)C)D
(AB)(CD)
(A(BC))D
A((BC)D)
A(B(CD))
The question is, does the order in which this operation is carried out have a
significant effect upon efficiency?
It's obvious that for square matrices of the same dimension the total number of
multiplications required for ABCD is the same no matter how we group the
product. For argument's sake, let's try:
A[ 4,40]
B[40, 2]
C[ 2,11]
D[11,20]
The total number of multiplications required for each grouping is shown in the
following table.
Grouping Complexity =
1 ((AB)C)D (4*40*2) + (4*2*11) + (4*11*20) 1,288
2 (AB)(CD) (4*40*2) + (2*11*20) + (4*2*20) 920
3 (A(BC))D (40*2*11) + (4*40*11) + (4*11*20) 3,520
4 A((BC)D) (40*2*11) + (40*11*20) + (4*40*20) 12,880
5 A(B(CD)) (2*11*20) + (40*2*20) + (4*40*20) 5,240
Grouping 4 requires 14 times as many multiplications as grouping 2. Evidently,
the order in which the multiplication of several matrices is carried out can
have a considerable effect upon efficiency.
Under the right circumstances, this simple observation might be put to the test
as a measure of a matrix software package's sophistication.
Catalan Numbers
The number of different groupings for a product of n matrices is called the
Catalan number for n, and is generated by the following formula:
Catalan(n) = ((2 * n) - 2)! / ( (n - 1)! * n! )
where x! (read "x factorial") = 1 * 2 * ... * (x - 1) * x.
The program 11-ctln.bas generates the Catalan number for n. If you run the
program you will see why it is not practical to use a brute-force approach for
finding the best, or even the worst, case of a matrix product as n increases.
C'ya,
RudeJohn
"I'm rude. It's a job."
*** HIT-OR-MISS INTEGRATION
[note: this article contains squared-signs which in the HTML are superscript
from the text. This is obviously not possible in plain old text format so some
of the formulae may be hard to read here :( ]
Warning: All code was play-tested in the QB 4.5 IDE.
Introduction
This article discusses the simplest type of probabilistic numerical integration
which is sometimes referred to as the hit-or-miss Monte Carlo method. This
approach may not compete with deterministic methods in general, but it's
something to think about when you wake up in a cold sweat at 4 a.m. I guess.
<shrug>
Parabolas
Consider the definite integral of x 2 from x = 0 to x = 1. Anyone who's had an
introduction to calculus will remember that the indefinite integral of x 2 is
given by (1/3) x 3 + C, where C is a constant. It follows that the value of the
definite integral is equal to [(1/3) 1 2 + C] - [(1/3) 0 2 + C] = 1/3. In other
words, the magnitude of the area under the graph of y = x 2 from (0,0) to (1,1)
is equal to 1/3.
That said, let's find the value of the definite integral in a very different
fashion as outlined by the following algorithm. For the sake of discussion,
random is an ideal random-number generator over [0,1] while num represents the
number of randomly-generated points.
procedure estimate_area
area = 0
loop from 1 to num {num > 0}
x = random
y = random
if y 2 then (area = area + 1)
end loop
return (area / num)
end procedure
If all goes well, this algorithm should return an estimate to within 99%
accuracy or better. This is not significant in terms of absolute error, but
what do you expect? Fortunately, the rationale is quite simple. (If it wasn't,
I'd have to find someone who could explain it to me.) For a sufficiently large
number of randomly-generated points, the number of points in one unit-area
should be nearly equal to the number of points in any other unit-area. This
means that any area A n is proportional to P n the number of points it
contains. So, if A 1 = k P 1 and A 2 = k P 2 then A 1 / A 2 = ( k P 1 ) / ( k P
2 ) or A 1 / A 2 = P 1 / P 2. See 11-x2.bas:
DIM Point2D AS DOUBLE
DIM Number AS DOUBLE
DIM Hits AS DOUBLE
DIM Diff AS DOUBLE
DIM Estimate AS DOUBLE
DIM Accuracy AS DOUBLE
DIM StartTime AS LONG
CLS
LOCATE 2, 1
PRINT STRING$(40, "=")
PRINT " Hit-or-Miss Estimate of y = x^2"
PRINT STRING$(40, "-")
LOCATE 21, 1
PRINT STRING$(40, "-")
PRINT " Enter 0 to Exit"
PRINT STRING$(40, "=")
VIEW PRINT 5 TO 20
INPUT "Number of Points: ", Number
WHILE Number > 0
RANDOMIZE (INT(INT(TIMER) * 4369 / 5760) - 32768) ' Scale the seed
' for 24 hours.
Hits = 0
FOR Point2D = 1 TO Number
IF RND <= RND ^ 2 THEN
Hits = Hits + 1
END IF
NEXT Point2D
PRINT
PRINT "Area"; TAB(15); 1# / 3#
Estimate = Hits / Number
PRINT "Estimate"; TAB(15);
PRINT USING "#.################"; Estimate
Diff = (1# / 3#) - Estimate
PRINT "Difference"; TAB(15);
PRINT USING "#.################"; Diff
Accuracy = 100 * (1 - ((1# / 3#) - Estimate) / (1# / 3#))
PRINT "Accuracy"; TAB(13);
PRINT USING "###.##%"; Accuracy
PRINT
INPUT "Number of Points: ", Number
WEND
END
The reader is invited to generalize the above algorithm for y = f(x) over the
interval [a,b]. Is this practical? What do you need to know about f(x) over
[a,b] before applying our hit-or-miss method?
Pi a la Rude
Consider a circle of diameter D inscribed within a square of area D 2. The
ratio of the area of the circle to the area of the square is pi / 4. As with
the previous example, we will use randomly-generated points to find an
approximate value for pi. If D = 1 and the center-point of the circle is
(0.5,0.5), then our test for points which lie on the disk is (x - 0.5) 2 + (y -
0.5) 2 2. See 11-pi2d.bas:
DIM Point2D AS DOUBLE
DIM Number AS DOUBLE
DIM Hits AS DOUBLE
DIM Diff AS DOUBLE
DIM Estimate AS DOUBLE
DIM Accuracy AS DOUBLE
DIM StartTime AS LONG
CONST Pi = 3.141592653589793#
CLS
LOCATE 2, 1
PRINT STRING$(40, "=")
PRINT " 2-Dimensional Estimate of Pi"
PRINT STRING$(40, "-")
LOCATE 21, 1
PRINT STRING$(40, "-")
PRINT " Enter 0 to Exit"
PRINT STRING$(40, "=")
VIEW PRINT 5 TO 20
INPUT "Number of Points: ", Number
WHILE Number > 0
RANDOMIZE (INT(INT(TIMER) * 4369 / 5760) - 32768) ' Scale the seed
' for 24 hours.
Hits = 0
FOR Point2D = 1 TO Number
IF ((RND - .5#) ^ 2 + (RND - .5#) ^ 2) <= .25# THEN
Hits = Hits + 1
END IF
NEXT Point2D
PRINT
PRINT CHR$(227); TAB(15); Pi
Estimate = 4# * (Hits / Number)
PRINT "Estimate"; TAB(15); Estimate
Diff = Pi - Estimate
PRINT "Difference"; TAB(15);
PRINT USING "##.###############"; Diff
Accuracy = 100# * (1# - Diff / Pi)
PRINT "Accuracy"; TAB(13);
PRINT USING " ###.##%"; Accuracy
PRINT
INPUT "Number of Points: ", Number
WEND
END
Funny thing is, if we restrict our randomly-generated points to the
line-segment from (0,0) to (1,1), the ratio of the total number of points on
the line-segment to the number of points on the circle's diameter approaches 2
1/2. Why?
By now, you must be wondering if this experiment can be extended to three
dimensions. Well, of course it can! <grin> This time, we'll need a sphere of
diameter D within a cube of volume D 3. If Vs and Vc represent the volume of
the sphere and the cube, respectively, then Vs / Vc = pi / 6. Our test for
points that lie within the ball is (x - 0.5) 2 + (y - 0.5) 2 + (z - 0.5) 2 2.
See 11-pi3d.bas:
DIM Point2D AS DOUBLE
DIM Number AS DOUBLE
DIM Hits AS DOUBLE
DIM Diff AS DOUBLE
DIM Estimate AS DOUBLE
DIM Accuracy AS DOUBLE
DIM StartTime AS LONG
CONST Pi = 3.141592653589793#
CLS
LOCATE 2, 1
PRINT STRING$(40, "=")
PRINT " 3-Dimensional Estimate of Pi"
PRINT STRING$(40, "-")
LOCATE 21, 1
PRINT STRING$(40, "-")
PRINT " Enter 0 to Exit"
PRINT STRING$(40, "=")
VIEW PRINT 5 TO 20
INPUT "Number of Points: ", Number
WHILE Number > 0
RANDOMIZE (INT(INT(TIMER) * 4369 / 5760) - 32768) ' Scale the seed
' for 24 hours.
Hits = 0
FOR Point2D = 1 TO Number
IF ((RND - .5#) ^ 2 + (RND - .5#) ^ 2 + (RND - .5#) ^ 2) <= .25# THEN
Hits = Hits + 1
END IF
NEXT Point2D
PRINT
PRINT CHR$(227); TAB(15); Pi
Estimate = 6# * (Hits / Number)
PRINT "Estimate"; TAB(15); Estimate
Diff = Pi - Estimate
PRINT "Difference"; TAB(15);
PRINT USING "##.###############"; Diff
Accuracy = 100# * (1# - Diff / Pi)
PRINT "Accuracy"; TAB(13);
PRINT USING " ###.##%"; Accuracy
PRINT
INPUT "Number of Points: ", Number
WEND
END
This time, if we restrict our randomly-generated points to the line-segment
from (0,0,0) to (1,1,1), the ratio of the total number of points on the
line-segment to the number of points on the sphere's diameter approaches 3 1/2.
Why?
Hyperspace
The next logical(?) step is to generalize our experiment using n-dimensional
hyperspatial objects, i.e., the hypersphere and hypercube.
Let Vs represent the "volume" of an n-dimensional hypersphere of diameter D.
Let Vc = D n represent the "volume" of an n-dimensional hypercube.
If n is even, Vs / Vc = pi m / ( m! 2 n) where m = n / 2.
If n is odd, Vs / Vc = ( m! pi m ) / n! where m = (n - 1)/ 2.
The reader is invited to write a program that will use our probabilistic
calculation of Vs / Vc to estimate pi in the general case. Keep in mind that
the formula for an n-dimensional hypersphere of radius R is given by
x12 + x22 + ... + xn2 = R 2.
Everyone who submits an entry to the Basix Fanzine will receive a lifetime
subscription absolutely free! First prize is a lovely string of multi-colored
paper-clips. Really.
Extra Credit
If we restrict randomly-generated points in the hypercube to the line-segment
from (0,0,...,0) to (1,1,...,1), what can we say about the ratio of the number
of points on the line-segment to the number of points lying on the
hypersphere's diameter?
Addendum
Deterministic algorithms can sometimes be hybridized to include probabilistic
methodology. For example, the so-called "trapezoidal rule" may be improved(?)
as follows. Rather than using the mean of f(x) taken at the endpoints of an
interval [a,b], or [f(b) - f(a)]/2, we take the mean of f(x) for n
randomly-generated values of x over the interval [a,b], i.e., [ f(x 1) + f(x 2)
+ ... + f(x n)] / n for a i Once again, the reader is encouraged to submit
either an algorithm or example program employing this technique to the Basix
Fanzine for future publication. Let's face it, if you had anything better to do
then you wouldn't be reading this!
Addendum 2
Okay, an Addendum to the Addendum may be a bit much, but I just remembered
something. The mathematical mean of a series of values can be extremely
misleading if a few of those values are unusually high or low in comparison to
the rest of the series. In response to this problem, somebody came up with the
idea of the sample median.
To find the sample median, first sort the series of values in question. If n is
odd, the central element of the series is our sample median. If n is even, our
sample median is the mathematical mean of the two values at the center of the
series. I would very much like to see someone incorporate the use of the sample
median into a hit-or-miss Monte Carlo program. As usual, it would make a
smashing article for a future issue of the Basix Fanzine!
C'ya,
RudeJohn
"I'm rude. It's a job."
PS: If it looks as though I've been a bit heavy-handed in my constant
solicitation of articles for the 'zine all I can say is "Glad you noticed!" Now
why don't you write something up and send it in? Got an idea, an opinion, a
story, or even a good joke? Send it in! Heck, think of the 'zine as a
multi-newsgroup bulletin board. Advertise your website, your proggies, and even
your latest game! Please, talk to us. We're so lonely. <sniff>
-------------------------------------------------------------------------------
FROM THE NEWSGROUPS
*** INACCURACY IN GRAPHICS TUTORIAL IN ISSUE 10
From: kraken@mbox3.singnet.com.sg (Rory)
Newsgroups: alt.lang.basic
Subject: inaccuracy in Graphics Tutorial BASIX fanzine #10
Date: Mon, 30 Mar 1998 16:54:38 GMT
in the aforementioned tutorial by 'Hacker' aka Damian Nikodem, he claims that
POKEing straight to video memory is faster than Qbasic's PSET routine. he said,
quote, "a LOT faster". hearing everyone say Qbasic's PSET is way slow for
setting pixels, and that writing direct to the video memory is faster, i
decided to investigate this myself. i came up with this code:
'code to benchmark speed of PSET and
'POKEing straight to video memory
SCREEN 13
PRINT "Press any key to begin test."
SLEEP
'fill screen pixel by pixel with PSET
startPSET# = TIMER
FOR col% = 0 to 15
FOR y% = 0 to 199
FOR x% = 0 to 319
PSET(x%, y%), col%
NEXT x%
NEXT y%
NEXT col%
endPSET# = TIMER
'fill screen pixel by pixel with POKE
DEF SEG = &HA000
startPOKE# = TIMER
FOR col% = 0 to 15
FOR y% = 0 to 199
FOR x% = 0 to 319
POKE 320& * y% + x%, col%
NEXT x%
NEXT y%
NEXT col%
endPOKE# = TIMER
DEF SEG = 0
'print results
PRINT "Time taken with PSET:"; endPSET# - startPSET#
PRINT "Time taken with POKE:"; endPOKE# - startPOKE#
ok, the times i got on my P100 for the POKE routine were never more than 1.5
seconds faster than the PSET routine. most of the time it was only 0.2 seconds
faster. so POKEing direct to the video memory isn't "a LOT faster" than using
PSET. what annoys me more about the article is that he never specified his
variables to be of any type, therefore Qbasic defaults to type double i think,
which makes the POKE routine run ridiculously slow. it took about 2.5s for the
PSET routine with everything specified as short integer, and 30s for the POKE
with no specifier!! does ayone see something wrong about my test code? are my
conclusions correct? the only thing i see wrong is that POKE is not as fast as
it can be, because i have to put an ampersand after the 320 in
this line POKE 320& * y% + x%, col% otherwise Qbasic spews out an overflow
error. because of the long, it's not as fast as if i was able to keep
everything short. if it was possible to do this, then i believe that POKEing
would be much faster the PSET. comments anyone?
From: SimpleSi <NewsGroups@phillips1.demon.co.uk>
Newsgroups: alt.lang.basic
Subject: Re: inaccuracy in Graphics Tutorial BASIX fanzine #10
Date: Mon, 30 Mar 1998 18:46:09 +0100
It all depends on the processor and graphics card that you have. With a fast
processor, the multiplication is quicker, so poke is not slowed down. On my
lowly P90, poke was twice as fast as pset.
From: pb@excelsior.xs4all.nl (Marc van den Dikkenberg)
Newsgroups: alt.lang.basic
Subject: Re: inaccuracy in Graphics Tutorial BASIX fanzine #10
Date: Mon, 30 Mar 1998 19:48:11 GMT
On my P200, the code you nclosed here takes 2.5 seconds for PSET, and 1.6
seconds for POKE. That's more then 1.5 times as fast... I think that qualifies
as 'a lot', when things are time-critical...
From: kraken@mbox3.singnet.com.sg (Rory)
Newsgroups: alt.lang.basic
Subject: Re: inaccuracy in Graphics Tutorial BASIX fanzine #10
Date: Tue, 31 Mar 1998 15:05:30 GMT
ok, another run today gave me 7.367s for PSET and 6.695s for POKE. that's a
difference of about 1.1 for me. well, since my code is just filing the screen,
i shall take your word for it now, that 1.5 times is significant enough to be a
LOT faster. i will try out both methods in a real world program (probably a
game of some sort) and post results when i have time. unless someone would like
to beat me to it.
From: Krogg <krogg@inspace.net>
Newsgroups: alt.lang.basic
Subject: Re: inaccuracy in Graphics Tutorial BASIX fanzine #10
Date: Mon, 30 Mar 1998 17:28:13 -0500
in qbasic on my p75 under win95
12.30 for pset
9.77 for poke
in powerbasic 3.5 on my p75 under win95
Note:i used screen 7 in pb3.5 for pset
and mode 13h for the poke part.
Time taken with PSET: 13.2370438659709
Time taken with POKE: 1.48298831693683
looks damn faster
here is a test using dim absolute scrn(319,199) as byte at &ha000
for a video buffer overlay
ploting a point ="scrn(%x,%y)=%col"
Time taken with PSET: 13.0722673863129
Time taken with POKE: 2.85612564742769
still faster than pset
but
with some inline asm code instead of the poking like
! mov ax, &ha000
! mov es, ax
! mov ax, 320
! mul y%
! mov bx, x%
! add bx, ax
! mov al, col%
! mov es:[bx], al
ya get
Time taken with PSET: 12.5230124541195
Time taken with ASM: .823882398297428
Now thats fast!
now with another asm code for the poking
not much diff but uses byte for color insteat of integer
! MOV AX , 320
! MUL y%
! MOV DI , AX
! ADD DI , x%
! MOV DX , &hA000
! MOV ES , DX
! MOV AL , col%
! STOSB
Time taken with PSET: 12.4680869608928
Time taken with ASM: .823882398290152
as you can see,its allmost the same.
I hope this helps someone
By the way,the asm routines i got from Robert Seidel. I havent got the code
handy but a faster asm code uses shifts instead of muls somehow but i will
leave that for someone else to test.
*** UNLOCKING GWBASIC PROGRAMS
From: pb@excelsior.xs4all.nl (Marc van den Dikkenberg)
Newsgroups: alt.lang.basic
Subject: Re: Unlocking old BASIC programs
Date: Mon, 30 Mar 1998 19:48:09 GMT
On 30 Mar 1998 15:13:32 GMT, eppersond@aol.com (EppersonD) wrote:
>Does anyone know how to unlock old BASIC programs. Seems like it used BLOAD
>and BSAVE to do it. I have it in a manual somewhere but I moved recently and
>have not been able to find it. When you try to list a program it says "Illegal
>Function Call".
If you're talking about protected GW-Basic programs, here are two ways to do
it. It's something I found on the internet quite some time ago...
Here's a trick that often works:-
1. run GWBASIC.
2. LOAD the protected program.
3. type NEW and hit return.
4. type 0'* (The * is a placeholder for CHR$(15) - so that's zero,apostrophe,
ALT+15) and hit return.
5. you can now LIST and SAVE the file normally.
6. don't ask ME why it works.
Failing that write your own UNPROT.BAS program as follows:-
1.Run DEBUG and type in the following
E100 FF 1B
RCX
2
NUNPROT.BAS
W
Q
with a carriage return at the end of each line of course.
There will be some responses from DEBUG which can be ignored except that RCX
will present you with a colon input prompt instead of the usual hyphen.
That gets you a file which contains only two bytes, FF and 1B.
Now...
2. Run GWBASIC.
3. LOAD the program you want to unprotect.
4. LOAD UNPROT.BAS.
5. You will now find you can LIST (etc.) the original program.
6. Don't ask me why that works either.
I take no credit (or blame) for either. Both are old, old tricks which have
been around for so long that, it seems, they may have been forgotten.
*** SORTING RANDOM NUMBERS
From: crbates@cdmnet.com (Curt Bates)
Newsgroups: alt.lang.basic
Subject: Re: Sorting random numbers?
Date: Mon, 25 May 1998 23:23:57 GMT
"Retribution" <saturn@29.net> wrote:
>Thanks Ian but the problem lies in the generation of the numbers. I'm
>generating them one at a time so no two are the same. The numbers have
>already been generated by the time I need to sort them rather than
>generated in a DIM statement.
>So I have six numbers, no two alike that need to be sorted. The routine you
>sent was however handy...thanks!
>
>Ian Blakeley <root@127.0.0.1> wrote in article
><35632d1a.18028890@news.btinternet.com>...
>> Hope the attached helps, some of its from a book can't remeber which
>> and some I probably modified. 100 random nubers are generated, sorted
>> and displayed.
For six number you can use a simple bubble sort. Like this:
[Ed's note - I've modified this slightly to work properly in QB, and to print
the results at the end]
RANDOMIZE TIMER
DIM n(6)
CLS
' generate 6 randem numbers
FOR x = 1 TO 6
n(x) = INT(RND * 40)
NEXT
' sort the numbers
s = 1
WHILE s = 1
s = 0
FOR x = 1 TO 5
IF n(x) > n(x + 1) THEN
t = n(x)
n(x) = n(x + 1)
n(x + 1) = t
s = 1
END IF
NEXT
WEND
FOR x = 1 TO 6
PRINT n(x)
NEXT x
Hope this helps.
*** FAST KEYBOARD INPUT
From: pb@excelsior.xs4all.nl (Marc van den Dikkenberg)
Newsgroups: alt.lang.basic
Subject: Re: HOW CAN I MAKE FAST KEYBOARD INPUT ??
Date: Tue, 12 May 1998 21:21:39 GMT
On Tue, 12 May 1998 18:17:15 +0200, Jellyfish <jelle@casema.net> wrote:
>I was wandering how I could get fast keyboard input for a game in
>GW-Basic ??
I'm not sure if GW-BASIC supports this too, but...
Try:
A=INP(&H60)
This will read a character directly from the in-port, and is a LOT faster then
inkey$. It will take you some time to figure out the values it returns, though,
since it's a lot less 'friendly' then INKEY$.
you may need to insert A$=INKEY$ in your loop as well, though, since the method
shown above won't delete the characters from the keyboard buffer. If you don't
do this yourself, your computer will be beeping continuously because the buffer
is full...
Advantages: no delays whatsoever, extremely fast repeat rate, detect key press,
and key release -- keep track of multiple keys hold down simultaneously.
Disadvantages: more difficult to keep track off, and you have to find the
scancodes/release codes of the various keys somewhere first.
*** CLEARING THE KEYBOARD BUFFER
From: c1284j@aol.com (C1284J)
Newsgroups: alt.lang.basic
Subject: Re: Annoying beeps
Date: 22 Apr 1998 23:36:24 GMT
>>anyone know how to be rid of that annoying beeping
>>when one holds down a key too long in qbasic?
>
>That's not QBasic, it's the operating system complaining that the
>keyboard
>buffer is full, and all those extra keystrokes are being lost. Just let go of
>the key when you hear the first beep.
And here's the code to clear
the keyboard buffer:
DEF SEG = &H40
POKE &H1A, PEEK(&H1C)
POKE &H1B, PEEK(&H1D)
DEF SEG
'switch to BIOS data segment
'make the buffer head pointer
'equal then buffer tail pointer
'back to default data segment
*** POKE-ING CHARACTERS TO THE SCREEN
From: "Judson McClendon" <judmc@mindspring.com>
Newsgroups: alt.lang.basic,comp.lang.basic.misc
Subject: Re: POKE to screen?
Date: Wed, 22 Apr 1998 08:33:36 -0500
KKJOHN2 wrote:
>A while back someone posted code to POKE and PEEK characters to the
>screen. I want to sqeeze the last bit of speed out of my text boxes
>without using alot of advanced programing.
>If you can help, please email me below, I sometimes can't follow these
>groups. THANKX
Don't know if this is faster than PRINT, but here are routines to POKE
characters and strings to the screen:
' **************************************************
' * *
' * POKE.BAS *
' * *
' * Print Character or String *
' * to screen using POKE *
' * *
' * Judson D. McClendon *
' * Sun Valley Systems *
' * 329 37th Court N.E. *
' * Birmingham, AL 35215 *
' * 205-853-8440 *
' * *
' **************************************************
'
DECLARE FUNCTION BufAdd% (Lin%, Col%)
DECLARE SUB PokeByte (Lin AS INTEGER, Col AS INTEGER, Byte AS STRING)
DECLARE SUB PokeString (Lin AS INTEGER, Col AS INTEGER, Str AS STRING)
CLS
CALL PokeString(12, 34, "Hello World!")
END
FUNCTION BufAdd% (Lin AS INTEGER, Col AS INTEGER)
BufAdd% = (Lin - 1) * 160 + (Col - 1) * 2
END FUNCTION
SUB PokeByte (Lin AS INTEGER, Col AS INTEGER, Byte AS STRING)
DEF SEG = &HB800
POKE BufAdd%(Lin, Col), ASC(Byte)
DEF SEG
END SUB
SUB PokeString (Lin AS INTEGER, Col AS INTEGER, Str AS STRING)
DIM I AS INTEGER
DEF SEG = &HB800
FOR I = 1 TO LEN(Str)
POKE BufAdd%(Lin, Col + I - 1), ASC(MID$(Str, I, 1))
NEXT
DEF SEG
END SUB
*** TREE/PLANT FRACTALS
From: "Ali Afshar" <afshar@easynet.co.uk>
Newsgroups: comp.lang.basic.misc
Subject: Re: DRAW for plants in fishtank program
Date: Fri, 24 Apr 1998 02:27:40 +0100
Steve Rush wrote in message
>It's been a while since I saw any code, but search for "fractal" and "plant".
>There are iterative processes that can create very realistic shapes with a few
>equations.
Dear Gloria
I'm not sure whether this will meet your needs but here's a simple iterative
SUB for creating a different number of tree/plant fractals using different
initial input parameters. Any problems with the code, get in touch.
REM The SUB Tree uses the initial parameters (x,y,l,a,ang,lim%,m,c)
REM x is the start x
REM y is the start y
REM l is the initial branch length
REM a is the initial angle
REM ang is the angle of rotation for each successive branch
REM lim% is the branch length lower limit
REM m is the denominator for successive branch length
REM c is the colour
SUB tree (x, y, l, a, ang, lim%, m, c)
IF l > lim% THEN
LINE (x, y)-(x + l * COS(a), y + l * SIN(a)), c
LINE (x, y)-(x + l * COS(a), y + l * SIN(a)), c
CALL tree(x + l * COS(a), y + l * SIN(a), l / m, a + ang, ang, lim%, m, c)
CALL tree(x + l * COS(a), y + l * SIN(a), l / m, a - ang, ang, lim%, m, c)
END IF
END SUB
DECLARE SUB tree (x!, y!, l!, a!, ang!, lim%, m!, c!)
REM A simple tree fractal by Ali Afshar
SCREEN 13
CONST pi = 3.141593
WINDOW (-200, 0)-(200, 400)
REM This example draws a big white tree
CALL tree(0, 0, 50, pi / 2, pi / 6, 5, 1.3, 15)
REM This example draws 4 trees all at a pi/3 angle in random colours
FOR a = -100 TO 100 STEP 50
CALL tree(a, 0, 20, pi / 3, pi / 12, 5, 1.4, RND * 15)
NEXT a
END
Cheers,
Ali
** USING THE MOUSE IN QBASIC
From: steverush@aol.com (Steve Rush)
Newsgroups: comp.lang.basic.misc
Subject: Re: Mouse in Qbasic?
Date: 10 Apr 1998 00:42:30 GMT
>In QBasic (not QB45), the ONLY way to call an interrupt is to
>write a little machine language program and then:
>
> 1) call ABSOLUTE to
> 2) call the machine language program, which
> 3) calls the interrupt, which
> 4) sends your message to the mouse driver.
I use QuickBasic 4.5, but I a have experimented with the CALL ABSOLUTE method
of calling the mouse driver. You don't need a machine-language program. You can
call the mouse driver directly with CALL ABSOLUTE if you know where to call.
You can PEEK this address out of the interrupt table at 0000:(&H33 * 4). The
first two bytes at this address are the segment, followed by the offset. It
takes a little fiddling to combine the two one-byte PEEK values if the segment
or the offset is greater than &H7FFF, because the obvious
MouseSeg% = PEEK(TablePtr%) + PEEK(TablePtr% + 1) * 256
MouseDvr% = PEEK(TablePtr% + 2) + PEEK(TablePtr% + 3) * 256
will produce an integer overflow. It should work if MouseSeg and MouseDvr are
LONG integers, but I think you have to convert them to 16-bit integers for use
by DEF SEG and ABSOLUTE.
You then use
DEF SEG MouseSeg
CALL ABSOLUTE (m1, m2, m3, m4, MouseDvr)
Where m1..m4 are the four parameters to the mouse driver. You always have to
supply all four, and they should be variables, not runtime expressions, because
many mouse functions return data by overwriting the parameters.
*** QBASIC COMMUNICATIONS
From: xxx.spagtime@compuserve.com [Ed: poss. anti-spam measure? Maybe
spagtime@compuserve.com ?] (Spag)
Newsgroups: comp.lang.basic.misc
Subject: Re: Qbasic Communications
Date: 29 Mar 1998 08:34:09 GMT
"Michael Beck" <dbeck@wesnet.com> wrote:
> I've just spent 5 hours trying to get two computers some what talking
> to each other. I would really like to know how to write modem or
> serial games in qbasic. If anyone would please direct me to a good
> communications tutorial, I would greatly appreciate it.
> Thanks for anything.
Have a go with this, hope it helps
Plumb the 2 machines together with a 'null modem' cable, then run the following
Qbasic prog on each. (it helps if you can see both monitors!!)
CLS
OPEN "COM2:9600,N,8,1,lf,cs,ds,cd,op,rs" FOR RANDOM AS #1
COM(2) ON
ON COM(2) GOSUB rxflag
DO
key$ = INKEY$
IF key$ <> "" THEN PRINT #1, key$
IF rxflag = 1 THEN GOSUB getmessage
LOOP UNTIL key$ = "!"
END
rxflag:
rxflag = 1
RETURN
getmessage:
rxflag = 0
DO UNTIL EOF(1)
rxchar$ = INPUT$(1, #1)
IF ASC(rxchar$) < 32 OR ASC(rxchar$) > 128 THEN rxchar$ = ""
PRINT rxchar$;
LOOP
RETURN
-------------------------------------------------------------------------------
INTERNET RESOURCES
GETTING THE FANZINE:
- Website
The Basix Fanzine: http://come.to/basixfanzine
The "Basix Fanzine Interactive Library" at GeoCities has been taken down. The
site no longer exists at all and may soon be reoccupied by somebody else.
- Newsgroups
The Basix Fanzine is posted when it is released to alt.lang.basic,
alt.lang.powerbasic, comp.lang.basic.misc and microsoft.public.basic.dos. If
you want it posted to any other BASIC newsgroups then please let me know.
- Mailing List
To get the Fanzines as they are released, join Tony Relyea's mailing list by
sending an email to the new address of fanzine@vt.edu with subject "subscribe
basix-fanzine". This mailing list is completely separate from the Basix Fanzine
so I cannot accept responsibility for any emails you do - or don't - get when
you join the mailing list.
USEFUL BASIC WEBSITES:
Compilers
-PowerBASIC (also FirstBasic, PB/DLL and PB/CC): http://www.powerbasic.com
-EMS (old MS compilers): http://www.wdn.com/ems/oldtools/ms.htm
-Provantage (old MS compilers): http://www.provantage.com
BASIC code
NEW LINK! The Beginners Basic Homepage:
http://www.users.globalnet.co.uk/~basic/
-QBasic.com: http://www.qbasic.com
-The Programmer's Page: http://www.professionals.com/~peterp/
-ABC Packets (bi-monthly collections of useful BASIC code):
http://come.to/abcpackets
-PowerBasic Archives: http://pitel-lnx.ibk.fnt.hvu.nl/~excel/pb.html
-Tim's QuickBasic Page: http://www.geocities.com/SiliconValley/Heights/8967/
-QBasic Programming Corner:
http://www.geocities.com/TheTropics/9964/qbasic.html
-The QBasic Site: http://hem.passagen.se/hedsen
-DMAPLAYH.BAS (WAV player): http://www.ocf.berkeley.edu/~horie/project.html
-The QuickBasic Enhanced Programming Page:
http://www.geocities.com/SiliconValley/Lakes/7303/
-Blood 225's BASIC stuff: ftp://users.aol.com/blood225
-Alex Warren's BASIC page: http://www.users.globalnet.co.uk/~dewarr/basic.htm
Libraries
-Zephyr Software (SVGA Library): http://www.zephyrsoftware.com
-MOD Library: http://www.fortunecity.com/millenium/celesteville/23/index.html
-QMIDI (MIDI player): http://www.primenet.com/~merlin57/qmidi/
Reference
-Ralf Brown's Interrupt List: http://www.ctyme.com/rbrown.htm
NEW LINK! Programmers' File Formats Collection: Europe:
http://www.wotsit.demon.co.uk · US: http://wotsit.simsware.com
NEW URL Basix Fanzine: http://come.to/basixfanzine
-PCGPE (PC Games Programmers' Encyclopaedia):
ftp://x2ftp.oulu.fi/pub/msdos/programming/gpe
Want to nominate one of these sites - or your own - for an award? See the Basix
Fanzine Awards 1998 News Article in issue 11.
Add your site to this list by sending an email to basix@dewarr.globalnet.co.uk.
Also, if any of the sites disappear or move address, please send an email so I
can update this page when I release the next issue.
USEFUL BASIC NEWSGROUPS:
alt.lang.basic
alt.lang.powerbasic
comp.lang.basic.misc
microsoft.public.basic.dos
soon... perhaps comp.lang.basic.powerbasic - see the news article in issue 11.
GETTING HOLD OF BASIC:
QBasic is free and available on DOS disks (versions 5.0 and up), the Windows
95/98 CDROMs, and within http://www.microsoft.com/windows/download/olddos.exe
You can order new and used copies of QuickBASIC, PDS 7.x, VBDOS, etc. online at
http://www.wdn.com/ems/oldtools/ms.htm and http://www.provantage.com
And you can buy PowerBasic, FirstBasic and other products from
http://www.powerbasic.com.
If you want to compile very few programs which have been made using QBasic, and
don't want to shell out $110 for PB, you can pay $5 a time for compiling at
http://members.aol.com/qbasicnow. Email qbasicnow@aol.com for more information
on this.
QB4.5 can be also be downloaded illegally from various websites. The Basix
Fanzine does not accept responsibility for any damage caused to your computer
or your life through downloading illegal software.
If you know of any other compilers or would like to advertise yours here, send
an email to basix@dewarr.globalnet.co.uk, or post a message on one of the BASIC
newsgroups and hope that I see it.
-------------------------------------------------------------------------------
HOW TO CONTRIBUTE
The Basix Fanzine relies on the contributions it recieves from ordinary people
like you - so, if you have an article or some source code you'd like to sumbit,
please email it to basix@dewarr.globalnet.co.uk - all contributions very
gratefully recieved, so thanks in advance.
If you have any questions about submitting an article - for example, if you
want to make sure that your article will be suitable - please do not hesitate
to ask!
Contributions are accepted in a number of formats. The preferred format is HTML
although you can submit documents in Word format, or just in plain old text
format if you prefer. Feel free to include graphics - the new format of the
fanzine means it is now easy to accommadate them, provided they are not too
big! Please note that some of the formatting in your article may be changed to
keep it consistent with the rest of the fanzine. In some cases files may be
included separately (i.e. articles may not be pasted straight in to the issue's
HTM file, they may be just put in with a hyperlink)
It helps me a lot if the font you use in articles is Verdana and any code is
indented in Courier New, in the same way as in exisiting HTML issues. Please
also refrain from ASCII art as it tends to bugger up when converted to HTML!
Articles and source code submitted becomes the joint copyright property of the
author and the Basix Fanzine. This means that both the author of the article
and the Basix Fanzine have the right to redistribute the article/source.
Remember - no articles, no fanzine :(
Please note that the editor reserves the right to edit or omit articles and
source code recieved for inclusion in the Basix Fanzine.
-------------------------------------------------------------------------------
FINAL WORDS
Thanks to the following for contributing articles and source code for this
issue:
- "Hacker" aka Damian Nikodem
- Rude John, aka "The Tripods". Though who knows what his real name might be...
...and to the following for their newsgroup posts that I've reproduced here:
- Rory
- "SimpleSi"
- Marc van den Dikkenberg
- "Krogg"
- Curt Bates
- "C1284J"
- Judson McClendon
- Ali Afshar
- Steve Rush
- "Spag"
NEXT ISSUE:
Well, who can tell... Rude John's column will be back... more informative posts
from the newsgroups... plus the latest news - all in a new, brighter, more
enlightening form guaranteed to bring you ever-lasting joy and happiness.
Probably.
I hope to release the next issue as soon as I get enough contributions -
hopefully before October 1998. If you'd like to see it sooner, why not
contribute an article? Go on - you know you want to.
I hope you've enjoyed the issue and have found it useful. Hopefully the new
HTML format has made the issue easier to read and easier to use code from.
Until next time... goodbye!
Alex Warren,
27th June 1998