#TurboBASIC XL
Explore tagged Tumblr posts
atariaction · 5 years ago
Text
10-Line Blackjack
Tumblr media Tumblr media
Hot on the heels of the poker game, I wrote a blackjack game for the 10-line BASIC contest. It is also in TurboBASIC XL on the Atari 8-bit, and also in ten 120-character lines. I borrowed the card shuffling code from the poker game, but otherwise it’s all new code.
As always with these short programs, there were some space tradeoffs. In exchange for a wallet/calculating money, I found room to show simple card graphics. I also had to give up the custom character with the cute little “10” character. Instead, “T” represents the 10 card.
Like standard blackjack, it starts by dealing your two cards face up, one dealer card face up and one face down. You can press H to hit (take another card) or S to stand (stop taking cards.) (This version does not support doubling down or splitting hands.) After you Stand, it reveals the dealer’s face-down card and the dealer plays. The dealer follows standard Las Vegas rules: always hitting on 16 or less; always standing on 17 or more.
The biggest challenge was calculating Aces, which in Blackjack can count for either 1 or 11. When figuring the player’s score, it starts by assuming an Ace is worth 1. When the player Stands: if the player holds an ace and counting it as 11 won’t cause the player’s total to exceed 21, it adds 10 to the player’s total. On the other hand, when calculating the dealer’s score, it starts by assuming an Ace is worth 11. If after a hit the dealer’s total exceeds 21 and it holds an Ace, it reduces the dealer’s total by 10 and keeps on playing.
Here’s the code:
REM BLACKJACK - KEVIN SAVETZ - JAN 2-3 2020 DIM CARDT$(15),CARDM$(15),CARDS$(15),CARDD$(15),CARDE$(15),SUIT$(4),N$(13),U(52),D(14),NUMCARDS(1),SUM(1),V$(13),I$(1),ACES(1) GR.0 POKE 82,0 CARDT$="\11\12\12\12\12\12\05\1E\1E\1E\1E\1E\1E\1E\1D" CARDM$="\7C \7C\1E\1E\1E\1E\1E\1E\1E\1D" 'CARDT$: card top 'CARDM$: card middle 'CARDS$: card middle with suit 'CARDD$: card middle with number in upper left 'CARDE$: card middle with number in lower right 'Card bottom and card back are drawn in the GOSUB area without strings to save space here 'U: Temp. storage whether a card has been placed in the deck 'D: Deck of randomized cards 'NUMCARDS: Number of Cards held by player/dealer 'SUM: SUm of player and dealer cards 'I$: storage for INKEY$ keyboard input 'ACES: Number of ACes held by player/dealer that may be counted at the other value (1/11) N$="A23456789TJQK":'one-character card names. V$="\01\02\03\04\05\06\07\08\09\0A\0A\0A\0A":'values of cards A-K SUIT$="\00\10\60\7B":'heart club diamond spade 'SHUFFLE FOR X=0 TO 14:'Fill slots. Only slotting 15 cards is faster than 52. N=0 WHILE N=0:'while we haven't found a card for this slot Y=RAND(52):'which card might go in this slot? IF (U(Y)=0):'if we haven't slotted this card yet D(X)=Y:'slot now contains this card U(Y)=1:'mark card as used in a slot N=1:'move on to next card ENDIF WEND NEXT X 'Deal cards FOR HAND=0 TO 1 FOR P=0 TO 1 OB=HAND AND P:'if second card going to dealer, show card back (OBscure it) GOSUB 50 NEXT P NEXT HAND 'Ask Hit or Stand WHILE I$<>"S" AND SUM(0)<22 I$="" ?"\1D\C8it/\D3tand?"; WHILE I$<>"S" AND I$<>"H" I$=INKEY$ WEND ?"\9C":'erase old Hit/Stand query IF(I$="H") P=0:'the player is getting cards GOSUB 50 ENDIF WEND 'After player has played, while player holds an ace, and if 11 is better for the 'score than 1, add 10 to the SUm total. WHILE ACES(0) AND SUM(0)+10<22 ACES(0)=ACES(0)-1 SUM(0)=SUM(0)+10 WEND P=1:'Now dealer's turn GOSUB 50:'reveal SEcret OBscubed card IF ((SUM(0)=21 AND NUMCARDS(0)=2)=0):'Skip next part if player got blackjack WHILE (SUM(0)<22 AND SUM(1)<17):'if player hasn't busted and dealer's hand <=16 PAUSE 60 GOSUB 50 'If >21 but dealer holds an ACe, change value of that ace from 11 to 1 WHILE SUM(1)>21 AND ACES(1) ACES(1)=ACES(1)-1 SUM(1)=SUM(1)-10 WEND WEND ENDIF 'Display totals and winner POS.0,22 ?"You: ";SUM(0);"\7F\7FDealer: ";SUM(1) 'reusing CARDT$ for the summary text CARDT$="Push" IF SUM(0)<22 IF SUM(1)>21 OR SUM(1)<SUM(0) CARDT$="You win!" ENDIF IF SUM(1)<22 AND SUM(1)>SUM(0) CARDT$="Dealer wins" ENDIF ELSE CARDT$="Busted" ENDIF ?CARDT$; WHILE INKEY$="":WEND RUN 50 CARDS$=CARDM$:CARDD$=CARDM$:CARDE$=CARDM$ POS. NUMCARDS(P)*2+P*20,2+NUMCARDS(P)*2 IF (P=1 AND SE):'reveal the SEcret card X=SE-1 SE=0 ELSE X=D(Z):'otherwise, next card in the deck Z=Z+1:'set pointer to next card ENDIF N=X MOD 13+1:M=X DIV 13+1 ?CARDT$;:'card top IF (OB=0):'if not OBscuring card... CARDS$(4,4)=SUIT$(M,M):'put suit on card middle CARDD$(2,2)=N$(N,N):'put number on upper-right CARDE$(6,6)=N$(N,N):'and lower-left ?CARDD$;CARDM$;CARDM$;CARDS$;CARDM$;CARDM$;CARDE$; SUM(P)=SUM(P)+ASC(V$(N,N)):'add to player's SUm total IF card face is shown SUM(P)=SUM(P)+(10*P*(N=1)):'When dealer draws an ace, count it as 11 NUMCARDS(P)=NUMCARDS(P)+1:'increment Number of Cards held by player ACES(P)=ACES(P)+(N=1):'numbr of ACes held by that player ELSE:'OBscuring card FOR X=1 TO 7:?"\7C.....\7C\1E\1E\1E\1E\1E\1E\1E\1D";:NEXT X:'back of card pattern SE=N:'save SEcret card OB=0:'don't OBscure next card ENDIF ?"\1A\12\12\12\12\12\03":'card bottom RETURN
7 notes · View notes
atariaction · 5 years ago
Text
10-Line Poker Machine
Tumblr media
My first entry for the 2020 10-line BASIC contest is a poker machine simulator written in TurboBASIC XL for the Atari 8-bit computer. At ten 120-character lines, it qualifies for the PUR-120 category. It is based on the common “Jacks Or Better” poker machine, although I changed the payouts to make it more fun and to conserve space.
The game deals a hand of five playing cards. You can choose to “hold” any or all of the cards by pressing 1 though 5, then press any other key to replace the cards that you did not hold. (Held cards are not replaced.) It then calculates whether you’ve won, based on standard poker hands.
Here are the payouts:
royal flush +650 (real game: 1250) royal straight +500 (not in real game) straight flush +350 (real game: 250) 4 of a kind +225 (real game: 125) full house +150 (real game: 30) flush +150 (real game: 25) straight +200 (real game: 20) 3 of a kind +150 (real game: 15) 2 pair +50 (real game: 10) pair of Jacks or better +5 (real game: 10)
With all the logic for calculating poker hands, there wasn’t room for card graphics. I did make a custom character set with just one special character: a "10" for the only two-digit card. I am proud of squeezing in money though. You start with $50 in your wallet, and the game costs $5 per hand. The game remembers your wallet by poking it into unused memory ($600, the top of Page 6) then peeking it back after it re-RUNs. Because RUN clears all the variables, this uses much less program space than resetting all the variables by hand.
Here’s the code:
GR.0:POKE 752,1:REM SET UP SCREEN DIM D(9),U(53),C(13),W$(29),I$(1),H(5),F$(8),SUIT$(4),N$(13) F$="\00\CE\DB\DB\DB\DB\CE\00" B=DPEEK($600)-5:'money. minus 5 builds in the cost of the round. B=B+(45*(B<0)):'that is, IF(B<0) THEN B=50-5. 'Since there's not enough space to zero-out necessary variables if 'we were to loop to play again, and we lose all variables at re-RUN: 'we save user's money in page 6 where it's safe from BASIC. 'On first run, cross our fingers that $600 is seeded 'at 0, otherwise \_(ツ)_/ ?"$";B:? REM D - cards in shuffled order. This game only deals max 10 cards REM U - tracks whether card number in subscript has been shuffled in REM C - Counts number of each card in suit REM W$ - Win/loss text REM I$ - storage for INKEY$ REM H - tracks which of the 5 card slots are Held REM F$ - custom character ("10") REM SUIT$ - control characters for suits REM N$(13) - card name characters (A thru K) SUIT$="\00\10\60\7B":'heart club diamond spade N$="A23456789#JQK":'one-character card names. '10' replaces # 'Replace '#' with "10" character CH=(PEEK(106)-16)*256:MOVE 57344,CH,1024 MOVE ADR(F$),CH+24,8:POKE 756,CH/256 'SHUFFLE FOR X=0 TO 9:'Fill slots. Only slotting 10 cards is faster than 52. N=0 WHILE N=0:'while we haven't found a card for this slot NN=RAND(52):'which card might go in this slot? IF (U(NN)=0):'if we haven't slotted this card yet D(X)=NN:'slot now contains this card U(NN)=1:'mark card as used in a slot N=1:'move on to next card ENDIF WEND NEXT X REM FORCE CARDS FOR TESTING 'D(0)=12 'D(1)=12+13 'D(2)=13+6 'D(3)=13+13+6 'D(4)=15 FOR GO=1 TO 2:'Do the next part twice 'SHOW CARDS FOR X=0 TO 4 'Show card name, suit, and the slot number N=D(X) MOD 13+1:M=D(X) DIV 13+1:?N$(N,N);SUIT$(M,M);" \1B\7F";X+1 'D(X) MOD 13+1 is the card number 1-13 'D(X) DIV 13+1 is the suit 1-4 'This is very clever. NEXT X IF(GO=1):'Choose hold cards, first time though only WHILE QQ=0 POKE 764,255 WHILE I$="" I$=INKEY$ WEND POKE 764,255:I$="" I=ASC(I$)-49 IF(I>=0 AND I<5) H(I)=NOT H(I):'Toggle hold status for chosen slot POS.9,I+2 IF(H(I)):?"HOLD":ELSE:?" ":ENDIF ELSE QQ=1 ENDIF WEND 'Replace cards that were not held. 'Every card has one potential replacement FOR X=0 TO 4 D(X)=D(X+5*(1-H(X))) 'if held, D(X)=D(X), unchanged. if not, D(X)=D(X)+5 'or, more readably: IF(H(X)=0):D(X)=D(X+5):ENDIF NEXT X ENDIF POS.2,8*GO:'Show new cards under old cards NEXT GO 'Game is over, now see if it's a wining hand 'Count each card type in the hand F=(D(0) DIV 13)+1:'F="is there a flush?" seed with 0th card suit FOR X=0 TO 4 N=D(X) MOD 13 C(N)=C(N)+1:'C(N) is how many of that card in the hand 'T is the maximum number of similar cards we've found T=T+(C(N)-T)*(C(N)>T) 'or, more readably: IF (C(N)>T):T=C(N):ENDIF F=((D(X) DIV 13)+1=F)*F:'if suit is not the same, set F to 0. I feel clever. NEXT X 'Count pairs - how many sets of exactly 2 are in the hand? FOR X=0 TO 12 P=P+(C(X)=2) 'Or, IF (C(X)=2):P=P+1:ENDIF NEXT X 'FULL HOUSE OR 3 OF A KIND OR 4 OF A KIND IF T>2:'really this is: IF T=3 OR T=4 becasue it can't be more IF P:'If there's also a pair W$="FULL HOUSE" B=B+150 ELSE W$=STR$(T) W$(2)=" OF A KIND":'msg is 3 or 4 of a kind B=B+(T-1)*75 ENDIF ELSE:'max same cards T <= 2 IF ((C(10)=2) OR (C(11)=2) OR (C(12)=2) OR (C(0)=2)) W$="JACKS OR BETTER" B=B+5 ENDIF IF(P=2) W$="2 PAIR" B=B+50 ENDIF ENDIF C(13)=C(0):'Kludge to copy Ace to above King FOR X=0 TO 9 IF (C(X) AND C(X+1) AND C(X+2) AND C(X+3) AND C(X+4)) W$="STRAIGHT " B=B+200 IF (X=9) W$="ROYAL " B=B+250 ENDIF ENDIF NEXT X 'Print win/loss message IF(W$="" AND F=0) ?"LOSE"; ELSE ?W$; IF F ?"FLUSH"; B=B+150 ENDIF ENDIF ?:?"$";B DPOKE $600,B 'Save $ on page 6 for next round 'WAIT FOR KEYPRESS, PLAY AGAIN WHILE INKEY$="":WEND RUN
5 notes · View notes
atariaction · 6 years ago
Text
Lander: BASIC Tenliners Contest 2019 entry
Tumblr media
Use the joystick controller to land your LEM (lunar excursion module) on a moon. Land on one of the green landing pads. The trigger fires the main thrusters, pushing the ship upward against the moon’s gravity. Left/right stick movement fires the side thrusters for horizontal movement.
A control panel shows your vertical speed (indicated by ↓), horizontal speed (→), strength of gravity on the moon (G), and amount of fuel (F). To land safely, you must touch down on a landing area with a vertical speed of 10 or less, and horizontal speed of 5 or less. Flying off the sides or the top of the screen is deadly. Running out of fuel is not recommended.
Each moon is a little different, with gravity ranging from light (G5 in the control panel) to heavy (G20.) Moons usually have one or two landing pads. (Rarely, you will come across a moon that has none! In this case you will die. I’m sorry. Space exploration is dangerous.)
The first Lunar Lander that I was exposed to was Atari’s vector arcade version, which seemed amazing — and impossibly difficult. Later, my dad bought the Adventure International version of Lunar Lander for his Atari 800. (It was one of the few pieces of Atari software that he didn’t pirate.) In that version, the LEM doesn’t rotate. Instead, side thrusters push the ship horizontally while it remains in a vertical position. I did the same in my version.
(That’s where I learned the word “hybrid.” The stats on the back of the box said “Language: Hybrid.” I wondered if that was some programming language I hasn’t heard of; dad explained that the word meant “a combination of two things.” In this case, BASIC and assembly language.)
Benj Edwards wrote a great history of Lunar Lander games that is worth reading.
I’ve wanted to program a Lunar Lander-type game since I was a teen. I’m pretty sure I tried it using shape tables on my Apple IIc in AppleSoft BASIC, and experimented with it in Atari BASIC at some point, but I never could get the movement with respect to thrust and gravity right. I didn’t have the math concepts. But in the past few weeks, with my buddy helping with the math for Bouncy; and reading Bruce Artwick’s book Microcomputer Displays, Graphics and Animation, I now know jussssst enough math to be dangerous with Atari graphics. So I was finally able to create a version of Lunar Lander, and in 10 lines of Turbo-BASIC XL.
For the contest, my program fits in the 120-characters-per-line category. In terms of cramming stuff into 10 lines, it’s some of my best work and I learned a lot. Several times I thought the program has to be done, there was absolutely no more room to squeeze in another feature. Then I’d find a way to do something in fewer bytes, making room for a tiny improvement elsewhere.
My favorite was replacing for-next loops to move or generate data with the MOVE statement, with copies memory around RAM. For instance, I needed to zero out Player (sprite) data. Normally I’d do that with FOR I=P+512 TO P+896:POKE I,0:NEXT I. But — MOVE DPEEK(88),P+512,384 does the same thing with fewer bytes (and much faster.) But I needed to copy from an area of RAM that is all zeros. Where would I find such a place? A newly blank screen is filled with zeros. At another point, I needed a mess of random-looking data for the ship explosion. I started with a FOR-NEXT loop writing RANDom numbers, but ended up moving random bits of data from the Atari ROM into sprite memory. Again, it was much faster and took of less precious program space.  I’m not implying at all that I invented this technique, but I figured it out on my own and it was satisfying.
Here’s the commented code:
'LANDER by Kevin Savetz 'March 22 2019 GRAPHICS 23:'GR. 7, no text window. 159x92 'normally y=95 for full GR.7 screen, we lose a little because text line at top DIM F0$(16),F1$(10) F0$="\00\00\00\00\3C\42\42\3C\42\7E\5A\81":'LEM graphic with blank spaces around 'to make erasing old LEM easy as it moves vertically 'F1$ is workspace for the P1 thrust flame FUEL=150:'starting fuel A=PEEK(106)-20:'set aside RAM for players POKE 54279,A:'PMBASE P=A*256:'top of P/M memory POKE 559,46:'Double line resolution P/M characters VX=-5+RAND(11):'Initial X speed POKE 53277,2:'turn on players (not missiles) M=DPEEK(88):'top of screen RAM MOVE M,P+512,384:'zero Player data, copying 0s from the fresh blank screen POKE 704,88:'PCOLR0. I like purple. 'custom display list D=DPEEK(741):'location of display list POKE D+4,66:'top line is Graphics 0 text line (mode 2) -MOVE D+102,D+99,3:'shorten the display list so screen's not too tall POKE 752,1:'hide cursor 'draw terrain & stars/ground texture COLOR 1 PLOT 0,90-RAND(60):'start drawing terrain on left edge LPP=1:'first segment can't be landing pad FOR I=10 TO 150 STEP 10 Z=M+40+RAND(3500):'pick a location for star/ground texture POKE Z,PEEK(Z)!3:'draw it IF (LPP OR (RAND(5) OR LP=2)):'draw craggy rock if we just drew a landing pad 'or if we've already drawn 2. Otherwise, maybe draw a pad II=RAND(40)+52:'rock height COLOR 1:'color of rock LPP=0:'remember that last thing drawn isn't a pad ELSE COLOR 2:'color of pads LP=LP+1:'count number of landing pads LPP=1:'remember last thing drawn is a pad ENDIF DRAWTO I,II:'draw the rock/pad NEXT I COLOR 1 DRAWTO 159,60 PAINT 159,92 DT=.05:'Time increment. Lower numbers make the game slower X=50+RAND(125):'Initial X Y=520:'Initial Y G=RAND(15)+5:'Strength of gravity VY=1+RAND(10):'Initital Y speed DO:'main loop POKE 53278,0:'Clear PM collisions X=X+VX*DT:'change LEM's X POKE P+Y+264,0:'clear side thrust Y=Y+VY*DT:'change LEM's Y VY=VY+G*DT:'new Y speed POKE 53248,X:'HPOSP0 position LEM at new X MOVE ADR(F0$),P+Y,16:'draw LEM at new vertical position 'clean up from last move... -MOVE M,P+Y+136,12:'copy 0s from top corner of screen to erase flame (if any) SOUND:'stop thrust sound if any 'thrust. Player 1 is the bottom thrust flame IF FUEL AND STRIG(0)=0:'if trigger and have fuel VY=VY-2:'decrease vertical speed MOVE ADR(F1$),P+Y+136,10:'place flame 8 lines below P0 SOUND 0,50+Y,8,8:'I KNOW, there's no sound in space POKE 53249,X:'P1 X position POKE 705,50+RAND(11):'flame color FOR Z=3 TO 8 POKE ADR(F1$)+Z,RAND(16)*4:'rows of random flame, but only 4 bytes 'in the middle so it isn't too wide 00111100 NEXT Z FUEL=FUEL-1:'reduce fuel ELSE:'if no trigger, check for left/right thrust. Player 2 is the side thrust flame S=STICK(0) Z=(S=7)-(S=11):'get joystick left-right status IF Z AND FUEL AND NOT FIRE:'if joystick and have fuel and LEM isn't thrusting up POKE P+Y+264,3:'put P2 flame at correct vertical position relative to LEM POKE 53250,X-3+(4*Z):'side flame on left or right of LEM POKE 706,50+RAND(11):'P2 color VX=VX-Z:'change X speed SOUND 0,50,8,8:'noise FUEL=FUEL-1 ENDIF ENDIF POKE 87,0:'get ready to print in text window 'If LEM goes off screen or hits terrain or hits landing pad too fast IF X<40 OR X>205 OR Y<510 OR PEEK(53252)&1 OR (PEEK(53252)&2 AND (VY>10 OR ABS(VX)>5)) FOR Z=1 TO 250:'explosion SOUND 0,50+RAND(30),6,8:'in space no one can hear you scream MOVE 59740+RAND(500),P+Y+4,12:'copy random data from ROM to P1 POKE 704,50+RAND(21):'P1 color NEXT Z RUN:'restart ENDIF 'show speed, gravity, and fuel POS. 14,0:?"\1B\1D";INT(VY);" \1B\1F";INT(VX); ?" \C7";G;" \C6";FUEL;" " IF(PEEK(53252)&2):'touched landing pad, make happy music & restart SOUND 0,121,10,10:PAUSE 80 SOUND 1,81,10,10:PAUSE 80 SOUND 2,60,10,10:PAUSE 150 RUN ENDIF LOOP
12 notes · View notes
atariaction · 6 years ago
Text
Bomber: BASIC Tenliners Contest 2019 entry
Tumblr media
My sixth entry in the 10-line BASIC contest is Bomber, a Kaboom! clone. It’s written in Turbo BASIC XL and fits in the PUR-120 category. You need a paddle controller and quick reflexes to catch the mad bomber’s falling bombs. The game ends when you miss five bombs. You earn one point for catching a bomb, and lose an increasing number of points for missing them.
Here's the code:
A=PEEK(106)-4:POKE 106,A:PM=A*256 'Where player missile data goes DIM F$(24),B(9),VOL(9) 'F$=character set data. B=bomb position (0 if inactive) 'VOL=volume of sound channels. (Only 0-3 are used.) GRAPHICS 17:'I love this graphics mode LV=10:'level starts at 10, goes down to 2. It's weird but player doesn't see that info. SB=2:'"audio channel available for boom sound starts at 2 SC=DPEEK(88):'top of screen RAM CH=(PEEK(106)-16)*256:'find RAM for character set POKE 712,$D6:'background color POKE 708,0:'bomber color F$="\02\08\10\38\74\7C\7C\38\38\7C\D6\D6\7C\6C\38\54\FE\82\FE\82\FE\C6\44\44" 'character set '1 = \02\08\10\38\74\7C\7C\38 = bomb '2 = \38\7C\D6\D6\7C\6C\38\54 = top of bomber '3 = \FE\82\FE\82\FE\C6\44\44 = bottom of bomber MOVE 57344,CH,1024:'Copy character set to RAM MOVE ADR(F$),CH+8,24:'install custom characters POKE 756,CH/256:'switch to RAM chatacter set POKE 53256,3:POKE 54279,A:POKE 559,46:POKE 53277,3:POKE 53248,130:POKE 704,10:POKE 53278,0 'Set up Player/Missile graphics FOR I=0 TO 512:DPOKE PM+I*2,0:NEXT I:POKE PM+618,$3F 'Empty the P/M area that we need. Draw the line that player controls. 'MAIN LOOP WHILE M<5:'go until player misses 5 bombs BD=RAND(20):'bomber destination 'MOVE PLAYER PADDLE WHILE BD<>BX P=180-PADDLE(0) IFP<37:P=37:ENDIF POKE 53248,P:'HPOSP0 'CAUGHT BOMB? IF PEEK(53252):'P0PF collision? FOR X=0 TO 9:'test every bomb IF B(X)>419:'if it's on bottom level of screen POKE SC+B(X),0:'erase it B(X)=0:'mark it inactive S=S+1:'increase score G=G+1:'"got" counter for stats ENDIF NEXT X POKE 53278,0:'clear P/M collision SG=SG+1:SG=SG*(SG<2):VOL(SG)=6:'happy beep POSITION 1,0 ?#6;S;" ":'update score ENDIF 'DROP A NEW ONE IF(RAND(LV)=0):'As level decreases, bombs drop more frequently POKE SC+80+BX,65:'draw bomb at top of screen B(C)=80+BX:'mark it as active C=C+1:'iterate 0-9, which bomb gets dropped next C=C*(C<10) ENDIF 'REM MOVE EXISTING BOMBS FOR X=0 TO 9 IF VOL(X):'make/update boom and beep noises for sound channels 0-3 VOL(X)=VOL(X)-2:'if channel has volume, make it quieter SOUND X,60,10-(X>1)*2,VOL(X):'update sound channel '^ channels 0-1 are pure tone beep, 2-3 are noisy boom. ENDIF IF B(X):'if bomb is active POKE SC+B(X),0:'erase old bomb position B(X)=B(X)+40:'move it down one row IF (B(X)>479):'if it's at the bottom B(X)=0:'mark it inactive S=S-(11-LV):'lose points for missing it M=M+1:'missed counter SB=SB+1:IF(SB=4):SB=2:ENDIF:'get channel for boom sound VOL(SB)=14:'queue up boom POSITION 1,0:?#6;S;" ":'update score ELSE POKE SC+B(X),65:'not at the bottom, redraw in new position ENDIF ENDIF NEXT X 'MOVE BOMBER Z=SC+40+BX:'bomber screen position POKE Z,0:'erase bomber top POKE Z+20,0:'and bottom BX=BX+(BX<BD):'move toward destination BX=BX-(BX>BD):'or in the other direction POKE SC+40+BX,2:'draw bomber top POKE SC+60+BX,3:'and bottom WEND:'WHILE BD<>BX - bomber has reached his destination... T=T+1:'increase number of trips tally IF (T=35):'if he's made enough trips LV=LV-(LV>2):''Reduce level number, minimum is 2. T=PEEK(712)-$10:'new level, new background color T=T+(T<6)*$D6:'don't let bg color get negative POKE 712,T:'change background color T=0:'Reset trip counter POKE 77,0:'inhibit attract mode ENDIF WEND :'WHILE M>5 'GAME OVER SOUND:'quiet POS. 0,0 POKE 712,10:'black background ?#6;"GAME OVER" ?#6;"SCORE: ";S ?#6;"ACCURACY: ";TRUNC((G/(G+M))*100);"%" WHILE PTRIG(0):WEND:RUN
13 notes · View notes
atariaction · 6 years ago
Text
Floody Bot: BASIC Tenliners Contest 2019 entry
Tumblr media
I love the BASIC 10-Liner contest! I didn’t find the time/energy/whatever to enter in 2018, so am excited to write some short BASIC programs for this year’s contest. First out of the gate is Floody Bot. This will be an entry for the EXTREME-256 category.
My soft overarching theme for entries this year is classic BASIC algorithms. Floody Bot started with the kernel of Maze Generator by Charles Bond, which was published in Compute! Magazine Issue 19.
In this game, you play the part of a rescue bot entrusted to save humans from rising flood waters. Touch a human to save them. You must rescue three or more humans to proceed to the next level. As levels increase, the flood waters rise more quickly. Oh, the bot can’t swim.
Once per level, you can press the fire button to set off a bomb destroying everything in your horizontal row. This can get you out a sticky situation. If your bot gets stuck, press START to self-destruct. (If you’ve already rescued three or more humans, you’ll move on to the next level with a new bot.)
Earn points for rescuing humans (lower-down humans are worth more.) Lose a lot of points if your bomb kills a human. (You don’t lose points if flood waters kill a human.)
Let’s look at the code:
GRAPHICS 17:DIM F$(48),A(5):CH=(PEEK(106)-16)*256
Set up graphics screen — graphics 1 with no text window. Save space for strings. F$ is for the custom character set. Array A is for maze generation. CH is the location of the character set in RAM.
F$="\FB\FB\FB\00\DF\DF\DF\00\08\61\B4\D0\66\0B\2D\86\7E\42\42\7E\99\7E\BD\66\3E\2A\14\3E\5D\1C\36\77\80\51\2A\04\80\45\2A\10"
This mess of ATASCII is the custom characters.
MOVE 57344,CH,1024:MOVE ADR(F$),CH+8,40:POKE 756,CH/256
Install the custom characters.
A(0)=2:A(1)=-40:A(2)=-2:A(3)=40 SC=DPEEK(88):
Top of screen memory
DO :'main loop
Set up level:
A=SC+21+(16*RAND(2))
Robot starts in either upper corner
G=0:GG=0:L=L+1:BM=1
G=number of guys to collect. I’m not being sexist. It’s a legacy variable because the humans were originally Gems. GG=number of Guys Got (saved). increase level, you have one bomb
W=16*(L+3)+8:WHILE W>255:W=W-258:WEND:POKE 710,W:
Change the brick color per level.
POKE 709,136 POKE 711,56
Set water and bomb colors.
POSITION 0,0 FOR I=1 TO 23:FOR J=1 TO 19:?#6;"\A1";:NEXT J:?#6:NEXT I
fill screen with bricks
COLOR 161:TEXT 11*RAND(2),15,CHR$(64+L)
draw the level letter in either lower corner in bricks 161=129 (Wall character) + 32 for the correct color
POKE 708,0
Hide character set while drawing maze. (It’s fun to watch but might be confusing.)
Now we get into the maze generation. It was a lot of work to tighten up the tangled original code and make it work without GOTOs, but that’s necessary for 10-liners.
POKE A,5 
place a marker at the maze starting point
MR=1:
MR=1: Start with a Random number. MR=0: iterating 
REPEAT BT=1
BT=0: blazing a new path. BT=1: we're BackTracking
IF MR
MR=do we want a random number to start looking for a valid direction?
J=INT(RND(0)*4):X=J
J=pick a random direction. X=remember our starting dir.
ENDIF B=A+A(J)
look forward to possible next space
IF PEEK(B)=129
is it a wall character? Make it a hallway 
POKE B,J+1
leave appropriate bread crumb for backtracking
POKE A+A(J)/2,0
draw hall character on the even column 
A=B
possible next space promoted to new space
MR=1:BT=0:
we'll pick a random direction to go from here
ELSE
its not a wall, so we can't use it. check another direction
J=(J+1)*(J<3):'iterate 1-2-3-0-1-2-3... IF J<>X MR=0:BT=0
we haven't tested all 4 yet, so look in next direction
ENDIF ENDIF IF BT:
we've tried all 4 directions with no luck. Time to backtrack
J=PEEK(A):
Get breadcrumb on current space
W=PEEK(A-1)+PEEK(A+1)+PEEK(A-20)+PEEK(A+20)=387*(J<5) POKE A,4*W
if there walls on 3 sides, it's a dead end, so draw guy (chr 4) (except on the staring spot: no guy there) else draw hall character (0) to erase unsightly breadcrumb.
G=G+W
G=number of guys to collect
A=A-A(J-1)
change current space to the one pointed to by the breadcrumb
ENDIF UNTIL J=5 
when we've backtracked back to the starting point, maze is done!
IF G<6 :GG=9:G=0:L=L-1:LOOP:ENDIF
If the maze generated fewer than 6 people, it's not good, give up and create another. This is hacky but oh well.
POKE 708,26
Reveal character set
We’ve finally built the screen, now we can play the game!
WL=23:'initial water level C=100-L*10:'countdown before water first appears.
C=C+(25-C)*(C<25)
Tidy way of doing C<25 then C=25
REPEAT POKE A,3 PAUSE 5
The actual game loop. Draw the bot. Pause to slow the game down a bit. J=STICK(0) B=A+(J=7)-(J=11) B=B+20*((J=13)-(J=14))
Potential new bot position based on joystick input.
IF PEEK(B)=0:POKE A,0:A=B:SOUND 0,99,6,8:SOUND:POKE 77,0:ENDIF
If that position is empty, move the bot to new position and make a little tick sound. Also defeat attract mode.
IF PEEK(B)=4:G=G-1:GG=GG+1
If robot touched a human, there’s one less human waiting to be saved. Increase counter of humans saved on this level.
S=S+L*((A-SC) DIV 20)
Increase score. Higher levels and deeper humans increase score more.
POKE A,0:A=B:POS.0,23:?#6;S;" ":SOUND 0,60,10,8:PAUSE 5:SOUND ENDIF
Erase human, update score display. Make a happy sound. 
IF PEEK(53279)<7:POKE A,2:SOUND 0,99,8,8:PAUSE 10:SOUND:EXIT:ENDIF
Press start to self-destruct. Make a sad sound, draw dead bot. Level over.
IF STRIG(0)=0 AND BM
If player pressed the fire button and has a bomb available...
BM=0
Used up the bomb.
Y=SC+20*((A-SC) DIV 20):
Compute player Y position. 
FOR W=-1 TO 0:
Drawing routine twice: first draw bomb fire then erase it
FOR X=1 TO 18:SOUND 1,50+X,8,8
up to 18 fire characters in either direction, with changing noise
FOR I=0 TO 1
iterate for left and right sides
IF I
don't extend past left edge
B=A-X
player screen position minus offset
J=B>Y:ELSE:B=A+X:J=B<Y+18:ENDIF
don't extend past right edge
IF J
IF PEEK(B)=4:G=G-1:S=S-25*L:POS.0,23:?#6;S;" ":SOUND 0,250,10,15:ENDIF
Aw, you're blowing up a human. There's one fewer guy onscreen. Lose points. Update onscreen score. Boop noise.
ENDIF POKE B,W*-194
draw, erase splody. chr=194, erase=0
ENDIF NEXT I NEXT X NEXT W SOUND ENDIF
Wrap up loops.
IF C<1:WL=WL-1
Time to raise the water level? Raise it.
C=60-5*L
countdown till it rises again. 
C=C+(10-C)*(C<10)
Maximum speed (IF C<10:C=10)
Next, draw water and make water sound:
FOR X=0 TO 18 SOUND 1,36-X*2,8,8 Z=SC+WL*20+X
Reduce guy count if it flooded a guy:
IF PEEK(Z)=4:G=G-1:SOUND 0,200,10,15:POKE Z,69:ENDIF 
IF PEEK(Z)=0:POKE Z,69:ENDIF
Draw flooding over guys and hall (but not walls)
NEXT X SOUND ELSE C=C-1:'tick down the timer ENDIF UNTIL G=0
Keep doing this until no people left onscreen.
IF GG>2 LOOP ENDIF
If 3 or more people saved, move on to next level.
POS.0,23:?#6;S;"   GAME OVER" WHILE STRIG(0):WEND:RUN
Otherwise show Game Over and wait for trigger to play again.
2 notes · View notes
atariaction · 6 years ago
Text
Bouncy: BASIC Tenliners Contest 2019 entry
Tumblr media
My fifth 10-line BASIC contest entry is Bouncy, a throw-the-ball-into-the-goal game loosely based on "Cup" by Jonathan Freidin from the 1979 book "More BASIC Computer Games." I have never actually played Cup, but read the sample game and code in the classic red book many times over as a kid.
The goal of Bouncy is to throw your ball into the target (not a cup, but a line in my version, so totally different.) Use the joystick to adjust the ball's initial speed (from 10 to 50 speed-o-units) and angle (from an almost-level 10 degrees to a skyward 60 degrees.) Press the trigger to throw the ball. If it falls into the goal or bounces in, you win. (Hitting the goal from below doesn't count.) If you miss, the goal remains unmoved: you can adjust your throw to try again.
My friend Mitch helped and helped with the hard math. (The math in this game is a lot more complected than Cup's!) The game is just eight 120-character lines in Turbo BASIC XL on the Atari, so it goes into the PUR-120 contest category.
'BOUNCY by @KevinSavetz 'with massive math help from @pneumaticdeath's math skills 'Jan 7 2019, for the 2019 BASIC 10-line contest W=1:'W is "did we win?" if yes (or 1st time) change goal position XMAX=159:'GR 7 YMAX=92:'95 for full GR.7 screen, we lose a little because text line at top DO GRAPHICS 7+16 DL=DPEEK(741):'location of display list POKE DL+4,66:'change top line to Graphics 0 text line (ANNTIC mode 2) -MOVE DL+102,DL+99,3:'shorten the display list so screen's not too tall 'POKE DL+99,PEEK(DL+102):DPOKE DL+100,DPEEK(DL+103):'another way to do it POKE 752,1:'hide cursor IF W:'if player just won (or first time), place goal in new random position CX=RAND(XMAX-30)+20:'goal x CY=RAND(YMAX-15)+15:'goal y CW=10:'goal width W=0 ENDIF COLOR 1 PLOT CX,CY:DRAWTO CX+CW,CY:'draw goal POKE 87,0:POS.0,0:'draw control interface on the GR.0 part ?"BOUNCY ANGLE: 10 SPEED: 10 AIM " WHILE STRIG(0):'joystick to adjust andle and speed. Trigger to fire. S=STICK(0) AI=AI+((S=14)-(S=13))*5:'up/down to adjust angle VI=VI+((S=7)-(S=11))*5:'left/right to adjust velocity IF AI<10:AI=10:ENDIF:'keep angle and velocity in range IF AI>60:AI=60:ENDIF IF VI<10:VI=10:ENDIF IF VI>50:VI=50:ENDIF POS.15,0:?AI;" " POS.26,0:?VI;" " PAUSE 10 WEND POS.30,0:?" ":'erase AIM POKE 87,7:'get ready to draw in the GR.7 part POKE 77,0:'defeat attract mode 'launch ball! COLOR 2 T=0:'TIME COUNTER LB=0:'LAST BOUNCE TIME DT=.03:'TIME INCREMENT X=1:'INITIAL X Y=10:'INITIAL Y G=12:'GRAVITY E=.6:'ELASTICITY A=AI*.01745:'CONVERT DEGREES TO RADIANS. .01745 IS (3.14159/180) VX=VI*COS(A):'X VELOCITY VY=VI*SIN(-1*A):'Y VELOCITY DO:'move/bounce ball T=T+DT:'time passes... X=X+VX*DT:'increment X Y=Y+VY*DT:'increment Y VY=VY+G*DT:'change velocity IF Y>YMAX:'BALL HIT BOTTOM. CHANGE TRAJECTORY TO BOUNCE IT VY=VY*-E:'adjust speed for bounce DY=Y-YMAX:'switch to upwards movement Y=YMAX-DY*E IF X>=XMAX OR T-LB<1.5:'TINY BOUNCING AT THE END, QUIT EXIT ENDIF LB=T:'LB=TIME OF LAST BOUNCE FOR I=250 TO 50 STEP -6:SO.0,I,10,10:NEXT I:SOUND:'BOUNCE SOUND ENDIF IF X<XMAX AND Y>1:'We already know Y<YMAX because IF above PLOT X,Y:'draw ball if it's onscreen 'Set win flag if ball hit the goal while falling IF X>=CX AND X<=CX+CW AND VY>0 AND (INT(Y)=CY OR INT(Y)=CY-1) W=1 EXIT ENDIF ENDIF LOOP POKE 87,0:POS.30,0:'print win or lose status IF W ?"WIN!" ELSE ?"MISS" ENDIF FOR I=0 TO 15:SOUND 0,50*(3*(NOT W))+50,10,15-I:NEXT I:'DING FOR WIN, BOOP FOR MISS POKE 87,7:'back to playing in GR.7 area PAUSE 200 LOOP
1 note · View note
atariaction · 6 years ago
Text
Garden: BASIC Tenliners Contest 2019 entry
Tumblr media
A quickie, final entry for the 2019 10-liner BASIC contest: GARDEN.
Inspired by arjanvandermeij's #plottertwitter art "8 bits binary flowers," I wanted to create something similar on the Atari 8-bit. I recently learned how to draw ellipses in my work on Renderiffic, my SVG renderer for Atari 8-bit computers, and learned how to rotate shapes from Bruce Artwick’s book Microcomputer Displays, Graphics and Animation. It was easy to combine the two techniques to draw a garden of elliptical flowers.
The program is just a little screensaver that endlessly draws and erases flowers. It’s not a game, so qualifies for the WILD category of the 10-line contest. It’s only four, 120-character lines in Turbo-BASIC XL. Once I get my 1020 plotter back from the fixit guy, I’ll make a version that draws these shapes on paper.
'inspired by @arjanvandermeij's "8 bits binary flowers" 'https://twitter.com/arjanvandermeij/status/1108485237296762880 GRAPHICS 8+16:POKE 710,0 MAXX=319:MAXY=191 W=4:H=12.5 DO FOR YAXIS=40 TO MAXY-W STEP 30 FOR XAXIS=40 TO MAXX-H STEP 30 IF(RAND(10)=0) X=XAXIS:Y=YAXIS X1=X+W:Y1=Y+H COLOR 0 FOR YY=YAXIS-H TO YAXIS+H PLOT XAXIS-H,YY DRAWTO XAXIS+H,YY NEXT YY COLOR 1 FOR ANGLE=0 TO 157.5 STEP 22.5 IF (RAND(2)=0) RADANG=ANGLE*.01745:'CONVERT DEGREES TO RADIANS FOR A = 0 TO 6.28318 STEP 2/H X1=X+COS(A)*W Y1=Y+SIN(A)*H 'Rotation code from Bruce Artwick's book 'Microcomputer Displays, Graphics and Animation ROTX=XAXIS+((X1-XAXIS)*COS(RADANG)-(Y1-YAXIS)*SIN(RADANG)) ROTY=YAXIS+((X1-XAXIS)*SIN(RADANG)+(Y1-YAXIS)*COS(RADANG)) IF (A=0) PLOT ROTX,ROTY IX=ROTX:IY=ROTY ELSE DRAWTO ROTX,ROTY ENDIF NEXT A DRAWTO IX,IY ENDIF NEXT ANGLE ENDIF NEXT XAXIS NEXT YAXIS LOOP
0 notes
atariaction · 6 years ago
Text
Mini Character Editor: BASIC Tenliners Contest 2019 entry
Tumblr media
One of the great features of the Atari computers was the ability to redefine the character set. Normally, the character set — the collection of letters, numbers, punctuation, and special symbols that the computer can display — is pulled from ROM, where it can’t be changed. But the Atari had the ability to look elsewhere in memory for the character set. Using that feature, you could create customized characters, put them in RAM, then tell the computer to use your custom character set. With that, you might change the standard letter A into a fancy script A, or into a little spaceship.
Back in the day most of us used Atari BASIC, and you could tell when a game was going to use a custom character set: PLEASE WAIT. When that message appeared, it would mean a delay of 30 to 40 seconds while the program copied the character set from ROM to RAM. Actually installing custom characters was very fast; the slow-verhead was in BASIC copying the whole set around memory. If a programmer was sophisticated enough to write a machine language subroutine, the same job could be done in a fraction of a second. I certainly wasn’t, and apparently neither were most of the programmers who had type-in games published in Compute!, Antic, and other computer magazines.
Happily, TurboBASIC XL has a memory move command, which does same work with the speed of machine language, removing the interminable wait to copy characters around.
Here’s how I set up a custom character set in another program I wrote, Poke Pig:
CH=(PEEK(106)-16)*256:’Define a chunk of RAM under the “top” of BASIC’s memory space. This is enough space to hold the character set. The memory location of the start of that space is put into variable CH.
MOVE 57344,CH,1024:’Copy the character set from its location in ROM (it starts at 57344 and is 1024 bytes) to the space we set aside in RAM. This is the part that used to take 30-40 seconds.
DIM F$(8):’This program only defines one special character, which will replace the # character. We’ll put the data for this character in F$. We need 8 bytes for that character data. Changing two characters would take 16 bytes, and so on.
F$="\E7\DB\81\42\99\99\42\3C":'Here’s the data for the new # character. Here it’s a bunch of hex numbers. In the listing that will be represented by a mess of eight ATASCII characters. The Mini Character Editor program generates these hex numbers (and the ATASCII version) based on your drawing.
MOVE ADR(F$),CH+24,8:’Copy the custom character, in F$, which is 8 bytes, replacing the # character, which is located at CH+24.
POKE 756,CH/256:’Tell the computer to start using our copy of the character set instead of the official ROM version.
So, that mess of hex codes in F$. Each hex number represents one row in the eight lines of a character. Normally I would draw the 8x8 character on graph paper, then convert each row to its binary number, then convert that number to its hex or ATASCII equivalent.
The Mini Character Editor program lets you draw a character using the joystick, see it instantly in the Atari’s five graphics modes (BASIC modes 0,1, 2, 4 and 5), and see the hex code and ATASCII string so you can install that graphic in your own program.
In addition to drawing with the joystick, there are four keyboard commands for manipulating the graphic: H for horizontal flip, V for vertical flip, D to move everything down one line, R to move everything right one space.
When you’re ready to install the graphic in your own program, copy down the hex numbers by hand (there are only 8 of them!) or BREAK out the program and type_ ?A$_ to get the ATASCII version to export into your program. 
Mini Character Editor fits in ten 120-character lines. Because it is not a game, i qualifies for the WILD category of the 10-line BASIC contest. I think it’s my first program to use a custom display list, which I (re?)learned about from the book The Creative Atari.
Here's the code:
'mini character editor 'Feb 3 2019 by @KevinSavetz 'use joystick to design a character set character 'H=horizontal flip, V=vertical flip 'D=move everything down, R=move everything right DIM F$(8),F(9) 'F in the main container for the data of the drawn character. 'F$ contains the data in string format GR.3:POKE 752,1 'start with BASIC mode 3, but we'll tweak that later. Turn off cursor. CH=(PEEK(106)-16)*256 'space for custom character set SC=DPEEK(88) 'top of screen RAM 'set up display list DL=DPEEK(741):'display list POKE DL+16,4:'MODE 4 @ SC+100 POKE DL+17,5:'MODE 5 @ SC+140 POKE DL+18,6:'MODE 6(BASIC MODE 1) @ SC+180 DPOKE DL+19,1799:'2 LINES OF MODE 7(BASIC MODE 2) @ SC+200 & SC+220 DPOKE DL+21,514:'2 LINES OF MODE 2(BASIC MODE 0) @ SC+240 & SC+280 POKE DL+23,0:'skip a line POKE DL+24,2:'2 LINES OF MODE 2(BASIC MODE 0) @ SC+320 & SC+360 FOR I=25 TO 31:POKE DL+I,0:NEXT I:'many blank lines 'print ! characters in the various screen modes FOR I=SC+100 TO SC+280 STEP 40 POKE I,1:POKE I+3,1:POKE I+4,1 NEXT I 'and some more in the text window ?"! ! !! !!!" ?" ! !! !!!" 'install RAM character set MOVE 57344,CH,1024 'replace ! with our custom character MOVE ADR(F$),CH+8,8:POKE 756,CH/256 'draw box around editing window COLOR 3:PLOT 0,0:DRAWTO 9,0:DRAWTO 9,9:DRAWTO 0,9:DRAWTO 0,0 X=1:Y=1 'main loop DO IF R<0:'re-draw contents of editing window FOR J = 1 TO 8:'for each row in the byte... FOR I = 1 TO 8:'look at each bit... COLOR SGN(F(J) & (2^((9-I)-1))) 'set color to 1 if the bit is set, 0 if not PLOT I,J:'draw the bit NEXT I NEXT J ENDIF IF R:'if R<>0, update hex/ATASCII display POKE $57,0:'prepare to print in text window ?CHR$(156);:'clear the text line FOR I=1 TO 8 F$(I,I)=CHR$(F(I)):'copy the data to F$ ?"\";HEX$(F(I));:'show the 8 bytes as hex NEXT I:?" "; FOR I=1 TO 8:'show the 8 bytes as ATASCII IF F(I)<>155 ?CHR$(27);CHR$(F(I));:'normal case ELSE ?" ";:'if character is CR (27) show space instead. CR messes display. ENDIF NEXT I POKE $57,3:'back to drawing in GR.3 MOVE ADR(F$),CH+8,8:'copy the new character to the active character set ENDIF R=0:'redraw defaults to off COLOR SGN(F(Y) & (2^((9-X)-1))): PLOT X,Y:'draw current bit S=STICK(0):'get joystick position Y=Y+((S=13)-(S=14)):'move up/down? X=X+(S=7)-(S=11):'move left/right? IF X<1:X=8:ENDIF:'stay in bounds of the drawning box IF Y<1:Y=8:ENDIF IF X>8:X=1:ENDIF IF Y>8:Y=1:ENDIF P=PEEK(764):'was a key pressed? IF (P=58):'d to move everything down FOR J=9 TO 1 STEP -1:'for each byte F(J)=F(J-1):'copy every byte to next byte. F(9) is temp storage only. NEXT J F(1)=F(9):'move bottom line to top R=-1:'put in order for full redraw ENDIF IF (P=40):'r to move everything right FOR J=1 TO 8:'for each byte Q=F(J) & 1:'copy rightmost bit (LSB) to temporary storage Q F(J)=TRUNC(F(J)/2):'divide byte by 2 to shift bits right F(J)= F(J) + 128*Q:'copy old rightmost bit to leftmost bit NEXT J R=-1:'put in order for full redraw ENDIF IF (P=57):'h for horizontal flip FOR J=1 TO 8:'for each byte Q=0:'working byte FOR I=1 TO 8:'for each bit in the byte Q=Q+(SGN (F(J) & (2^(I-1))) * 2^((9-I)-1)) 'add to working byte: ' SGN [make 0 or 1] ( ' (the current row bitwise-and ' the value of the current bit (1,2,4,8,16...))) ' * the value of the opposite bit (128,64,16,8,4...) 'So: if the 1 bit is on, add 128 to the working byte, 'if the 2 bit is on, add 64 to the working byte, and so on. 'This was not easy to figure out, nor to figure out all over 'again the next day to write these comments NEXT I F(J)=Q:'install reversed byte NEXT J R=-1:'put in order for full redraw ENDIF IF (P=16):'v for vertical flip FOR J=1 TO 4:'for bytes 1 to 4 Q=F(J):'temp copy of byte F(J)=F(9-J):'copy 8 to 1, 7 to 2, 6 to 3, 5 to 4 F(9-J)=Q:'copy 1 to 8, 2 to 7, 3 to 6, 4 to 5 NEXT J R=-1:'put in order for full redraw ENDIF ' there was no room for this, but might be fun to add ' IF (PEEK(764)=45):'t to turn (rotate) ' ENDIF POKE 764,255:'clear keyboard buffer IF(STRIG(0)=0):'if trigger is pressed F(Y) = F(Y) EXOR (2^((9-X)-1)):'toggle current bit R=1:'only redraw hex/atascii PAUSE 4:'slow things down a tad ENDIF COLOR 2:PLOT X,Y:'show cursor PAUSE 4 LOOP
0 notes
atariaction · 8 years ago
Text
DESCEND: BASIC Tenliners Contest 2017 entry
It's my favorite time of year — the 10-line BASIC programming contest. My first entry for 2017 is DESCEND, a port of my assembly language game Kaverns of Kfest. Your job is to descend into the cave collecting gems, without hitting the walls. As usual, I did this project in Turbo BASIC XL on the Atari 8-bit.
Tumblr media
Here’s the code:
0 REM DESCEND BY KEVIN SAVETZ 1 REM 2017 BASIC 10-LINER CONTEST 2 REM A PORT OF KAVERNS OF KFEST 3 ------------------------------ 5 GRAPHICS 0:DL=DPEEK(560):POKE DL+3,68:FOR I=DL+6 TO DL+25:POKE I,4:NEXT I:I=I+3:POKE I,65:DPOKE I+1,DL 10 DIM F$(24),W$(38),B$(8):F$="(mess of ATASCII)":PX=20:PY=1:POKE 752,1:W$="(mess of ATASCII)" 15 B$="(mess of ATASCII)":POSITION 0,21:? "DEPTH":POSITION 17,21:? "SHIELDS 10":POSITION 35,21:? "GEMS 0" 20 CH=(PEEK(106)-16)*256:MOVE 57344,CH,1024:MOVE ADR(F$),CH+8,24:POKE 756,CH/256:SC=DPEEK(88):LW=15:CW=8:SS=10:WHILE SS 40   MOVE ADR(W$),SC+800,LW:MOVE ADR(B$),SC+800+LW,CW:MOVE ADR(W$),SC+800+LW+CW,40-LW-CW:POKE SC+800+RAND(40),3 50   POKE SC+800+RAND(40),4:X=RAND(3):LW=LW+X-1:IF LW<1:LW=1:ENDIF :IF LW>32:LW=32:ENDIF :PX=PX+(STICK(0)=7)-(STICK(0)=11) 65   IF PX<1:PX=1:ENDIF :IF PX>38:PX=38:ENDIF :Q=PEEK(SC+PX+PY*40):IF Q=4:SOUND 0,50,10,8:G=G+1:POSITION 36,22:? G:ELSE 70     IF Q>0:SS=SS-1:POSITION 20,22:? SS;" ":SOUND 0,RAND(100)+100,8,8:ENDIF :IF Q=0:SOUND :ENDIF :ENDIF 80   POKE SC+PX+PY*40,2:FOR I=0 TO 19:MOVE SC+40+40*I,SC+40*I,40:NEXT I:L=L+1:IF L=20 AND CW>3:CW=CW-1:ENDIF :IF L=40 AND PY<17:PY=PY+1 90     L=0:POKE 708,RAND(200)+4:ENDIF :LL=LL+1:POSITION 1,22:? LL:WEND :POSITION 16,23:? "GAME OVER";:SOUND :WHILE STRIG(0):WEND :RUN
Here's a breakdown of the code:
0 REM DESCEND BY KEVIN SAVETZ 1 REM 2017 BASIC 10-LINER CONTEST 2 REM A PORT OF KAVERNS OF KFEST 3 ------------------------------ 5 GRAPHICS 0:
This game uses ANTIC mode 4, the 4-color text mode. Start in graphics mode 0, then we'll tweak the display list to use mode 4.
DL=DPEEK(560)
Find the top of the display list.
POKE DL+3,68:FOR I=DL+6 TO DL+25:POKE I,4:NEXT I:I=I+3:POKE I,65:DPOKE I+1,DL
Change most of the lines (excepting the bottom 3, which will be score dispaly) to mode 4. Everything you need to know about what's doing on here is in this article by Orson Scott Card. 
Setting up to use mode 4 costs an entire line of BASIC, pretty expensive in a 10-line program. More, really, because you pretty much need to use a custom character set with mode 4.
10 DIM F$(24),W$(38),B$(8):F$="(mess of ATASCII)":PX=20:PY=1:POKE 752,1:W$="(more ATASCII)"
F$ is the data for three custom characters used in the character set: the walls, the player's ship, and the random rocks/barriers. The gems are their own character, which I don't actually set. By not setting them, they display some regular character set character, which looks kind of speckly and cool and gem-like in ANTIC mode 4.
PX is the player's X position. PY is player's Y position. Unlike Kaverns of Kfest, this game doesn't allow the player to control the Y; instead, you descend automatically, increasing difficulty.
W$ is characters for the wall.
POKE 752,1 turns off the cursor.
15 B$="(shorter mess of ATASCII)"
B$ is characters for the blank space where the ship goes.
:POSITION 0,21:? "DEPTH":POSITION 17,21:? "SHIELDS10":POSITION 35,21:? "GEMS0"
Print score headers and starting scores.
20 CH=(PEEK(106)-16)*256
Find space for the custom character set.
:MOVE 57344,CH,1024
Copy the ROM character set to the RAM space reserved for our custom set.
:MOVE ADR(F$),CH+8,24
Replace 3 characters with custom characters.
:POKE 756,CH/256
Switch from the ROM character set to our custom character set.
:SC=DPEEK(88)
Find the top of screen memory.
:LW=15:CW=8:SS=10
LW is left wall width. CW is center (play area) width. SS is number of shields (basically, lives.)
:WHILE SS
Here's the main game loop. As long as you still have at least one shield...
40   MOVE ADR(W$),SC+800,LW
Build new section of wall-center-wall. This always goes at the bottom of the playfield and is pushed up later by the scroll routine.
First, the left wall. Copy LW (left wall width) characters of wall to the new line, at SC+800, that is, on the left edge 20 lines down.
:MOVE ADR(B$),SC+800+LW,CW
Now, copy CW (center width) characters of blank space to the right of the wall.
:MOVE ADR(W$),SC+800+LW+CW,40-LW-CW
Fill the rest of the line with wall.
:POKE SC+800+RAND(40),3
Each line gets a barrier (blue block) in a random place.
50   POKE SC+800+RAND(40),4
Each line also gets gems in a random place. Might be in the center where you can get 'em, but probably not.
:X=RAND(3):LW=LW+X-1
Adjust the width of the left wall with every move. It can be one less, one more, or stay the same.
:IF LW<1:LW=1:ENDIF :IF LW>32:LW=32:ENDIF
But don't let the width go off either side of the screen.
:PX=PX+(STICK(0)=7)-(STICK(0)=11)
Change PX + or - 1 based on left-rightness of joystick.
65   IF PX<1:PX=1:ENDIF :IF PX>38:PX=38:ENDIF
But don't let player move off the edges of the screen.
:Q=PEEK(SC+PX+PY*40):
Look at the space where the player is about to move to.
IF Q=4:SOUND 0,50,10,8:G=G+1:POSITION 36,22:? G:ELSE
It's a gem! Make a happy noise, increase count of gems collected, update that tally.
70     IF Q>0:SS=SS-1:POSITION 20,22:? SS;" ":SOUND 0,RAND(100)+100,8,8:ENDIF
If you're about to touch literally anything else: lose a shield, update the shield tally, play a bad sound.
:IF Q=0:SOUND :ENDIF :ENDIF
But if you're not touching anything, turn off sound, in case it's on from the last move.
80   POKE SC+PX+PY*40,2
Draw the player in the new position.
:FOR I=0 TO 19:MOVE SC+40+40*I,SC+40*I,40:NEXT I
This is the scroll. Copy the second screen line to the first, third to the second, and so on.
:L=L+1
L is a temporary counter that counts every 40 levels.
IF L=20 AND CW>3:CW=CW-1:ENDIF
Every time L hits 20, make the center width one less, but don't let it get too narrow.
:IF L=40 AND PY<17:PY=PY+1
Every line L hits 40, move the ship down one line, but not too low...
90     L=0
and restart the count-to-40 counter...
:POKE 708,RAND(200)+4:ENDIF
and change the wall color because that's fun.
:LL=LL+1:POSITION 1,22:? LL
LL is the total number of levels you've descended.
:WEND
End of main game loop. Once we go past this, we must be out of shields.
:POSITION 16,23:? "GAME OVER";:SOUND
Print game over, turn off sound.
:WHILE STRIG(0):WEND :RUN
Wait for joystick button to be pressed then play again.
This wasn't too bad to compress into 10 lines, I had just enough space to do everything I wanted to do. I didn't feel the need to use tbxl-parser to compress things, just did it by hand. I could have - but didn't need to - compress things further by using more 1-character variable names and 1-digit line numbers.
10 notes · View notes
atariaction · 6 years ago
Text
MINILIFE: BASIC Tenliners Contest 2019 entry
Tumblr media
Back to my personal theme for 10-liner entries — classic BASIC algorithms. It’s hard to get more classic than Conway’s Game of Life. This simple game/simulation was covered so times from many perspectives in Byte Magazine, Creative Computing, and so on. I used the algorithm as described by Mark D. Niemiec in the January 1979 issue of Byte for my 10-liner.
My program lets you edit the starting playfield configuration, run the simulation, then optionally stop the sim to edit the playfield before continuing. At 80 characters per line, this program would fit in PUR-80, the most restrictive contest category. But after writing it I learned that the contest rules say that the PUR-80 category is limited to versions of BASIC that ship with the computer — e.g. Atari BASIC for the Atari 8-bit line. Since I wrote MINILIFE in TurboBASIC XL, and can’t convert it to Atari BASIC without making it significantly longer, I will submit it to the PUR-120 category. Boo.
GR.3 HY=10:'MAX 19 - playfield height HX=20:'MAX 39 - playfield width. Bigger playfield makes it slower. DIM OLD(HY+1,HX+1),NW(HY+1,HX+1):'arrays for old and new playfield 'draw bounding box COLOR 3:PLOT 0,0:DRAWTO HX+1,0:DRAWTO HX+1,HY+1:DRAWTO 0,HY+1:DRAWTO 0,0 ?"MINILIFE" 'Edit cells with joystick. DO X=1:Y=1:?"Edit mode. Place cells then SPACE." POKE 764,255:'clear keyboard buffer WHILE PEEK(764)<>33:'until SPACE is pressed... COLOR NW(Y,X):PLOT X,Y:'show cell in current position S=STICK(0) Y=Y+((S=13)-(S=14)):'move up/down X=X+(S=7)-(S=11):'move left/right IF X<1:X=HX:ENDIF:'stay in bounds IF Y<1:Y=HY:ENDIF IF X>HX:X=1:ENDIF IF Y>HY:Y=1:ENDIF IF(STRIG(0)=0) NW(Y,X)=NOT NW(Y,X):'toggle cell on/off PAUSE 3 ENDIF COLOR 2:PLOT X,Y:'show cursor PAUSE 4 WEND 'now run the sim IT=0:?"Generating life. SPACE to stop." POKE 764,255 DO 'draw the current colony FOR Y = 1 TO HY FOR X = 1 TO HX COLOR 3:PLOT X,Y OLD(Y,X)=NW(Y,X) COLOR OLD(Y,X) PLOT X,Y NEXT X NEXT Y IF PEEK(764)=33:EXIT:ENDIF:'SPACE = back to editor 'calculate the next generation. Read the Byte article :) FOR Y = 1 TO HY FOR X = 1 TO HX SUM=OLD(Y-1,X-1)+OLD(Y-1,X)+OLD(Y-1,X+1)+OLD(Y,X-1)+OLD(Y,X+1)+OLD(Y+1,X-1)+OLD(Y+1,X)+OLD(Y+1,X+1) IF SUM=3 NW(Y,X)=1 ELSE IF SUM=2 NW(Y,X)=OLD(Y,X) ELSE NW(Y,X)=0 ENDIF ENDIF NEXT X NEXT Y IT=IT+1:?IT:'iteration counter LOOP LOOP
0 notes
atariaction · 8 years ago
Text
DESCEND update
After I submitted the DESCEND game for the 2017 10-line BASIC programming contest, AtariAge forum user vitoco took it upon himself to improve the game. He made it significantly smaller and used a single MOVE to scroll the screen rather than my many MOVES in a FOR-NEXT loop.
That change is so, so obvious — now. Having first programmed this game in assembly language, I was thinking like an assembly language programmer. But it’s much easier to move larger blocks of memory in TurboBASIC XL. As a result, the game is smoother and faster.
Too fast. Vitoco added a hard-coded PAUSE command to slow it down, but suggested that I tweak it so the game gets faster as you play. Which I did. I make some other changes, too: I didn’t know before that you could get to ANTIC mode 4 easily by just using the command GRAPHICS 12 instead of complicated display list hand-tweaking. I’m now using the Atari’s “official” text window instead of my home-brew one, which means I can position text using POKE 656 and 657 — but I do both at once with DPOKE 656 which is kind of elegant and takes up less space than the POSITION command did.
The new version is faster, harder, smoother, and now qualifies in the 80-character-per-line category instead of the 120-character category it was in before. 
1 note · View note
atariaction · 9 years ago
Text
FORTKNOX: BASIC Tenliners Contest 2016 entry
My second entry in the 2016 10-line BASIC program contest is FORTKNOX, in which you steal treasure away from robot guards.
Tumblr media
Move the joystick to collect the diamonds, avoiding the robot guards. When your timer runs out, the game ends. Touching a guard decreases your timer dramatically; getting a diamond increases it a little. Your final score is the maximum amount the timer attained during the game. There are 9 levels: as they increase, the guards do more damage (decreasing your time more dramatically) and there are fewer prizes to increase your time.
I was having a lot of trouble with TurboBasic XL's tokenizer on very long lines - for both this program and CABBAGE before it. This isn't a problem I remember having in previous years of doing this contest. If I understand it correctly, TBXL can choke on very compacted, but long program lines. Even though a line is under the limit of 120 characters, if the number of tokens it takes to store that line exceeds some internal limit, TBXL freaks out with a crash or by scrambling the program in memory. I mentioned this program on the AtariAge forum, and someone pointed me to TurboBasic XL parser tool, a program (which runs on a modern computer) that parses and tokenizes TBXL programs. There wasn't a Mac version, so someone made a binary for me. (The Atari community is pretty incredible.) So I was able to write this program in BBEDIT, let TurboBasic XL parser tool create the tokenized BAS file, and import that into Atari800MacX for testing.
Not only does this program let me avoid the TBXL tokenizing bug, it produces more compact BASIC programs than I've been able to (making smart use of abbreviations, for instance), allowing me to squeeze in more features than I'd be able to with it, and taking away the tedious task of compressing programs by hand.
UPDATE: Turns out that the parse tool can create extra-long BASIC lines (up to 256 characters) and does so by default -- so I accidently made this game with 256-line characters instead of the usual 120-character limitation. Which is fine, it just puts the game in a different category for the contest. It also explains why I was able to pack in so much, so easily. Next time I'll know to use the -s option to force shorter BASIC lines. If I so choose :)
Here's FORTKNOX, the 10-line version created by the parser tool:
0 DIM L(4),M(4),F$(48):FOR X=1 TO 5:L(X-1)=20*X+X:NEXT X:Q=100:LV=1:GRAPHICS 18:SC=DPEEK(88):CH=(PEEK(106)-16)*256:POKE 711,28:POKE 709,12:POKE 708,88 1 F$="{...}":MOVE 57344,CH,1024:MOVE ADR(F$),CH+8,40:POKE 756,CH/256 10 G=0:FOR X=0 TO 239:POKE SC+X,0:NEXT X:POKE 710,40-2*LV:FOR X=1 TO 10:POKE SC+X*20,131:POKE SC+X*20+19,131:NEXT X:FOR X=2 TO 19:POKE SC+X,131:POKE SC+20*11+X,131:NEXT X:P=218:POKE P+SC,66 11 POSITION 0,0:PRINT #6;"L";LV:POKE SC+220,69:IF LV>4:XX=10-LV:ELSE :XX=50-10*LV:ENDIF :FOR X=1 TO XX:Z=RAND(198)+20:IF PEEK(SC+Z)=0:POKE SC+Z,196:ELSE :X=X-1:ENDIF :NEXT X:FOR X=0 TO 4:M(X)=PEEK(SC+L(X)):NEXT X 35 FOR I=0 TO 4:IF L(I)=P AND PEEK(712)=0:POKE 712,28:Q=Q-100*LV:SOUND 0,20,2,8:IF M(I):G=G+1:ENDIF :ENDIF :NEXT I:POKE 712,0:SOUND :FOR I=0 TO 4:IF L(I)<38-I+I*20:N=L(I)+1:ELSE 36     IF L(I)>201+I-I*20:N=L(I)-1:ELSE :IF L(I)&1=I&1:N=L(I)+20:ELSE :N=L(I)-20:ENDIF :ENDIF :ENDIF :ENDIF :POKE SC+L(I),M(I):M(I)=PEEK(SC+N):IF M(I)=66:M(I)=0:ENDIF :POKE SC+N,1:L(I)=N:IF N=P:POKE 712,28:Q=Q-100*LV 37   SOUND 0,20,2,8:ENDIF :NEXT I:S=STICK(0):IF S=15:PM=0:ENDIF :IF S=7:PM=1:ENDIF :IF S=11:PM=-1:ENDIF :IF S=13:PM=20:ENDIF :IF S=14:PM=-20:ENDIF 38 IF (P+PM) MOD 20=0 OR (P+PM+1) MOD 20=0 OR P+PM<21 OR P+PM>218:PM=0:ENDIF :POKE P+SC,0:P=P+PM:IF PEEK(P+SC)=196:Q=Q+50:G=G+1:SOUND 0,60,10,10:ENDIF :POKE P+SC,66:IF G=XX:LV=LV+1:IF LV=10:IF T<Q 39       T=Q:ENDIF :SOUND :POSITION 7,4:PRINT #6;"YOU WIN":POSITION 1,5:PRINT #6;"END SCORE ";Q:POSITION 1,6:PRINT #6;"MAX SCORE ";T:WHILE STRIG(0):WEND :CLR :RUN :ELSE :GOTO 10:ENDIF :ENDIF :Q=Q-0.6:IF T<Q:T=Q:ENDIF :POSITION 1,11:PRINT #6;Q;"...." 40 IF Q<=0:SOUND :POSITION 3,4:PRINT #6;"% GAME OVER %":POSITION 1,5:PRINT #6;"MAX SCORE ";T:POSITION 1,6:PRINT #6;"FIRE TO PLAY AGAIN":WHILE STRIG(0):WEND :CLR :RUN :ENDIF :GOTO 35
Below is the same program, using the "pretty printed expanded listing" option, and with my notes.
dim L( 4 ), M( 4 ), F$( 48 ) L is the location of the 5 robot guards. M is the memory of whether there is a diamond under where each guard is standing. F$ is the custom character set,
for X = 1 to 5 L( X - 1 ) = 20 * X + X next X
Set the starting location for the five guards. Line them up in a nice diagonal.
Q = 100
Q is the timer. Start at 100 time units.
LV = 1 LV is level, starts at 1.
graphics 18 SC = dpeek( 88 ) CH = ( peek( 106 ) - 16 ) * 256 Set the graphics mode. Put the top of screen memory in SC. Find some space for the custom character set, put that in CH.
poke 711, 28 poke 709, 12 poke 708, 88
Set the color of the diamonds, player, and robots.  
F$ = "{mess of ATASCII}" move 57344, CH, 1024 move adr( F$ ), CH + 8, 40 poke 756, CH / 256 Copy the character set to RAM at the space saved for it, CH. Replace 5 of them with our custom graphics. Switch to the custom character set.
I borrowed the graphics for the wall, player, and diamond from Bill Kendrick's 10-line game MINIDASH. My 8-year-old daughter designed the robot guard on graph paper. I did the hourglass.
10 G = 0
One of just two cases where I specify an explicit line number for the parser, because we jump here at the start of each new level.
G is the number of diamonds we've collected (Got) on the current level.
for X = 0 to 239 poke SC + X, 0 next X Clear the screen at the start of each level. Didn't have to do this, but I like the effect.
poke 710, 40 - 2 * LV Wall color changes depending on the level.
for X = 1 to 10 poke SC + X * 20, 131 poke SC + X * 20 + 19, 131 next X for X = 2 to 19 poke SC + X, 131 poke SC + 20 * 11 + X, 131 next X Draw the brick walls.
P = 218 poke P + SC, 66 Player starts in the bottom right corner. Draw him in.
position 0, 0 print #6; "L"; LV
Print level number in the upper corner.
poke SC + 220, 69
Timer icon in the bottom left. if LV > 4 XX = 10 - LV else XX = 50 - 10 * LV endif XX is the number of diamods to collect, which decreases on each level.
for X = 1 to XX Z = rand( 198 ) + 20 if peek( SC + Z ) = 0 poke SC + Z, 196 else X = X - 1 endif next X Choose places for the diamonds. Don't put two on the same spot. for X = 0 to 4 M( X ) = peek( SC + L( X ) ) next X If there's a diamond on a robot stating position, we need to know that. M is "memory" of what each robot is standing on. It will either be 0 (nothing) or 196 (a diamond.) 35
Here we go with the main loop of the game, at 35, the other explicitly designated line number.
for I = 0 to 4 if L( I ) = P and peek( 712 ) = 0 poke 712, 28 Q = Q - 100 * LV sound 0, 20, 2, 8 if M( I ) G = G + 1 endif endif next I Check whether each robot shares the player's position. If so, show a warning color, knock off points (increasing per level), play a nasty sound. If that happens on a place where there's also a diamond, you get credit for collecting it, but no points because reasons.
Don't take away points if PEEK(712) isn't 0: this prevents penalizing the player twice for the same guard hit, because we do this check again later.
poke 712, 0 sound Turn off the warning color and nasty sound.
for I = 0 to 4 if L( I ) < 38 - I + I * 20 N = L( I ) + 1 else if L( I ) > 201 + I - I * 20 N = L( I ) - 1 else if L( I ) & 1 = I & 1 N = L( I ) + 20 else N = L( I ) - 20 endif endif endif endif This mess of ifs determines the robots' clockwise movement. N is the robot's New location. This is the first time I've written a program that keeps trak of things based on their location in screen memory rather than X and Y coordinates. I kind of like it — just one number of keep track of, and easier to manipulate on screen. For this graphics mode, +20 moves a character down one line, -20 up one line. poke SC + L( I ), M( I ) Erase the guard's old position, replacing it with what's in it's memory of what was there before.
M( I ) = peek( SC + N ) if M( I ) = 66 M( I ) = 0 endif
Create new memory of where it's about to move to. E.g. Is there a diamond there? But not if it's the player.
poke SC + N, 1 L( I ) = N Draw the robot's new location, and remember it in L.
if N = P poke 712, 28 Q = Q - 100 * LV sound 0, 20, 2, 8 endif If the robot and the player share the same position, color, points, buzz again. I found it necessary to do the check before and after the robot moves, or before and after the player moves, which is basically the same thing.
next I
Guards are done moving, now it's the player's turn.
if S = 15 PM = 0 poke P + SC, 66 else
Player isn't moving. Just redraw him to be safe. Otherwise...
if S = 7 PM = 1 endif if S = 11 PM = -1 endif if S = 13 PM = 20 endif if S = 14 PM = -20 endif Inelegant way of setting the player's intended relative position based on joystick position. (I couldn't think of an elegant way.)
if ( P + PM ) mod 20 = 0 or ( P + PM + 1 ) mod 20 = 0 or P + PM < 21 or P + PM > 218 PM = 0 endif An elegant way of keeping the player in bounds (I couldn't think of an inelegant way.)
poke P + SC, 0 P = P + PM Erase the player, move him to his new location.
if peek( P + SC ) = 196 Q = Q + 50 G = G + 1 sound 0, 60, 10, 10 endif
If new player position has a diamond, give points, count one more Gotten diamond, play a nice sound.
poke P + SC, 66 Draw the player in the new position.
if G = XX LV = LV + 1
Did we collect them all? Increase the level by one.
if LV = 10 if T < Q T = Q endif sound position 7, 4 print #6; "YOU WIN" position 1, 5 print #6; "END SCORE "; Q position 1, 6 print #6; "MAX SCORE "; T while strig( 0 ) wend clr run else goto 10 endif endif endif
Did we finish level 9? Then the game's over. Update Top score (T) if needed, print winning message and score. Wait for trigger to play again. This (and the corresponding version for end of game without winning, below) was the last thing I added to the program. Before I just dumped to graphics 0 to print end of game messages, but the basic parsing tool saved me enough space to squeeze in this pretty version and replay-ability with the trigger. Q = Q - 0.6 if T < Q T = Q endif position 1, 11 print #6; Q; "\A3\A3\A3\A3" The game isn't over. Decrease the timer by .6 (I think seeing the decimals fly by on the timer makes it seem more frantic.) Print the timer with some brick characters after to overwrite the old numbers.
if Q <= 0 sound position 3, 4 print #6; "% GAME OVER %" position 1, 5 print #6; "MAX SCORE "; T position 1, 6 print #6; "FIRE TO PLAY AGAIN" while strig( 0 ) wend clr run endif The timer has run out, print game over message and score. Trigger restarts. CLR:RUN takes less space than resetting the level to 1, timer to 100.
goto 35
Game's still in progress, continue main loop.
3 notes · View notes