Tron 3.0

I have been spending a little more of time in CBM-Basic, so I am ready to present… Tron 3.0.
– Improved Graphics and speed up to the limits of CBM-Basic of unexpanded Vic-20.

The code is not as “academic” as before due to memory optimizations, but it is still fully commented.

Download source code and d64 image disc: Tron 3.0

Source code.

::::::::::::::::::::::
:rem tron 3.0      :::
:rem by f.g.huerta :::
::::::::::::::::::::::

:rem ms->screen memory (normally 7680)
:rem mc->color memory (normally 38400)
:rem cm->character memory (normally 32768) 
1 ms=peek(648):mc=37888+256*(ms and 2):ms=ms*256:cm=32768:poke36879,16

::::::::::::::::::::::
:rem music :::::::::::
:rem m1,m2,m3 music chanels
:rem n%(8) -> melodie
:rem max volumen
3 dim n%(8):m1=36874:m2=36875:m3=36876:ni=0:poke 36878,15

::::::::::::::::::::::
:rem players :::::::::
:rem p%(i, data) -> data player array
:rem i -> player id
:rem p%(i, 0)-> x pos
:rem p%(i, 1)-> y pos
:rem p%(i, 2)-> ix
:rem p%(i, 3)-> iy
:rem p%(i, 4)-> color
:rem p%(i, 5)-> status: 0->ok, 1->crashed
:rem p%(i, 6)-> current q
:rem p%(i, 7)-> last q 
:rem p%(i, 8)-> last ix
:rem p%(i, 9)-> last iy
:rem p%(i,10)-> num crashes
:rem v ->velocity
:rem b ->background sprite 46
:rem nc -> num cols
:rem nr -> num rows
4 dim p%(1,10):v=1:nc=22:nr=22:b=102

:rem sprites
:rem s(0) -> up down 93
:rem s(1) -> up right 112
:rem s(2) -> up left 110
:rem s(3) -> left right 64
:rem s(4) -> down right 109
:rem s(5) -> down left 125
5 s0=93:s1=112:s2=110:s3=64:s4=109:s5=125
:rem 52 s$=chr$(93)+chr$(112)+chr$(110)+chr$(64)+chr$(109)+chr$(125)
:rem chr$(158) -> yellow
:rem chr$(30)  -> green
:rem chr$(31)  -> blue

::::::::::::::::::::::
:rem new game entry point
::::::::::::::::::::::
:rem reset scores
10 p%(0,10)=0:p%(1,10)=0

::::::::::::::::::::::
:rem new match entry point
::::::::::::::::::::::
:rem init melodie
11 for i=0 to 8:read n%(i):next
:rem init players 
12 for i=0 to 1: for d=0 to 9: read p%(i,d): next:next
:rem clear screen cyan chr$(159): white 5: black 144
13 k$="":for i=1 to nc:k$=k$+chr$(166):next i
14 ?chr$(147)chr$(28):for i=0 to nr-1:?k$;:next
:rem paint scores
15 gosub 140

::::::::::::::::::::::
:::rem begin main loop
::::::::::::::::::::::
: rem debug - print main loop miliseconds
rem 20 ?chr$(19)+str$(timer-t)+"    ";:t=timer

: rem match finished?
20 if p%(0,5) or p%(1,5) then 100

: rem game finished?
22 if p%(0,10)=9 or p%(1,10)=9 then 120

: rem store old velocities
23 p%(0,8)=p%(0,2):p%(0,9)=p%(0,3):p%(1,8)=p%(1,2):p%(1,9)=p%(1,3)

: rem read keyboard in any key
24 if peek(198)=0 then 30

:::::::::::: rem exit? 'x'
25 get k$:if k$="x" then 120

:::::::::rem player ia
26 if k$="a" then p%(0,2)=-v:p%(0,3)=0:goto 30
27 if k$="d" then p%(0,2)=v:p%(0,3)=0:goto 30
28 if k$="w" then p%(0,3)=-v:p%(0,2)=0:goto 30
29 if k$="s" then p%(0,3)=v:p%(0,2)=0:goto 30

:::::::::::rem computer ia
: rem inminent crash? and little random factor
rem 30 q=(p%(1,1)+p%(1,3))*nc+p%(1,0)+p%(1,2):i=rnd(1)
30 d1=p%(1,1):d3=p%(1,3):d0=p%(1,0):d2=p%(1,2)
31 q=(d1+d3)*nc+d0+d2:i=rnd(1)
32 if peek(ms+q)=b and i<.95 then 40
: rem  change direction
33 d=v: if i<.5 then d=-d
34 if d2<>0 then q=(d1+d)*nc+d0:goto 36
35 q=d1*22+d0+d
: rem direction blocked? change direction again
36 if peek(ms+q)<>b then d=-d
: rem final decision
37 if d2<>0 then p%(1,2)=0:p%(1,3)=d: goto 40
38 p%(1,2)=d:p%(1,3)=0

