News:

NEW GAME: MERLIN in the Castle of Evil ! Check this topic!

Main Menu

Snake program in C7420 Basic

Started by gertk, September 21, 2011, 10:42:28 PM

Previous topic - Next topic

gertk

This is the source of the snake program demo-ed at the Retro event in Steenwijk

01000 REM Snake and Dots
01010 REM idea from quitebasic project
01020 REM ----------------------------
01032 PRINTCHR$(150);
01033 GOSUB 10000
01037 GOSUB 11000
01038 TX 4,0,0
01039 PRINT"written by Gert vd Knokke";
01040 PRINT" (c)2011":PRINT
01045 TX 3,0,0
01050 PRINT "Use joystick to steer"
01060 PRINT "the snake through the"
01070 PRINT "field avoiding the walls"
01080 PRINT "but collecting the dots."
01085 PRINT
01090 DISPLAY
01100 SCREEN
01110 TX 6,0,0
01120 PRINT"Press ";:TX 1,4,1
01125 PRINT"FIRE";
01130 TX 6,0,0:PRINT" button to start."
01190 T=0
01200 A=ACTION(1) AND 1
01205 T=T+1:IF T>1500 THEN RUN
01210 IF A=0 THEN 1200
01500 REM setup graphics characters
01505 SETEG 32,"00000000000000000000"
01510 SETEG 033,"000000183C3C18000000"
01520 SETEG 035,"00183C5ADBFF7E3C1800"
01530 SETEG 034,"00183C7EFFDB5A3C1800"
01540 SETEG 036,"00183C4EFFFF4E3C1800"
01550 SETEG 037,"00183C72FFFF723C1800"
01560 SETEG 039,"00183C7EFFFF7E3C1800"
01570 SETEG 038,"00183C7EFFFF7E3C1800"
01580 SETEG 040,"00183C7EFFFF7E3C1800"
01590 SETEG 041,"00183C7EFFFF7E3C1800"
01600 SETEG 042,"00F7F7F7F700BFBFBFBF"
01610 SETEG 043,"FF08080808FF40404040"
01620 SETEG 044,"FF09090909FF41414141"
01630 SETEG 045,"FF88888888FF80808080"
02000 REM the array holds one entry
02010 REM for each space on screen
02020 REM a non zero means occupied
02030 REM a dot is encoded by 33
02040 REM if the snake occupies the
02050 REM space the value is direction
02060 REM each sbroutine is called acc.
02070 REM array in G
02075 DIM G(40,25)
02080 REM == initialize ==
02085 MX=39:MY=20
02087 GOSUB 6000
02088 STORE
02090 P=12
02100 Q=12
02110 G(P,Q)=34
02120 CURSORX P:CURSORY Q
02122 EG 2,0,0
02125 PRINTCHR$(G(P,Q));
02127 LINE Q,Q
02130 R=12
02140 S=11
02150 G(R,S)=38
02160 CURSORX R:CURSORY S
02162 EG 2,0,0
02165 PRINTCHR$(G(R,S));
02167 LINE S,S
02170 FOR T=1 TO 10
02171 GOSUB 3500
02172 NEXT T
02179 EG 1,0,0
02180 CURSORX A:CURSORY B
02185 PRINTCHR$(33);
02187 LINE B,B
02300 REM == control input ==
02310 C=ACTION(1)
02320 IF C AND 8 THEN G(P,Q)=34
02330 IF C AND 16 THEN G(P,Q)=35
02340 IF C AND 4 THEN G(P,Q)=36
02350 IF C AND 2 THEN G(P,Q)=37
02500 REM == move the snake ==
02510 D=G(P,Q)
02515 G(P,Q)=D+4
02516 CURSORX P:CURSORY Q
02517 EG 2,0,0: PRINTCHR$(G(P,Q));
02518 LINE Q,Q
02520 ON D-33 GOSUB 9100,9200,9300,9400
02530 P=P+U
02540 Q=Q+V
02550 IF P>MX OR P<1 THEN 7000
02555 IF Q>MY OR Q<1 THEN 7000
02560 IF G(P,Q) THEN 3000
02570 G(P,Q)=D
02580 CURSORX P:CURSORY Q
02582 EG 2,0,0
02585 PRINTCHR$(D);
02587 LINE Q,Q
02590 D=G(R,S)
02600 ON D-37 GOSUB 9100,9200,9300,9400
02610 G(R,S)=0
02620 CURSORX R:CURSORY S
02625 PRINTCHR$(32);
02627 LINE S,S
02630 R=R+U
02640 S=S+V
02650 REM pause level
02660 GOTO 2300
03000 REM collission detection
03010 IF G(P,Q)<>33 THEN 7000
03015 SOUND 4
03020 F=F+1
03030 CURSORX 10:CURSORY 22
03040 TX 6,0,0
03050 PRINT "Score:";STR$(F);
03055 LINE 22,22
03060 G(P,Q)=D
03070 CURSORX P:CURSORY Q
03072 EG 2,0,0
03075 PRINTCHR$(D);
03077 LINE Q,Q
03080 GOSUB 3500
03140 GOTO 2320
03500 REM place random dot
03510 A=INT(RND(1)*(MX-4))+2
03520 B=INT(RND(1)*(MY-4))+2
03530 IF G(A,B) THEN 3510
03540 G(A,B)=33
03550 CURSORX A:CURSORY B
03560 EG 1,0,0
03570 PRINTCHR$(33);
03580 LINE B,B
03590 RETURN
06000 REM build the walls
06001 INIT 0:PRINTCHR$(150);:STORE
06007 EG 3,0,0
06008 CURSORY 0
06010 FOR X=0 TO MX
06020 CURSORX X
06030 PRINTCHR$(42);
06040 NEXT X
06050 CURSORY MY+1
06060 FOR X=0 TO MX
06070 CURSORX X
06080 PRINTCHR$(42);
06090 NEXT X
06110 FOR Y=1 TO MY
06115 CURSORX 0
06120 CURSORY Y
06130 PRINTCHR$(42);
06140 CURSORX MX
06150 CURSORY Y
06160 PRINTCHR$(42);
06170 NEXT Y
06800 SCREEN
06900 RETURN
07000 REM game over
07005 SOUND 1
07010 CURSORX P:CURSORY Q
07020 TX 7,0,1:PRINT"Ouch!";
07030 LINE Q,Q
07100 FOR T=1 TO 4000:NEXT T
07999 RUN
09000 REM subroutines mapping direction
09100 U=0
09110 V=1
09120 RETURN
09200 U=0
09210 V=-1
09220 RETURN
09300 U=-1
09310 V=0
09320 RETURN
09400 U=1
09410 V=0
09420 RETURN
10000 REM advertise
10020 INIT 0
10030 STORE
10040 PRINTCHR$(150);
10100 TX 3,3,0
10110 PRINT"  WWeellkkoomm  oopp"
10120 PRINT"  WWeellkkoomm  oopp"
10200 PRINT:PRINT
10210 TX 7,3,1
10220 PRINT"RReettrroozzoonnee  ##11"
10230 PRINT"RReettrroozzoonnee  ##11"
10300 PRINT:PRINT
10310 TX 2,3,0
10320 PRINT "iinn  SStteeeennwwiijjkk"
10330 PRINT "iinn  SStteeeennwwiijjkk"
10900 SCREEN
10910 FOR T=1 TO 4000:NEXT T
10920 RETURN
10930 END
11000 REM initial screen
11010 INIT 0
11020 PRINTCHR$(150);:STORE
11030 TX 2,3,0
11100 PRINT "VViiddeeooppaacc  ";
11110 PRINT "CC77442200"
11120 PRINT "VViiddeeooppaacc  ";
11130 PRINT "CC77442200"
11200 PRINT "BBaassiicc  SSnnaakkee";
11210 PRINT "  &&  DDoottss"
11220 PRINT "BBaassiicc  SSnnaakkee";
11230 PRINT "  &&  DDoottss"
11999 RETURN
>>G7000 G7200(P+S) G7400 N60 JET27 VG5000 ZX80 ZX81 ORIC-1 COMX35 Aquarius<<

