|
| | Hay 37 invitados y 2 miembros en línea
Eres un usuario anónimo.
|
| |
Autor
| IOMBCC - Explained
| NYYRIKKI msx master Mensajes: 1533 | Publicado: Marzo 19 2005, 11:08   | Here you can send your explanations, how did you end up into something so weird, that you wanted to participate and what are the ideas behind that completely unreadable goddamnbasicmagicpotionprescription. :9
If you don't want to spoil your fun of reading unreadable BASIC programs, stop reading now! Next I'm gonna explain how my IOMBCC stuff works!
Character zoom for IOMBCC:
I got the idea for this entry from KEY LIST command, that gets second place on most useless BASIC commands
list just after WAIT command(*). I had not seen it used ever on MSX-BASIC program, so this needed to be
corrected. :-)
Here is my first real entry explained line by line:
1 ' Character zoom for IOMBCC 2005 ver 1.1
2 ' Made By: NYYRIKKI
3 ON ERROR GOTO 5 OR 8
No, execution will not jump to line 13 on error. Error handler will be on line 5 and error will be
generated right away. :-)
4 DEFINTA-Z:DEFFNN(N)=PEEK(N)+PEEK(N+1)*256:DEFUSR=ASC(">"):DEFFNF(N)=(1+((PEEK(A)AND2^N)=0))*&O117:DEFSTRR
:DEFFNC(N)=FNN(-1760)+N:GOTO6
FNN routine reads 16bit value from memory. It is only used by FNC routine.
The routine defined by DEFUSR is used to restore function keys to default.
FNF routine is used to return status of address "A" bit "N" as ASCII value of "O" or zero.
In memory address #F920 (-1760) is the location of font. In #F91F is the slot of font, but this is always
slot 0 if custom font is not loaded, so we simply ignore that fact.
5 K=K+1:X=ERR:RESUME NEXT
This is the real error handler.
6 N=RK+K:KEYOFF:CLS:KEYK,"DEL to exit"
As "R" beginning variables are defined as strings, here is the second error. K variable will be anyway only
1 because DEFINT has already erased K variable once.
7 X=X+(K/N):REMOTE=RK:RESUME NEXT
Here is the important error: As N is not defined, X will be 10 because of "Division by zero" error. Rest of
the line is just to trick people. It is only remark.
8 IFKMODXTHENKEYK,RE:GOTO 7
Idea is to clear all function keys at startup. Typical way of doing this kind of loop is: FOR K=2 to 10:KEY
K,"":NEXT How ever the idea here is: 11 MOD 11 = 0 = False. These variables do not change after K&X=11 so
in future rounds, this line does not do anything.
9 IFATHENA=FNC(ASC(INPUT$(1))*8)+(A>N)ELSEA=K:GOTO11
Yet another trick: At first time A=0 so here we set A to non zero value and jump to dislay the "Del to exit"
text. When we return here, we initialize A with memory address of font of typed character -1. (A is always
greater than 0, so (A>N)= True =-1)
10 FORP=NTOERL:A=A-NOTE:FORI=XXORKTOK-4:POKEP*16-1882-I,FNF(I):NEXTI,P
P is Y coordinate of font (0-7) and I is X (0-7) coordinate. FNF function is used to get the font data from
memory and POKE command is used to put the data directly to function keys.
11 LOCATE SEARCH, FIND AND DESTROY: KEY LIST
This line looks nice and displays the font. This is same as LOCATE 0,0 AND 0:KEY LIST -> LOCATE 0,0:KEY LIST
12 IF K=X=A-FNC(2^(X-1))THENPRINTCHR$(USR(12));ELSE8
This weird line checks, if DEL key was pressed. I selected DEL because DEL does not have font anyway. If it
was, then we pass number 12 to routine that restores function keys. Because this routine does not have
input or output values, the function keys are restored and the number is passed back in to CHR$. This causes
VT-52 emulation to clear screen and after that program stops.
Here is how to solve the DEL check math problem:
K=X = 11=11 = True = -1
A = 127(DEL=ASCII 127)*8+7(ERL)+font address = 127*8+7+X = 1023+X
FNC(2^(X-1)) = FNC(2^10) = FNC(1024) = 1024+font address = 1024+X
(1023+X)-(1024+X)=-1
-1=-1 -> EXIT
- End of Story -
(*) Does anyone have a idea, how you could use WAIT for something usefull? Only semi usefull thing, that comes
to my mind is:
PRINT"Turn CAPS-lock off!":WAIT 170,64:CLS
... but even this is better to do like this:
POKE&hFCAB,0: OUT170,INP(170)OR64
Someone could make some usefull IOMBCC entry around WAIT command :-)
| | NYYRIKKI msx master Mensajes: 1533 | Publicado: Marzo 19 2005, 11:21   |
Here is another one...
10 '3LR2n+RtOMo6HU98tn16F2w8ZjiLXMJsB51oF5gTnAHmOA-DUgz2HcldV10qF5gT7LRmA9IJ
20 '4xjGEDJKHxTEE1EnjEJtB51oVbQnYlItB1xNyBWLXMJ6kjj6uDzu4+kHbWW+h1PvHVzwVbA
These first two lines actually contains the BASIC extention for SYS and KEYBUF commands.
30 SCREEN0,,0:KEYOFF:WIDTH40:U=-189:PRINT"Please wait, generating thoughts...":P
OKEU,201:DEFFNA(N)=PEEK(N)+PEEK(N+1)*256:T$="+-":POKEU+1,V:READE:FORI=0TO61
The U will now contain the BASIC command hook address #FF43. 'RET' instruction is put to hook just in case,
there is something already. E variable will get value 15
40 T$=T$+CHR$(48+I-(I>35)*6-(I>9)*7):NEXT:POKE &HFBB1,1:M=&HD000:A=FNA(&HF676)+6
:DEFUSR=17+RND(-TIME):POKEU+2,208:FORO=NOT0TO0:POKEO-3142,PEEK(O-2441):NEXT
Here we generate string that is used to decode lines 10-20. This string contains 64 characters: "+", "-",
all numbers, all lo-case alphapets and all hi-case alphapets. After that we disable CTRL+STOP because
stopping program in wrong place can be a very bad idea (screen disabled, wrong number of lines in screen
and keyboard buffer full of unwanted stuff) Variable A will now contain the BASIC start address+6. The
BASIC start address is also copyed from #F676 to normally unused BASE(3) variable. DEFUSR is used to
initialize random generator and as variable for storing number of lines in image.
50 A=A+1:P=PEEK(A):D=INSTR(T$,CHR$(P))-1:IFD=>0THENPOKEM,(DAND(4^C-1))*4^(4-C)+B
:B=D\4^C:M=M-(C>0):C=(C+1)AND3:GOTO50ELSEIFP=0ANDPEEK(A+6)=143THENA=A+7:GOTO50
This line actually decodes the crap in lines 10-20. Idea is, that each 3 characters of 6bit source data
will be converted to 3 bytes of 8bit data by shifting bits. End of the line is used to detect possible
line change.
60 POKEU,195:SYS65:PRINTCHR$(12);CHR$(10);CHR$(49);STRING$(7,39):PRINT"GOTO80"
First POKE is used to put "JP" (jump) command to the HGONE hook. This causes new commands to be ready for
use. Routine at address 65 disables the screen. After this we print "1'''''''" that will be inserted to
this program later in purpose to get space for empty line after plasma. "GOTO80" is used to return to
this program after inserting the new line.
70 PRINTCHR$(11);:KEYBUFSTRING$(2,13):END' --== Sourcered Forces 1.0 ==--
Here we insert the line from screen by puting two return characters to key buffer, sending pointer to
up left corner of screen and ending program. Return characters will take care, that new line will be
inserted and program will be continued from line 80. This line also defines, that this plasma will be
called Force, when this project is ready :-9
80 POKEBASE(3)+2,2:FORI=7TO9:POKEBASE(3)+I,8:NEXT
Here we renum line 1 to line 2 and change part of the "'" characters to backspace in order to
delete "2 '" from the beginning of the line. Idea of renumbering is, that we can now add line 1
again without overwriting it.
90 X=PEEK(-3174)-1:POKE-3174,X:IFX>0THENIFX>ETHENFORI=10TO12:POKEBASE(3)+I,32:NE
XT:PRINTCHR$(27);"Y!#";STRING$(28,39):GOTO70ELSE70ELSEREADD:KEYBUF"RENUM10,110"+
CHR$(13)+"RUN"+CHR$(13):P=ATN(1)/32' Made By: NYYRIKKI 2005
Here we decrease the value defined by DEFINT command untill we have all needed lines for the plasma.
If we are executing this for first time, we will change characters after backspace to space in order
to delete the visual characters from screen and also update the line in screen to be more long in
order to get enough space for next generated plasma picture lines. Note, that this template to put
plasma is done from bottom to up.
If all lines are inserted to source, we read the value 15 this time to D variable and update keyboard
buffer. P is used to hold 2*pi (whole sin wave) /256
100 FOR I=0 TO 255:POKE &HD100+I,SIN(P*I)*D+128:NEXTI:DELETE 10-100
Here we "draw" whole sin wave to memory area #D100-#D1FF and after that we delete all these BASIC
lines we don't need anymore. After RENUM the RUN command in keyboard buffer will take care, that
the program that is left will be started afterwards.
110 DEFINTA-Z:DEFFNP(U,S)=PEEK(53504!+(R(U*2)+(S*R(U*2+1)\32)AND255)):DIML(15)
Here we have the new line 10. Idea of weird looking FNP function is to read sin wave at offset S
from random location number U in random steps number U. Eh, sounds clear? :-)
120 READJ:FORB=ETOJ:READL(B):NEXT:B=BXOR26:POKE&HF3B1,26:CLS
Ok, here we read that same old value 15 for 3rd time. This time it is used to read all the values
from data lines in order to get character numbers to draw the plasma picture. B will get value 10
and we will add two lines below bottom of the screen in order to get some space to hide "Ok" prompt
after LIST command.
130 C=B:U=E:GOSUB150:SYS &H44:ONINTERVAL=60GOSUB150:INTERVALON:FORI=0TO5:R(I)=RN
D(1)*200+55:NEXT:FORU=0TOJ:U1=FNP(E,U):FORC=BTO35:Z=((U1+FNP(1,C)+FNP(2,C+U))AND
15):POKEBASE(3)+C+U*&H25,L(Z):NEXTC,U:INTERVALOFF:GOSUB150:DATA15,32,32,58,45
Here is the plasma generation routine. C=10:U=0 Routine in address &H44 enables screen, if it is
needed. First we initialize all the needed random numbers and then we use FNP function to change
them to random waves. After that we replace the generated remark lines with wave data trough
character conversion. ON INTERVAL GOSUB is used to update the progress counter to screen.
140 IFINKEY$=""THENSYS&O101:KEYBUF CHR$(11)+"GOTO30"+CHR$(13):PRINTCHR$(27);"Y&
":LIST2ELSECLS:POKE-3151,24:END:DATA43,61,112,42,35,42,113,61,43,45,58,32
If user does not want to stop after picture is ready, we again disable the screen. VT-52 codes
are used to move cursor to correct line and LIST2 is used to end the program and to print all
our generated BASIC lines containing the plasma to screen. Keyboard buffer is used to loop the
program from line 30 (130 in here)
If user wants to exit, we will restore the number of lines on screen to default and end the program.
150 PRINTCHR$(11);INT((C+U*26-B)/.442)/B;CHR$(8);"% ":RETURN: FOR IOMBCC
This weird looking line is just used to print status of progress to up left corner of screen in %.
| | NYYRIKKI msx master Mensajes: 1533 | Publicado: Marzo 19 2005, 12:16   | Couple of corrections to first message:
This was meant to be @ beginning:
Hmm... What could be more useless and more bad idea than IOMBCC? Maybe trying to teach BASIC by using IOMBCC sources as examples! Suddenly I've had these exellent ideas, how to torture my self and my fellow MSX users, so here we go again...
Quote:
| Here is the important error: As N is not defined, X will be 10 because of "Division by zero" error.
|
TYPO: X will be 11...
| | [D-Tail]
 msx guru Mensajes: 3026 | Publicado: Marzo 19 2005, 13:00   | _O_