:::::::::: rem phisics
40 for i=0to1
rem 40 i=0
 :::::::::::: rem move - memory optimized
rem 41 d0=p%(i,0):d2=p%(i,2):p%(i,0)=d0+d2+22*((d0=21andd2=1)-(d0=0andd2=-1))
rem 42 d1=p%(i,1):d3=p%(i,3):p%(i,1)=d1+d3+22*((d1=21andd3=1)-(d1=0andd3=-1))

::::::::: rem move - speed optimized
41  d0=p%(i,0)+p%(i,2):d1=p%(i,1)+p%(i,3):p%(i,0)=d0:p%(i,1)=d1
42  if d0<0  then p%(i,0)=21
43  if d0>21 then p%(i,0)=0
44  if d1<0  then p%(i,1)=21
45  if d1>21 then p%(i,1)=0
46 next
rem 46 if i=0 then i=1:goto 41

:::::rem check crashes
:rem draw?
50 if p%(0,0)=p%(1,0) and p%(0,1)=p%(1,1) then p%(0,5)=1:p%(1,5)=1:goto 100

:rem crash?
51 for i=0 to 1
 :rem if crashes ->
 :rem  - update status
 :rem  - increment crashes
52  p%(i,7)=p%(i,6):p%(i,6)=p%(i,1)*nc+p%(i,0)
53  if peek(ms+p%(i,6))<>b then p%(i,5)=1: p%(i,10)=p%(i,10)+1
54 next

:::::::::::::rem paint
60 for i=0 to 1
 :::::::::::::rem tail
 :: rem get tail char
 61 d2=p%(i,2):if d2 and d2=p%(i,8) then d=s3:goto 67
 62 d3=p%(i,3):if d3 and d3=p%(i,9) then d=s0:goto 67

 63 if (p%(i,9)=-v and p%(i,2)=-v) or (p%(i,8)= v and p%(i,3)= v) then d=s2:goto 67
 64 if (p%(i,9)=-v and p%(i,2)= v) or (p%(i,8)=-v and p%(i,3)= v) then d=s1:goto 67
 65 if (p%(i,9)= v and p%(i,2)=-v) or (p%(i,8)= v and p%(i,3)=-v) then d=s5:goto 67
 66 if (p%(i,9)= v and p%(i,2)= v) or (p%(i,8)=-v and p%(i,3)=-v) then d=s4:goto 67
 
 :: rem poke tail & head
 67 d7=p%(i,7):poke ms+d7,d:poke mc+d7,p%(i,4):d6=p%(i,6):poke ms+d6,90:poke mc+d6,0
68 next

: rem play music
69 gosub 85

:::::rem end main loop
70 goto 20

::::::::::::::::::::::
:rem music :::::::::::
:rem prepare next note
85 ni=ni+1:if ni>8 then ni=0:poke m1,0
:rem play a note :::::
86 poke m1,n%(ni):poke m2,n%(ni):poke m3,n%(ni)
87 return

:::::::: rem music off
88 poke m1,0:poke m2,0:poke m3,0:ni=0
89 return

::::::::::::::::::::::
:::::::::rem end match
::::::::::::::::::::::
::::::::rem select msg
100 if p%(0,5)=1 then msg$="human crash!":q=p%(0,1)*nc+p%(0,0):poke mc+q,2
101 if p%(1,5)=1 then msg$="computer crash!":q=p%(1,1)*nc+p%(1,0):poke mc+q,2
102 if p%(0,5)+p%(1,5)=2 then msg$="draw!"
:::::::::rem music off
103 gosub 88

::::::::rem earthquake
104 for n=1 to 10:for m=10 to 14
105  poke 36864,m:poke 36877,240-m
106 next m: next n
107 poke 36877,0

:::::::::rem show info
110 k$=chr$(17):?chr$(19)k$k$k$k$k$k$k$k$k$k$k$k$
111 ?chr$(28)"  "msg$:?"  any key continue   ";
::rem flush key buffer
112 get k$: if k$<>"" then 112
::::::::::::::rem wait
113 for i=1 to 1000: next
:rem read keyboard
115 get k$: if k$="" then 115
:::::::::::::rem exit?
116 if k$="x" then 120
::rem start new match
117 restore
118 goto 11