manopac

and here it is running in O2EM  8)

as you can see, there are still some errors in the VP+ emulation I should fix ... (missing letters anyone ?)
sex, lies, and videopac

Rafael

Congrats, Gert. It looks very nice. My fingers will burn!
You also could try Snafu, it?s very fun:

gertk

#3
Yes, SNAFU looks like a lot of fun and it is multiplayer! Maybe I will give it a go. My other program on the wishlist (either in Basic or asm) is pipepanic which should be doable in both. I have the C source of the Linux pipepanic version but the core routine seems to be ported from Java and has enormous levels of 'code nesting' so it is no fun in understanding how it works exactly.

The missing characters error in o2em is quite odd, it is not just that the characters are not displayed but they are 'skipped'
If you adjust for example the cursorx command of the score printing at the bottom does that result in other characters being skipped ?

edit: I notice that in 'Score' the 'or' is missing and in 'button' and in the line 'use joystick to steer' on the intro screen the 'to' is missing could it be that they are converted to basic tokens by accident ? (inside the quotes of a print or string command no token conversion should be done)
>>G7000 G7200(P+S) G7400 N60 JET27 VG5000 ZX80 ZX81 ORIC-1 COMX35 Aquarius<<

gertk

This is my tokenizer (from ascii text) routine:


// Tokenizer program for converting BASIC 80 source code to
// tokenized (binary) form data
// by Gert van der Knokke (c)2011