(worships NYYRIKKI)  | | snout
 msx legend Mensajes: 4995 | Publicado: Marzo 19 2005, 23:44   | Wow, thanks for posting this extremely well documented explanation. A whole new world of BASIC has opened for me  | | dvik msx master Mensajes: 1376 | Publicado: Marzo 20 2005, 11:45   | I'll start explaining the second prime number one liner. The first one is pretty similar so when you understand this one it will be pretty easy to get the first one as well.
This post will try to explain how the msx basic one liner does to generate odd prime numbers
(i.e. all prime numbers except 2):
1 PRINTCHR$(-30*(D<>0OR(C-B)<>2))A:A=A-2*(D=0)-(A=0):B=(D=0)-(D<>0)*B:C=(D=0)-(D<>0)*C:D=D-A*(D=0):C=C-2*(D>0):B=B-2*(D<0):D=D+C*(D>0)-B*(D<0):GOTO1
Before explaining how the code works we need to describe the algorithm used in the program.
Any integer number, r, can be written as a product of two equal or smaller integer numbers p and q:
r = p * q (1)
A non prime number will have integer solutions to the equation where p and q both are greater than
one and a prime number only has a solution where either p or q is one. So to find if a number is a
prime number we can try to find the solutions to the equation. This is usually called factorization
since we want to find two factors, p and q, of r.
To make the factorization easier, we substitue p and q with
p = x + y (2)
q = x - y
where a and b are integers we get the equation
r = (x + y) * (x - y) (3)
which gives
r = x ^ 2 - y ^ 2 (4)
The number series x ^ 2 for different values of x is
1, 4, 9, 16, 25, 36, ....
A given number in this series can be calculated as:
x
---
x ^ 2 = > 2 * i - 1 (5)
---
i=1
Using equation 5 in 4 we get an equation for the number r and two of its factors
that only contains the operations + and - (we moved all terms to one side of the equal sign):
x y
--- ---
r - [ ( > 2 * i - 1 ) - ( > 2 * j - 1 ) ] = 0 (6)
--- ---
i=1 j=1
This equation can be solved by iteration. This may be a bit tricky to see but this is what we get:
1, Let a = -1 and b = -1 and r = the number to factorize (7)
2, If r > 0, calculate a = a + 2, r = r - a
3, If r < 0, calcualte b = b + 2, r = r + b
4, If r = 0 Then we have found a factor, else goto 2
From the resulting values of a and b we can (using equation 5) find x and y:
x = a / 2 (8)
y = b / 2
And then by substituting back using equation 3 finally get the two factors p and q:
p = (a + b) / 2 (9)
q = (a - b) / 2
This iteration will stop when we find the two factors of r that are closest to each other. This means
that if the number is not a prime number we'll find two factors that are not r and 1. But if the number
is a prime number we'll get the factors r and 1. So if the number r is a prime number we have the smaller
factor q being 1, which means that (a - b) / 2 = 1 or:
a - b = 2 (10)
So the only thing we need to do to find out if a number r is a factor is to do the iteration in (7) and
test the resulting values a and b with equation 10.
So now to the code. As you see in the code there are no loops but the code manage to print all prime
numbers from 3 and up. So there are some clever coding involved as well as the nice little algorithm.
First you'll see that there is a GOTO in the end of the line and there are no branches so all epressions
in the line will be executed and then the program starts over from the beginning.
The program uses four variables:
A - A counter that contains the number to test if it is a prime, i.e. 3, 5, 7, 9, 11, 13, 15, ...
B - The variable b in the iteration in (7)
C - The variable a in the iteration in (7)
D - The variable r in the iteration in (7)
The first part of the code:
PRINTCHR$(-30*(D<>0OR(C-B)<>2))A
prints two things. The second part is the value of A. The first is a character that is calcualted from
the expression
-30*(D<>0OR(C-B)<>2)
This expression has two possible values:
0 - If D = 0 and C-B = 2. This is because the epxression D<>0 will become 0 and (C-B)<>2 will become 0
which means that (D<>0OR(C-B)<>2) also will be 0 and finally -30 * 0 will be 0.
30 - If D is not 0 or C-B is not 2. This is because a boolean expression in MSX basic that is true will
get the integer value -1. So if D<>0 is true and/or (C-B)<>2 is true, the resulting expression
(D<>0OR(C-B)<>2) will be true and give the value -1. And -30 * -1 is 30.
The character with the value 30 is the 'up' character which will move the cursor one line up. The character
0 is just an empty character. So if either D is not 0 or C-B is not 2 the cursor is moved up one line and
the value printed on that line will be overwritten with the new value of A.
The whole idea with this is that if the current value of A is not a prime number we will overwrite it. But
if it is a prime number we want to print it and move to the next line on the console. From equation 7 and
10 we know that the only time we have a prime number is if both D=0 (the variable r in 7) and if (C-B)=2
(the variables a and b in 7 and 10).
The next part of the code:
A=A-2*(D=0)-(A=0)
Simply increases the counter A by two if D=0. It also increases the counter A by one if A=0 which only
happens the first time the expression is executed. Note that D is only 0 either the first time we
execute the expression or if we found a solution to the iteration (r=0)
After this we want to initialize the variables B and C. We use the expression
B=(D=0)-(D<>0)*B
which simply will set B to -1 if D=0 and leave B as it is if D is not zero. The same is done for the
variable C.
The last initialization is for the variable D:
D=D-A*(D=0)
This simply sets D to A if D=0 and leave D as it is otherwise. This simply initializes D to the number
we want to factorize after we found the factors of a previous iteration or the first time we execute
the expression.
Now were done with the initialization of our variables (step 1 in the iteration process in equation 7).
Next we want to execute the other steps in the iteration process. We start with the first half of step
2 and 3 which is to increment B or C with two depending of the sign of D:
C=C-2*(D>0)
B=B-2*(D<0)
This means that C will be incremented by 2 if D>0 and that B will be incremented by 2 if D<0.
The last thing is to calculate the second half of step 2 and 3 in equation 7 which is to increment or
decrement D depending on the sign of D:
D=D+C*(D>0)-B*(D<0)
If D>0 we'll decrement D with the value of C which was previously incremented by 2. And if D<0 we'll
increment D with the value of B.
When all this is done well jump back to the beginning of the program and make sure the number is
printed if we finished the iteration (D=0) and the number was a prime number (A-B=2).
| | HansO msx addict Mensajes: 375 | Publicado: Marzo 20 2005, 12:47   | These Basic programs remind me of a quote made by the late Edsgar Dijkstra, one of the most influencal computer scientists (look him up with google, he wrote good books on computer science)
Quote:
| It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.
|
| | wolf_ online
 msx legend Mensajes: 4827 | Publicado: Marzo 20 2005, 14:25   | Depends which basics he's referring to.. the old line-number basics with gotos and no if-endif, select-case, while-wend, functions etc. are quite oldfasioned and it's easy to make a giant mess with them. Modern basics have OOP, good program-flow etc. I doubt that Edsgar would say the same about the modern basics..