::::::::::::::::::::::
:::::: rem exit ::::::
::::::::::::::::::::::
: rem music off
120 gosub 88
: rem score screen
121 ?chr$(144)chr$(147):
122 ?"final score"
123 ?"----------------------"
124 ?"human    : ";p%(1,10)
125 ?"computer : ";p%(0,10)
126 if p%(0,10)=p%(1,10) then msg$="draw!":goto 129
127 if p%(0,10)<p%(1,10) then msg$="human wins!":goto 129
128 msg$="computer wins!"
129 ?msg$

:::::: new game? :::::
130 ?:?"play again (y/n)?"
: rem flush key buffer
131 get k$: if k$<>"" then 131
::::::::::::: rem wait
132 for i=1 to 1000: next
133 get k$: if k$="" then 133
134 if k$="y" then restore:goto 10
135 ?"bye.":end

:::::::rem paint score
140 ?chr$(19);:for i=1 to nc:?chr$(17);:next:d0=p%(0,10):d1=p%(1,10)
141 ?chr$(31)" human:"chr$(158)str$(d1)chr$(31)" computer:"chr$(30)str$(d0);
::::::: rem background score
142 for i=0 to 1
143 for ir=0 to 7:d=peek(cm+(48+p%(1-i,10))*8+ir)
144 for ic=7 to 0 step -1
145 d=d/2:d0=0:if d=int(d) then d0=p%(i,4)
146 d=int(d):poke mc+(ir+1)*nc+ic+2+10*i,d0
147 next:next:next
148 return

::::::::::::::::::::::
::::: rem data :::::::
::::::::::::::::::::::
: rem melody
200 data 215,201,187, 215,201,195, 215,201,187
: rem initial players values
210 data 5,10,1,0,7,0,225,224,0,1
220 data 16,10,-1,0,5,0,236,237,0,1

Tron 2.0

My first quick version of tron was extremely simple.

Here it is another more user friendly version, with improved computer I.A. and sound effects.

In game screen.

Download source code and d64 image disc: tron.rar

Source code.

::::::::::::::::::::::
:rem tron 2.0      :::
:rem by f.g.huerta :::
::::::::::::::::::::::

:: rem configure music
::::::::::: volume max
10 poke 36878,15

::::::::::::::::::::::
:rem music :::::::::::
:rem mm(2) -> instruments
:rem n%(3) -> melodie
20 dim mm(2):dim n%(3)
:rem init instruments
22 mm(0)=36874:mm(1)=36875:mm(2)=36876
:rem music pointers
24 mi=0:ni=0

::::::::::::::::::::::
:rem players :::::::::
:rem p(pn, data) -> data player array
:rem pn -> player id
:rem p(pn, 0)-> x pos
:rem p(pn, 1)-> y pos
:rem p(pn, 2)-> ix
:rem p(pn, 3)-> iy
:rem p(pn, 4)-> color
:rem p(pn, 5)-> status: 0->ok, 1->crashed
:rem p(pn, 6)-> num crashes
:rem p(pn, 7)-> last x pos
:rem p(pn, 8)-> last y pos
30 dim p(1,8)

:rem ms->screen memory
:rem mc->color memory
40 ms=7680: mc=38400

:rem v ->velocity
:rem s ->character sprite
:rem hc->head color
50 v=1:s=asc("*"): hc=0

::::::::::::::::::::::
:rem new game entry point
::::::::::::::::::::::
:rem reset scores
60 p(0,6)=0:p(1,6)=0

::::::::::::::::::::::
:rem new match entry point
::::::::::::::::::::::
:rem init melodie
70 for i=0 to 3:read n%(i):next i
:rem init players 
75 for pn=0 to 1: for i=0 to 5
80  read p(pn,i)
90 next i: next pn

:rem clear screen
100 print chr$(147)

::::::::::::::::::::::
:::rem begin main loop
::::::::::::::::::::::

: rem match finished?
110 if p(0,5)+p(1,5) > 0 then 1510

: rem game finished?
120 if p(0,6)=9 or p(1,6)=9 then 1810

: rem read keyboard
130 get k$

: rem exit?
140 if k$="x" then goto 1810

:::::::::rem player ia
210 if k$="a" then p(0,2)=-v:p(0,3)=0
220 if k$="d" then p(0,2)=v :p(0,3)=0
230 if k$="w" then p(0,3)=-v:p(0,2)=0
240 if k$="s" then p(0,3)=v :p(0,2)=0