#include <stdio.h>
#include <string.h>
#define DEBUG   false


// my pseudo ram space
unsigned char ramspace[16384];
#define RAMEND 2048

#define MAXTOKENS       91
static char token[MAXTOKENS][10]={"END","FOR","NEXT","DATA","INPUT","DIM","READ","LET",
                        "GOTO","RUN","IF","RESTORE","GOSUB","RETURN","REM",
                        "STOP","ON","LPRINT","DEF","POKE","PRINT","CONT",
                        "LIST","LLIST","CLEAR","CLOAD","CSAVE","TX","GR",
                        "SCREEN","LINE","DISPLAY","STORE","INIT","CURSORX",
                        "CURSORY","SCROLL","PAGE","BRIGHT","SOUND","DELIM",
                        "SETET","SETEG","ET","EG","NEW","TAB(","TO","FN",
                        "SPC(","THEN","NOT","STEP","+","-","*","/","^","AND",
                        "OR",">","=","<","SGN","INT","ABS","USR","FRE","LPOS",
                        "POS","SQR","RND","LOG","EXP","COS","SIN","TAN","ATN",
                        "PEEK","LEN","STR$","VAL","ASC","STICKX","STICKY",
                        "ACTION","KEY","CHR$","LEFT$","RIGHT$","MID$"};

#define BASICOFFSET     0x88C1 
#define TAPEOFFSET      25

// This functions compares all tokens with given string
// and returns a token number or NULL if no token is found
// Since it compares the exact length of the token even tokens
// not seperated by spaces are recognized (from left to right)
int checktoken(char *string)
{
        int t=0,s=0;

        // scan for all tokens
        while (s<MAXTOKENS && !t)
        {
#if DEBUG
                printf("comparing %s with token %s\n",string,token[s]);
#endif
                // no use comparing strings of smaller size
                if (strlen(string)>=strlen(token[s]))
                {
                        // if a token compares to tokenlength characters of the string
                        // a token is positively found and the loop is finished
                        if (!strncmp(token[s],string,strlen(token[s]))) t=s+0x80;
                }
                s++;
        }
        // return token value or NULL if no token found
        return t;
}

// hexdump ramspace to standard output in 'hexdump -C' style
void hexdump(int limit)
{
        char ascbuf[16];
        int n,m;
        int c;

        if (!limit) limit=RAMEND;

        for (n=0; n<limit; n+=16)
        {
                printf("%08x  ",n+TAPEOFFSET);
                for (m=0; m<16; m++)
                {
                        c=ramspace[n+m] & 0xff;
                        printf("%02x ",c & 0xff);
                        // hexdump -C style
                        if (m==7) printf(" ");
                        if (c>31 && c<128) ascbuf[m]=c;else ascbuf[m]='.';
                }
                ascbuf[m]=0;
                printf(" |%s|\n",ascbuf);
        }
}