| | Grauw msx professional Mensajes: 1006 | Publicado: Marzo 20 2005, 19:50   | In the contrary, I think this proves NYYRIKKI is one of the most brilliant programmers alive  . Respect, dude. | | HansO msx addict Mensajes: 375 | Publicado: Marzo 20 2005, 20:03   | Quote:
| I doubt that Edsgar would say the same about the modern basics..
|
I guess he would hate Object Oriented programming. I believe he only approved a bit of Algol and a bit of Pascal. He did make this quote in the time when the article Goto's considered harmfull appeared. He was one of the mathematicians who helped the theoretical part of computer science get shape. Every modern operating system is based on his work on concurrency, like semaphores and such. But he mostly loved clear, structured, easy to understand programs, and the IOMBCC does not really deliver that ...
Great fun though. | | Grauw msx professional Mensajes: 1006 | Publicado: Marzo 20 2005, 20:12   | How can he on one hand be in favour of the "goto considered harmful" line of thought, yet hate object oriented programming?
OO just takes goto considered harmful a step further, although it doesn’t really have much to do with the gotos themselves.
I wish there was an assembler for MSX which supported OO...
~Grauw
| | NYYRIKKI msx master Mensajes: 1533 | Publicado: Marzo 20 2005, 23:34   | I think, that Dvik has proven that even one line of BASIC can be so complicated that explaining and understanding whole nature of it will take huge amount space and time. Thanks, it was very interesting lesson about iteration.
| | dvik msx master Mensajes: 1376 | Publicado: Marzo 21 2005, 08:22   | This post will try to explain the snake game:
1 SCREEN1:KEYOFF:FORR=0TO9:COLOR5,1,1:LOCATE8,11:PRINT" s to start":M=32:S=-10
2 IFINKEY$<>"s"THEN2ELSECLS:FORD=0TO737::D=D+(D+1AND2ANDD>MANDD<704)*15:F=6176
3 VPOKED+F,7:NEXT:H=6480:T=H-D:FORC=ATOF:S=S+10:L=F+RND(1)*D:IFVPEEK(L)-MTHEN3
4 Y=Y-10*(S>Y):R=3ANDASC(INKEY$+"C")+R+1:VPOKEL,15:U=M^(RAND1)*(1-(RAND2)):C=0
5 VPOKE2^13,6:VPOKEH-D,U+M:H=H+U:O=VPEEK(H):VPOKEH,9:IFO-MANDO-15THENR=3:NEXTR
6 LOCATE1,0:PRINT"SCORE"S,"HI"Y:IFO=15THEN3ELSEVPOKET+D,M:T=T+VPEEK(T)-M:GOTO4
This is really just an msx basic program that is optimized for code size. I'll
start describing how the worm moves and then I'll bring up some fun features
of the source code.
The program contains a loop that moves the snake forward one step by adding a 'O'
character at the head of the snake and removes one at the tail in the background
map part of the VRAM. The direction of the movement is given by the variable R
which can be
0 - right
1 - down
2 - right
3 - up
Before the snake moves, the character at the position of the new head is checked.
If it is a food character, the score is increased, a new food is drawn after the
head is drawn. If the character is a wall or snake character, the game is over.
In parallel, the direction of the worm is stored in the unused part of VRAM in
screen 1. The direction is stored to be able to clear up the tail of the worm.
So after the head is drawn and the new location of the head didn't contain a food
character, the tail is cut off by writing a blank character over the tail. Then
the new tail position is calculated by using the stored direction in the not
visible part of VRAM.
A new food is always drawn on a blank position in the game field. a new food
location is found by using a random number. If the new location isn't blank,
a new random location is generated.
So now to some interesting things about the code.
1 SCREEN1:KEYOFF:FORR=0TO9:COLOR5,1,1:LOCATE8,11:PRINT" s to start":M=32:S=-10
The first line sets the screen and then starts a loop from 0 to 9. The loop
variable R is always set to a value less then 9 before NEXT is called so this
will be an infinite loop. Then the start message is printed. After this a constant
M is initialized. This constant is only used to save some space. Finally the
variable S is initialized. S will contain the current score but it is initialized
to -10 because it will be incremented to 0 before the game starts.
2 IFINKEY$<>"s"THEN2ELSECLS:FORD=0TO737::D=D+(D+1AND2ANDD>MANDD<704)*15:F=6176
The first part of the line waits for the key 's' to be pressed which will start
the game. Next the screen is cleared and a loop is started. The loop will draw
the border of the game field. It loops over all characters from the top of the
screen to the bottom but the next statement will cause the drawing to skip the
game field and just draw the border.
The long statement that will cause the loop to jump over the game field is
actually quite interesting and it relies of the order of which operations are
executed in msx basic. It is a little bit more obvious what it does if parenthesis
are added to show how it is executed:
( (D + 1) AND 2 ) AND (D > M ) AND (D < 704 )
This expression will return either 2 or 0 depending of the value of D.
The last part of the line just defines a constant F.
3 VPOKED+F,7:NEXT:H=6480:T=H-D:FORC=ATOF:S=S+10:L=F+RND(1)*D:IFVPEEK(L)-MTHEN3
First part draws the border character.
The resulting value D will also be used later in the code as a constant to offset
the non visible part of VRAM used for the snake's direction map.
Then the snake head location H and tail location T is initialized. Note that H
points to the visible part of VRAM and T to the not visible part.
Then we have a for loop that will be called to draw a new food and increase the
score. The new food location L is calculated and then we check that the food is
not placed on the border or on the snake itself. If this is the case we want to
call NEXT to jump back to the beginning of the loop. But since we want to save
code space it is better to do a THEN 3 instead of a THEN NEXTC call. The first
statement on the line is safe to do since the value D will not change and the
only thing we'll do is to redraw the bottom left corner of the border.
A side effect of doing the NEXT call is that the score will be increased by 10
every time we try to place a food on a non blank position. This will happen more
often the longer the snake is which means that you'll get more points for a food
when you get a long snake.
4 Y=Y-10*(S>Y):R=3ANDASC(INKEY$+"C")+R+1:VPOKEL,15:U=M^(RAND1)*(1-(RAND2)):C=0
First part updates the high score Y if it is less than the current score. Next we
calculate a new direction based on the keys the game player presses. This is done
as short as possible by getting the character value of INKEY$. But if no key is
pressed we want the snake to continue moving in the same direction so we append
the character "C" to INKEY$ which will make the entire expression to be unchanged
if no key is pressed. The rest of the expression is made to make the 'z' key turn
the worm counter clockwise and the 'x' key turn it clockwise.
The following VPOKE will draw the food on the location we calculated earler.
Then the value U is calculated. This value will be the offset from the current
head location to the new head location. So for the four directions, U will be
right - U = 1
down - U = 32
left - U = -1
up - U = -32
The last statement is really not needed but it will make sure that the FORC loop
is infinite.
5 VPOKE2^13,6:VPOKEH-D,U+M:H=H+U:O=VPEEK(H):VPOKEH,9:IFO-MANDO-15THENR=3:NEXTR
First VPOKE sets the color of the border. Second vpoke will store the direction
of the snake at the current head position. Note that the VPOKEs need to be positive
numbers so the value U is modified to always be positive.
The VPEEK checks the character at the location of the new head position and the
following VPOKE draws the new head.
If the new location is a border or snake character, the game is over. We reset
the direction R and jump back to the for loop at line 1.
6 LOCATE1,0:PRINT"SCORE"S,"HI"Y:IFO=15THEN3ELSEVPOKET+D,M:T=T+VPEEK(T)-M:GOTO4
First the score is printed. This is done for every movement and it actually is
a reason for this. The print takes a while to perform and it happens to be just
as much time to make the snake move with a good speed to make the game playable.
The IF statement checks if the character on the current head location is a food
character. if so we want to do a NEXTC to get back to the FOR statement on line 3
but since the THEN3 call is shorter and will contain a NEXT statement we do this
instead.
If there was no food at the head location we'll cut of the tail and upate the
tail position and continue the game loop.
So even if the code is quite short, the statements are chosen very carefully and
they all have a very important role in the game. Some of the satements are not
as important to have in a specific location in the program and they have been
used to make sure that all lines in the program will be 79 lines long. One tricky
part was to put as many if statements as possible at the end of a line so the
ELSE keyword could be avoided.
| | AuroraMSX
 msx master Mensajes: 1278 | Publicado: Marzo 21 2005, 12:20   | Quote:
| I guess he would hate Object Oriented programming.
|
I think so, too. As a mathematician, I guess he would prefer functional programming languages like Miranda or CClean. Stuff like:
f :: N -> N
f(0) -> 0
f(1) -> 1
f(n) -> f(n-1)+f(n-2)
| | Vincent van Dam msx addict Mensajes: 384 | Publicado: Marzo 21 2005, 16:35   | Quote:
| I think so, too. As a mathematician, I guess he would prefer functional programming languages like Miranda or CClean.
|
I think so too, though Algol and Pascal are imperative languages. | |
| |
| |
| |