#turbobasicxl atari
Explore tagged Tumblr posts
Text
Garden: BASIC Tenliners Contest 2019 entry

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
Text
MINILIFE: BASIC Tenliners Contest 2019 entry
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
Text
Poke Pig: BASIC Tenliners Contest 2019 entry

My third grade teacher hated me and told my mom that I would grow up to be a serial killer. (This turned out to be inaccurate.) She also taught me the dice game “Pig.” In our class, the teacher would roll two dice again and again. Students would add each dice roll to their score, and could quit at any time. But if the teacher rolled snake eyes, the game was over, and any students still playing were out with zero points.
My second 10-line BASIC contest entry is loosely based on the Pig game. It is a ridiculous self-modifying program — instead of rolling dice, it pokes random numbers into random memory locations owned by BASIC. The player can choose how many random memory locations to POKE for points. The player wins if they quit before the game crashes.
I doubt the judges will like it, but I think it's hilarious. It fits into the Pure-120 character category.
MULT=1:'multplier increases for higher score offer as game progresses DIM A(7),F$(8) F$="\E7\DB\81\42\99\99\42\3C":'piggy face character A(4)=50:A(5)=100:A(6)=250:'number of POKE choices 'instruction screen GR.0 ?"POKE PIG" ?"Choose how many random memory" ?"locations to POKE for points." ?"You win if you quit before" ?"the game crashes. If it crashes," ?"you lose.":?:?"Press trigger." WHILE STRIG(0):WEND 'setup screen GR.2:POKE 710,0:POKE 708,$4A 'move character to RAM so it'll get mangled CH=(PEEK(106)-16)*256:MOVE 57344,CH,1024 'install custom pig face charcter MOVE ADR(F$),CH+24,8:POKE 756,CH/256 LM=DPEEK(128):'lomem MT=DPEEK(741):'memtop. We're going to only poke memory owned by BASIC. Staying out of page zero, the display list, etc. DO POS.0,0 ?#6;" # poke pig #" ?#6;"YOU HAVE ";S;" POINTS" POS.0,3 ?#6;"CHOOSE:" FOR D=4 TO 6 ?#6;" ";A(D);" POKES +";INT((A(D)*D*MULT)/2);"PTS" NEXT D ?#6;" OR...QUIT NOW" PAUSE 20 D=4 'choose item from menu WHILE STRIG(0) POS.0,D:?#6;" " D=D+((STICK(0)=13)-(STICK(0)=14)) IFD<4:D=4:ENDIF IFD>7:D=7:ENDIF POS.0,D:?#6;">" PAUSE 5 WEND 'chose Quit IF A(D)=0 POS.0,8 ?#6;"YOU WIN WITH ":?#6;S;" POINTS!" IF S ?"Coldstart now. Really." ELSE ?"Wimp." ENDIF END ENDIF 'choose to POKE. MAX=A(D) FOR X=1 TO MAX POSITION 8,9 ?#6;MAX-X;" " POKE RAND(MT-LM)+LM,RAND(256) Y=50-X*2 IF Y>0 PAUSE Y:'speeding up as it works is fun ENDIF SOUND 0,99,10,10 PAUSE 2 SOUND NEXT X S=S+INT((A(D)*D*MULT)/2) MULT=MULT*1.25:'next points offer is higher LOOP
0 notes
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.
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
Text
CABBAGE: BASIC Tenliners Contest 2016 entry
For my first entry in the NOMAM BASIC 10-Liners Contest for 2016, I wanted to see if I could do a text adventure game in just 10 lines of BASIC on the Atari 800. (I like Turbo Basic XL.) I went from that thought to finished game in just a few hours. Turns out it can be done — if you want a game with two rooms, three items, and five verbs.
Wikipedia calls this the "fox, goose and bag of beans puzzle". I first heard it as wolf, sheep, and cabbage, which wikipedia calls a "cosmetic variation." I picked the latter for the game because a cabbage is funnier than a bag of beans, and easier to parse. I'm not sure why I changed it to goat, I goofed I guess. Though the single Chinese word yáng refers both to goats and sheep, so they're interchangeable, sorta.
1 REM CABBAGE - A TEXT ADVENTURE IN 10 LINES OF BASIC BY [email protected] - JANUARY 17, 2016 2 REM GET ALL ITEMS NORTH ACROSS THE RIVER. YOUR LITTLE BOAT ONLY FITS 1 ITEM AT A TIME. 3 REM COMMANDS ARE: INVENTORY, NORTH, SOUTH, GET , DROP 10 DIM A$(20),B$(1),RN$(20),RN(2,2),IN$(100),IN (3,2),IL(3),EX(2,4):EX(1,1)=2:EX(2,2)=1: L=1:H=3 20 RN$="South BankNorth Bank":RN(1,0)=1:RN(1,1)=10:RN(2,0)=11:RN (2,1)=20:IN$="WOLFGOATCABBAGE":IN(1,1)=1 25 IN(1,2)=4:IN(2,1)=5:IN(2,2)=8:IN(3,1)=9: IN(3,1)=9:IN(3,2)=15:D=0:? :? RN$(RN(L,0),RN(L,1)):? "You see:":Y=L:EXEC LL 50 INPUT ">",A$:IF A$="":GOTO 25:ENDIF :B$=A$(1,1):IF B$="N":D=1:ELSE :IF B$="S":D=2:ENDIF :ENDIF 70 IF D:IF EX(L,D):IF H>1:? "Boat too full.":ELSE :L=EX(L,D):ENDIF :ELSE :? "YOU CAN'T GO THAT WAY.":ENDIF :ENDIF 80 IF B$="I":? "You're carrying:":Y=0:EXEC LL:ENDIF :I=0:IF H=3 AND L=2:? "All safe on North Shore, you win!":END :ENDIF 90 IF B$="G" OR B$="D":IF INSTR(A$,"WOLF"):I=1:ENDIF :IF INSTR(A$,"GOAT"):I=2:ENDIF :IF INSTR(A$,"CABBAGE"):I=3:ENDIF 95 IF B$="G":IF IL(I)=L:IL(I)=0:? "Got it":H=H+1:ELSE :? "NOT HERE":ENDIF :ELSE :IF IL(I)=0:IL(I)=L:? "Dropped":H=H-1:ENDIF :ENDIF 96 ENDIF :IF IL(2)=L:IF IL(1)=L:? "Wolf gobbles goat!":END :ELSE :IF IL(3)=L:? "Goat eats cabbage!":END :ENDIF :ENDIF :ENDIF :GOTO 25 99 PROC LL:Z=0:FOR X=1 TO 3:IF IL(X)=Y:? IN$(IN(X,1),IN(X,2)):Z=1:ENDIF :NEXT X:IF Z=0:? "Nothing.":ENDIF :ENDPROC
Here’s my explanation of the code:
10 DIM A$(20),B$(1),RN$(20),RN(2,2),IN$(100),IN(3,2),IL(3),EX(2,4):EX(1,1)=2:EX(2,2)=1:L=1:H=3
DIMs: A$ is the user's command B$ is the first character of A$. To save line space vs. using A$(1,1) all the time. RN$ contains all the room names. By "all" I mean "both" but it could easily be more. RN (two-dimensional array) contains info about the start (roomnumber, 1) and end (roomnumber, 2) of room names in RN$ IN$ contains the items names of all items IN (two-dimensional array) contains info about the start (itemnumber, 1) and end (itemumber, 2) of item names in IN$ IL (array) contains locations (room numbers) for each item. 0 means in your inventory. EX (two-dimensional array) is info about room exits. (roomnumber, direction) Direction is 1 for north, 2 for south, and you could certainly keep going for a more complicated game and do 3 for east, 4 west, 5 up, and so on. So EX(1,1)=2 means from room number 1, the north exit leads to room 2.
:EX(1,1)=2:EX(2,2)=1 Set up the two exits. :L=1 Starting location room number. :H=3 Held items: number of items in inventory is 3.
20 RN$="South BankNorth Bank":RN(1,0)=1:RN(1,1)=10:RN(2,0)=11:RN(2,1)=20:IN$="WOLFGOATCABBAGE":IN(1,1)=1
Set up room and item names. I wanted to keep this flexible so it would be easy to create other environments.
25 IN(1,2)=4:IN(2,1)=5:IN(2,2)=8:IN(3,1)=9:IN(3,1)=9:IN(3,2)=15
More setup of item names. This is part of the main loop — I didn't love that but needed to put it here for space and it doesn't hurt anything.
:D=0:? :? RN$(RN(L,0),RN(L,1)):? "You see:":Y=L:EXEC LL
D will tell us if we're moving (N or S only for this game) or 0 for non-moving commands.
Print room name, show what's in the room via subroutine.
50 INPUT ">",A$:IF A$="":GOTO 25:ENDIF :B$=A$(1,1):IF B$="N":D=1:ELSE :IF B$="S":D=2:ENDIF :ENDIF
Get user command. Check for no input (that would break the A$(1,1)).
North is direction 1, South is direction 2. D stays 0 for other commands.
70 IF D:IF EX(L,D):IF H>1:? "Boat too full.":ELSE :L=EX(L,D):ENDIF :ELSE :? "YOU CAN'T GO THAT WAY.":ENDIF :ENDIF
We're trying to move! Don't allow it if inventory is >1 item. Change to new room number if it's a real place. If it's 0, there's no exit that way, complain.
80 IF B$="I":? "You're carrying:":Y=0:EXEC LL:ENDIF :I=0:IF H=3 AND L=2:? "All safe on North Shore, you win!":END :ENDIF
Player typed "INVENTORY" (or INV or I or IGUANA): list items with location 0 via subroutine. It also checks for end of game conditions (holding all 3 items in room 2) when you do inventory.
90 IF B$="G" OR B$="D":IF INSTR(A$,"WOLF"):I=1:ENDIF :IF INSTR(A$,"GOAT"):I=2:ENDIF :IF INSTR(A$,"CABBAGE"):I=3:ENDIF
Player wants to Get or Drop an item. I wish I had had room to allow Take also. Ham-fistedly assign I as item number based on object name.
95 IF B$="G":IF IL(I)=L:IL(I)=0:? "Got it":H=H+1:ELSE :? "NOT HERE":ENDIF
If we're Getting (not Taking) make sure it's in this room, print message, increment H, or complain.
:ELSE :IF IL(I)=0:IL(I)=L:? "Dropped":H=H-1:ENDIF :ENDIF
If we're Dropping, make sure it's in inventory, print message, decrement H. (Oops, no complaint option.)
96 ENDIF :IF IL(2)=L:IF IL(1)=L:? "Wolf gobbles goat!":END :
Don't put these guys down together. (Apparently carrying them both around in your arms in perfectly safe though.) Note: IF IL(2)=L -- the goat is the root cause of all our problems.
ELSE :IF IL(3)=L:? "Goat eats cabbage!":END :ENDIF :ENDIF :ENDIF :GOTO 25
Goats loooove some cabbages, apparently. Loop back for next move.
99 PROC LL:Z=0:FOR X=1 TO 3:IF IL(X)=Y:? IN$(IN(X,1),IN(X,2)):Z=1:ENDIF :NEXT X:IF Z=0:? "Nothing.":ENDIF :ENDPROC
This subroutine lists the stuff in your inventory (if Y was pre-set to 0) or in the room (if Y was pre-set to L.)
3 notes
·
View notes