// the main event
int main(int argc,char *argv[],char *envp[])
{
        FILE *fp;
        char inbuf[256];
        char temp[256];
        int c;
        int quoteflag,ignoreflag;
        int n,m,r,t,pos,startpos;
        char *valid;

        // pointer in my ram space
        pos=0;
       
        // try to open the input file...
        fp=fopen(argv[1],"r");

        // if it worked, then start the process
        if (fp)
        {
                // loop until end of file
                do
                {
                        // first reset offsetpointers and flags
                        n=0;
                        quoteflag=0;
                        ignoreflag=0;

                        // make inbuf a zero length string
                        inbuf[n]=0;
                        // read one line of input
                        valid=fgets(inbuf,255,fp);

                        // if a line is succesfully read
                        if (valid)
                        {
                                // get rid of the 0x0a at the end of the line
                                if (inbuf[strlen(inbuf)-1]==0x0a) inbuf[strlen(inbuf)-1]=0;     

#if DEBUG
                                // show original line
                                printf("%s\n",inbuf);
#endif
                                // now scan for linenumber
                                while (isdigit(inbuf[n])) temp[n]=inbuf[n++];
       
                                // close temporary string
                                temp[n]=0;


                                // read value from string in 'r'
                                sscanf(temp,"%d",&r);
#if DEBUG
                                printf("read linenumber %d from %s\n",r,temp);
#endif
                                // save current position
                                startpos=pos;

                                // reserve 2 bytes for offset
                                ramspace[pos++]=0x00;   
                                ramspace[pos++]=0x00;

                                // store binary linenumber in rambuffer
                                ramspace[pos++]=(r & 0xff);
                                ramspace[pos++]=(r >> 8);

                               
                                // skip spaces after linenumber
                                while (inbuf[n]==0x20) n++;
                                // now proces this line character by character until end of string (NULL)
                                while (inbuf[n])
                                {
                                        t=0; // clear token number
       
                                        //  toggle quoteflag if quotes are found (string start or end)
                                        if (inbuf[n]==0x22) quoteflag=!quoteflag;

                                        // check for tokens if quoteflag and ignoreflag are not set
                                        if (!quoteflag && !ignoreflag)
                                        {
                                                // check for tokens at current offset (n)
                                                t=checktoken(inbuf+n);
                                                if (t)  // we've found a token
                                                {
                                                        // now skip tokenlength characters in inputbuffer
                                                        n+=strlen(token[t & 0x7f]);
                                                        // write token code into output buffer
                                                        ramspace[pos++]=t;
                                                        // set ignoreflag to ignore all (!) tokens
                                                        // until end of line if token was a REM (0x8e)
                                                        if (t==0x8e) ignoreflag=1;
                                                } // end if (t)
                                        } // end if (!quoteflag && !ignoreflag)

                                        // if no token found or in ignore or string mode...
                                        if (!t)
                                        {
                                                // copy literally to ramspace and advance pointer(s)
                                                // convert some special chars to Videopac's equivalent
                                                c=inbuf[n];
                                                switch (c)
                                                {
                                                        case '$':c=0x04; break;
                                                        case '#':c=0x06; break;
                                                        case '^':c=0x7f; break;
                                                        case 0xa3:c=0x03; break;
                                                        case 0xa8:c=0x7e; break;
                                                }
                                               ramspace[pos++]=c;
                                                n++;
                                        } // end if (!t)
                                } // end while (inbuf[n])
                               
                                // write a NULL byte at the end of this tokenized line
                                ramspace[pos++]=0x00;

                                // fill in the current offset in the reserved offset bytes
                                ramspace[startpos]=(pos + BASICOFFSET) & 0xff;
                                ramspace[startpos+1]=(pos + BASICOFFSET) >> 8;
                        } // end if valid
                }
                while (valid);

                // close the file
                fclose(fp);

                // show the result in hex
                hexdump(pos);
        }
        else
        {
                // error...
                printf("could not open %s!\n",argv[1]);
                return 1;
        }

}

>>G7000 G7200(P+S) G7400 N60 JET27 VG5000 ZX80 ZX81 ORIC-1 COMX35 Aquarius<<

manopac

you were right :-) my parser was missing the statement to set the variable for opening/closing the string ... the checks if it was inside a string etc. were already there :D

here's better screenshots :-)
sex, lies, and videopac

gertk

>>G7000 G7200(P+S) G7400 N60 JET27 VG5000 ZX80 ZX81 ORIC-1 COMX35 Aquarius<<

Rafael

Quote from: gertk on September 22, 2011, 07:48:57 AM
My other program on the wishlist (either in Basic or asm) is pipepanic 
:)Great choice. This game is also very fun!

carl

Hi Gertk,
I am adapting your C7420 code for the VG5000 with some personal modifications ;-)
Once finalized, I will share the code for VG5000 here...



Carl