:::::::::::rem computer ia
: inminent crash? and little random factor
310 q=(p(1,1)+p(1,3))*22+p(1,0)+p(1,2)
320 if peek(ms+q)<>s and rnd(1)<.95 then goto 410
: change direction
330 d=v: if rnd(1)<.5 then d=-d
340 if p(1,2)<>0 then q=(p(1,1)+d)*22+p(1,0):goto 360
350 q=p(1,1)*22+p(1,0)+d
: direction blocked? change direction again
360 if peek(ms+q)=s then d=-d
: final decision
370 if p(1,2)<>0 then p(1,2)=0:p(1,3)=d: goto 410
380 p(1,2)=d:p(1,3)=0

:::::::::: rem phisics
410 for pn=0 to 1
 :::: rem save old pos
420  p(pn,7)=p(pn,0):p(pn,8)=p(pn,1)
 :::::::::::: rem move
430  p(pn,0)=p(pn,0)+p(pn,2): p(pn,1)=p(pn,1)+p(pn,3)
 ::::::::: rem fix pos
440  if p(pn,0)<0  then p(pn,0)=21
450  if p(pn,0)>21 then p(pn,0)=0
460  if p(pn,1)<0  then p(pn,1)=22
470  if p(pn,1)>22 then p(pn,1)=0
480 next pn

:::::rem check crashes
:rem draw?
510 if p(0,0)=p(1,0) and p(0,1)=p(1,1) then p(0,5)=1:p(1,5)=1:goto 1510

:rem player crashes?
520 for pn=0 to 1
 :rem if crashes ->
 :rem  - update status
 :rem  - increment crashes
530  q=p(pn,1)*22+p(pn,0)
540  if peek(ms+q)=s then p(pn,5)=1: p(pn,6)=p(pn,6)+1
550 next

:::::::::::::rem paint
610 for pn=0 to 1
 :::::::::::::rem tail
630  q=p(pn,8)*22+p(pn,7)
640  poke mc+q,p(pn,4)
 :::::::::::::rem head
660  q=p(pn,1)*22+p(pn,0)
670  poke ms+q,s
680  poke mc+q,hc
690 next

:::::::rem paint score
720 q=2*22+2
730 poke mc+q,p(0,4)
740 poke ms+q,48+p(1,6)
750 q=2*22+19
760 poke mc+q,p(1,4)
770 poke ms+q,48+p(0,6)

: play music
780 gosub 1110

:::::rem end main loop
790 goto 110

::::::::::::::::::::::
::::: music ::::::::::
:rem prepare next note
1110 ni=ni+1:if ni>3 then ni=0:poke mm(mi),0:mi=mi+1
1120 if mi>2 then mi=0
:rem play a note :::::
1130 poke mm(mi),n%(ni)
1140 return

:::::::::::: music off
1210 poke mm(0),0
1220 poke mm(1),0
1230 poke mm(2),0
: reset music pointers
1240 mi=0:ni=0
1250 return

::::::::::::::::::::::
:::::::::rem end match
::::::::::::::::::::::
::::::::rem select msg
1510 if p(0,5)=1 then msg$="human crash!":q=p(0,1)*22+p(0,0):poke mc+q,2
1520 if p(1,5)=1 then msg$="computer crash!":q=p(1,1)*22+p(1,0):poke mc+q,2
1530 if p(0,5)+p(1,5)=2 then msg$="draw!"

:::::::::rem music off
1540 gosub 1210

::::::::rem earthquake
1550 for n=1 to 10:for m=10 to 14
1560  poke 36864,m:poke 36877,240-m
1570 next m: next n
1580 poke36877,0

:::::::::rem show info
1610 print msg$
1620 print "any key continue"
::rem flush key buffer
1630 get k$: if k$<>"" then 1630
::::::::::::::rem wait
1640 for i=1 to 1000: next
:rem read keyboard
1650 get k$: if k$="" then 1650
:::::::::::::rem exit?
1660 if k$="x" then 1810
::rem start new match
1670 restore
1680 goto 70

::::::::::::::::::::::
:::::: rem exit ::::::
::::::::::::::::::::::
: rem music off
1810 gosub 1210
: rem score screen
1815 print chr$(147)
1820 print "final score"
1830 print "----------------------"
1840 print "human    : ";p(1,6)
1850 print "computer : ";p(0,6)
1860 if p(0,6)=p(1,6) then msg$="draw!":goto 1890
1870 if p(0,6)<p(1,6) then msg$="human wins!": goto 1890
1880 msg$="computer wins!"
1890 print:print msg$

:::::: new game? :::::
1900 print:print"play again (y/n)?"
: rem flush key buffer
1910 get k$: if k$<>"" then 1890
::::::::::::: rem wait
1920 for i=1 to 1000: next
1930 get k$: if k$="" then 1930
1940 if k$="y" then restore:goto 60
1950 print "bye."
1960 end

::::::::::::::::::::::
::::: rem data :::::::
::::::::::::::::::::::
: melody
2010 data 195,201,207,209
: initial players values
2020 data 9, 11, 0, -1, 7, 0
2030 data 11, 11, 0, -1, 5, 0

Tron – Remembering old Commodore days

A couple of days ago, I found in Amazon the book “A commodore 64 Walkabout by Robinson Mason”, so I had no choice but buy it.

As many other nowadays developers, in the eighties I was the owner of a fantastic Commodore Vic-20, a real cool computer, the real programmer teacher for many of us.

After reading no more than twenty pages, I had to download the VICE emulator and as if it was an old ritual, I began to type the game of TRON, a clasic game that I have developed in every computer platform that I have owned, and in every programming language that I have learned.

Here is the code I have been able to develop in a couple of hours of remembering CBM Basic. The code works ok in the Commodore Vic-20 emulation of VICE. Enjoy it.

10 : rem TRON   :::::
12 : rem by     :::::
14 : rem F.G.Huerta :

20 rem ::::::init vars
25 rem n => (x, y, ix, iy, color)
30 dim p%(1,4)
40 for pn=0 to 1
50  for i=0 to 4
60   read a: p%(pn,i)=a
70  next i
80 next pn

90 :::::::rem velocity
100 v=1

110 rem ::::::::sprite
120 s=asc("*")

130 rem screen & color
140 ms=7680: mc=38400

150 :::rem init screen
160 print chr$(147)

170 :::::rem main loop
180 get k$
190 if k$="x" then msg$="bye":goto 1600: rem salir

200 :::::rem player ia
210 if k$="a" then p%(0,2)=-v:p%(0,3)=0
220 if k$="d" then p%(0,2)=v :p%(0,3)=0
230 if k$="w" then p%(0,3)=-v:p%(0,2)=0
240 if k$="s" then p%(0,3)=v :p%(0,2)=0

300 :::::::rem comp ia
310 x=p%(1,0)+p%(1,2):y=p%(1,1)+p%(1,3)
320 gosub 1000: rem get char
330 if z<>s then goto 400
340 if p%(1,2)<>0 then p%(1,2)=0:p%(1,3)=1: goto 400
350 p%(1,2)=1:p%(1,3)=0

400 :::::::rem phisics
410 for pn=0 to 1
420   gosub 1100: rem p to vars
430   gosub 1200: rem move
440   gosub 1300: rem vars to p
450 next pn

500 :::::::rem chk fin
510 if p%(0,0)=p%(1,0) and p%(0,1)=p%(1,1) then 1400: rem empate
520 for pn=0 to 1
530   gosub 1100: rem p to vars
540   gosub 1000: rem get char
550   if z=s then 1500: rem winner
560 next

600 ::::::::rem pintar
610 for pn=0 to 1
620   q=p%(pn,1)*22+p%(pn,0)
630   poke mc+q,p%(pn,4)
640   poke ms+q,s
650 next

700 ::::::rem end loop
710 goto 170

1000 ::::::rem get char
1010 q=y*22+x
1020 z=peek(ms+q)
1030 return

1100 :::::rem p to vars
1110 x = p%(pn,0): y = p%(pn,1)
1120 ix= p%(pn,2): iy= p%(pn,3)
1130 return

1200 ::::::::: rem move
1210 x=x+ix: y=y+iy
1220 if x<1  then x=21
1230 if x>21 then x=0
1240 if y<1  then y=21
1250 if y>21 then y=0
1260 return

1300 :::::rem vars to p
1310 p%(pn,0)=x
1320 p%(pn,1)=y
1330 return

1400 ::::::: rem empate
1410 msg$="draw"
1420 gosub 1700: rem efectos especiales
1420 goto 1600: rem salir

1500 :::::::rem winner
1510 msg$="human win"
1520 if pn=0 then msg$="computer win"
1530 gosub 1700: rem efectos especiales

1600 ::::::::rem salir
1610 print msg$
1620 end

1700 :::rem efecto fin
1710 for n=1 to 10
1720  for m=10 to 14
1730   poke36864,m
1740  next m
1750 next n
1760 return 

2000 :::::::::rem data
2010 data 9, 11, 0, 1, 7
2020 data 11, 11, 0, 1, 2