I've made a one liner - called Line

The place for codemasters or beginners to talk about programming any language for the Spectrum.
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

I've made a one liner - called Line

Post by patters »

A game about a line, written in a single line of BASIC code

I've been fascinated by Digital Prawn's One Liners since discovering them recently. I was compelled to take up the challenge, and have created my own game, called Line:

Image

I notice that things have been a bit quiet for the last decade on the one liners front - anyone else fancy having a crack at one?
User avatar
Alessandro
Dynamite Dan
Posts: 1908
Joined: Wed Nov 15, 2017 11:10 am
Location: Messina, Italy
Contact:

Re: I've made a one liner - called Line

Post by Alessandro »

Nice! I managed to get to level 10 on my first go.

Out of curiosity, why didn't you make the game run upon loading?
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

Re: I've made a one liner - called Line

Post by patters »

A solid first go! I set the max level at 20 mainly because it seems within easy reach enough to hook the player a bit more. However, the escalation in difficulty is quite rapid. The aim is for it to be a digital equivalent to one of those wire loop dexterity tests. Just one more go, I know I can do it this time...

I did just try it on my real Speccy for this first time and unfortunately the blue line is really hard to see compared to on the emulators. Not ideal.

Regarding not saving with LINE 1, I was following what seems to be the convention of those other one liners on Digital Prawn's site. Since you have to keep typing RUN anyway, I figure it at least gives people a chance to see the listing before the colours get changed. That is the focus after all.

I find this format forces clean design. That Connect 4 game on Digital Prawn's sits is so elegant, a real marvel.

There are two features from my original version of this game that I had to drop to fit within the one liner constraints - multiple lives in a game, and better sound effects for dying and game over. Now I'm already wondering if I can get the lives back in. It's quite addictive, optimising over and over.
User avatar
R-Tape
Site Admin
Posts: 6353
Joined: Thu Nov 09, 2017 11:46 am

Re: I've made a one liner - called Line

Post by R-Tape »

It certainly does have that 'just one more go' factor. Surprisingly fun game.
patters wrote: Mon Jul 29, 2019 12:38 am I notice that things have been a bit quiet for the last decade on the one liners front
Aye - there is a ZXDB on-liner group, and there's only been 1 of them since Prawn's, Einar's and DrBeep's heyday.
- anyone else fancy having a crack at one?
Not me! I'm not averse to certain kinds of coding challenge, but the thought of doing a one-liner gives me the heebeegeebies! Happy to admire what you guys achieve.
User avatar
Joefish
Rick Dangerous
Posts: 2042
Joined: Tue Nov 14, 2017 10:26 am

Re: I've made a one liner - called Line

Post by Joefish »

I find it horrendous enough not having an 'ELSE' keyword in Sinclair BASIC, never mind having to code an entire game with non-branching logic.
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

Re: I've made a one liner - called Line

Post by patters »

Joefish wrote: Tue Jul 30, 2019 11:41 am I find it horrendous enough not having an 'ELSE' keyword in Sinclair BASIC, never mind having to code an entire game with non-branching logic.
Agreed, having to repeat the condition and resort to GOTOs is so annoying .

There is a secret weapon though once you start peeling apart the examples - POKE 23620,x (the sysvar named NSPPC) which jumps execution to statement x within a line. Since logic operators are evaluated inline you can retain very complex control, for example from Labyrin3D:

Code: Select all

POKE (p+z<i)*23620,8+9*o*(q<i)*(c>1):
So this is only going to apply the POKE if a certain conditions are met, and even then its outcome depends on a host of other variable states.
Another trick of the trade is using READ and DATA to define and calculate variables instead of LET since they can be combined (e.g. READ a,b,c,d,e,f)

There is one slight edge case to my game. In order to keep the action reasonably fast I DRAW the line in increments of two pixels rather than PLOTing each point. Since the attributes are only checked every two pixels of line it's possible for the line to clip across the corner pixel of an obstacle and turn it blue without a collision. A necessary design compromise though...
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

Good job!
patters wrote: Mon Jul 29, 2019 11:46 pm There are two features from my original version of this game that I had to drop to fit within the one liner constraints - multiple lives in a game, and better sound effects for dying and game over.
A few easy tips to make it shorter:
  • Initializing variables using READ/DATA doesn't always make it shorter. In your case, eliminate variables 'a' and 'b' (use these values directly in your DRAW statements) to save 4 characters.
  • Sometimes simple Math changes can save a lot. For instance, replace this:

    Code: Select all

    FOR x=10 TO 250 STEP 2: ... INT (x/8)
    with this:

    Code: Select all

    FOR x=5 TO 125: ... INT (x/4)
  • Don't use parenthesis unless really necessary. For instance, you can save 2 characters replacing this:

    Code: Select all

    LET k=(4*(INKEY$=" "))-2
    with this:

    Code: Select all

    LET k=4*(INKEY$=" ")-2
    although I think it would work better like this:

    Code: Select all

    LET k=4*(INKEY$<>"")-2
    This way, users would be able to play the game using whatever key they prefer.
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

After eliminating variables 'a' and 'b', you can save another 8 characters replacing this:

Code: Select all

FOR n=0 TO 1: PLOT 1+n,6+n: DRAW 0,163: DRAW 248,0: DRAW 0,-163: DRAW -248,0: NEXT n: PLOT 250,6
with this:

Code: Select all

PLOT 2,170: FOR n=0 TO 1: DRAW 248,0: DRAW 0,n+n-164: DRAW n+n-249,0: DRAW 0,163: NEXT n
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

Another optimization is to allow Sinclair BASIC to round numbers for you. For instance, instead of this:

Code: Select all

INK INT (RND*4)+4
use this:

Code: Select all

INT RND*4+3.5
There are several places in your program where you can use this kind of trick.
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

Instead of this:

Code: Select all

FOR n=9+(l>9) TO 12-(l>9): PRINT AT n,31; INK 0;" ": NEXT n: PRINT AT 0,0; INK 3;"LEVEL ";l
use this:

Code: Select all

PRINT INK 3;"LEVEL ";l: FOR n=9+(l>9) TO 12-(l>9): PRINT AT n,31; INK 0;" ": NEXT n
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

You can remove this statement from the GAME OVER sequence:

Code: Select all

POKE q,1
At this point, you will already have INK 1 and PAPER 0. The only effect practical effect of this statement is to disable BRIGHT, but it's nearly impossible to distinguish brightness with these colors anyway.
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

patters wrote: Tue Jul 30, 2019 12:31 pm There is one slight edge case to my game. In order to keep the action reasonably fast I DRAW the line in increments of two pixels rather than PLOTing each point. Since the attributes are only checked every two pixels of line it's possible for the line to clip across the corner pixel of an obstacle and turn it blue without a collision. A necessary design compromise though...
To fix this bug, change the start position from (8,85) to (8,84).
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

Re: I've made a one liner - called Line

Post by patters »

Great tips, from the master himself :)

I was just experimenting with the collision detection. The star character is quite small relative to the character block so I was wondering about whether to change it to use POINT rather than ATTR. Drawing each pixel on the line with PLOT is still considerably slower, but if I stick to DRAWing in increments of two I can validate the POINT status at both points for roughly the same overhead as one ATTR lookup. This would allow the line to really skim the obstacles and would make the game feel a lot more fair. Colour clash can be somewhat mitigated by making the entire playfield INK 1 and rendering the line with INK 8. This is less jarring than the line turning obstacles blue. I'll fold in your improvements and post a new version here to see whether people prefer it.
Last edited by patters on Tue Jul 30, 2019 9:06 pm, edited 1 time in total.
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

Re: I've made a one liner - called Line

Post by patters »

Einar Saukas wrote: Tue Jul 30, 2019 8:17 pm To fix this bug, change the start position from (8,85) to (8,84).
How did I not see that. :lol:
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

patters wrote: Tue Jul 30, 2019 9:04 pm Great tips, from the master himself :)
Thanks! :)

patters wrote: Tue Jul 30, 2019 9:04 pm I was just experimenting with the collision detection. The star character is quite small relative to the character block
I think it would look good to use the hash sign '#', but setting a different PAPER instead of INK.
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

Einar Saukas wrote: Tue Jul 30, 2019 10:04 pm I think it would look good to use the hash sign '#', but setting a different PAPER instead of INK.
Another idea is to use either hash sign '#' or capital 'O', setting PAPER 1 and a different INK. It will give the impression there's a faint force field around each obstacle. This way, these obstacles won't look as blocky, but the collision will always seem correct.

Yet another option is using the copyright symbol that fills almost the entire character block, but I don't think it will look as good.
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

Re: I've made a one liner - called Line

Post by patters »

Hmm. I've really convinced myself that ATTR collision detection is not a good fit here, so I've switched to POINT. The main issue is that as the later levels get congested with obstacles, the player needs to be able to cut a diagonal between closely packed obstacles. If you can't do this then it seems too unfair. This is a remake of a game I had played at school, and on that computer I'm pretty sure collisions were pixel accurate, so this feels more faithful.

Code: Select all

FOR l=1 TO 20:
POKE 23693,65:
BORDER 0:
CLS :
INK 2:
PLOT 2,170:
FOR n=0 TO 1:
DRAW 247,0:
DRAW 0,n+n-164:
DRAW n+n-248,0:
DRAW 0,163:
NEXT n:
PRINT INK 3;"LEVEL ";l:
FOR n=9+(l>9) TO 12-(l>9):
PRINT AT n,31; INK 1;" ":
NEXT n:
INK RND*4+3.5:
FOR n=0 TO l*3+20:
PRINT AT RND*18+1.5,RND*26+3.5;"*":
BEEP .0001,60:
NEXT n:
INK 8:
LET y=85:
PLOT 8,y:
FOR x=5 TO 125:
LET k=4*(INKEY$<>"")-2:
LET y=y+k: POKE 23620*POINT (2*x,y),34:
DRAW 2,k:
NEXT x:
BEEP .01,20:
BEEP .01,30:
NEXT l:
DIM a$(32):
BRIGHT 0:
INK 1+5*(l=21):
FOR n=0 TO 6:
BEEP .005,20-5*n:
NEXT n:
FOR n=0 TO 10:
PRINT AT n,0; OVER 1;a$;AT 21-n,0;a$:
NEXT n:
PRINT AT 10,n; INK 7;"GAME OVER" AND l<21;"WELL DONE" AND l=21
Download link

The game is a bit faster now which I think makes it more addictive, but it's a lot more achievable though still challenging. In fact I just completed it for the first time. I've improved the sound a bit, and added a completion screen. The collision detection is only checked every two pixels on the line, but I think with the current grid alignment it's working well. What do you think Einar?
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

Re: I've made a one liner - called Line

Post by patters »

Here is a version which sacrifices the better sounds in order to offer the player three lives with a visual indicator in the bottom right of the screen. Given that the game runs faster, I think this is a good addition. In order to get it under the one screen limit I have had to re-use the 'e' variable a few times.

Code: Select all

READ p,q,e,l,d$:
FOR d=0 TO 2:
POKE q,65:
BORDER 0:
CLS :
INK 2:
PLOT 2,170:
FOR n=0 TO 1:
DRAW 247,0:
DRAW 0,n+n-164:
DRAW n+n-248,0:
DRAW 0,163:
NEXT n:
PRINT INK 3;"LEVEL ";l:
FOR n=9+(l>9) TO 12-(l>9):
PRINT AT n,31; INK 1;" ";AT 20,29+d;d$( TO 2-d):
NEXT n:
INK RND*4+3.5:
FOR n=0 TO l*3+e:
PRINT AT RND*18+1.5,RND*26+3.5;"*":
NEXT n:
INK 8:
LET y=85:
PLOT 8,y:
FOR x=5 TO 125:
LET k=4*(INKEY$<>"")-2:
LET y=y+k:
POKE p*POINT (2*x,y),34:
DRAW 2,k:
NEXT x:
LET l=l+1:
BEEP .02,30:
POKE p,3+33*(l=e):
BEEP .2,-e:
NEXT d:
DIM a$(32):
INK 1+5*(l=e):
FOR n=0 TO 10:
PRINT AT n,0; OVER 1;a$;AT 21-n,0;a$:
NEXT n:
PRINT AT 10,n; INK 7;"GAME OVER" AND l<e;"WELL DONE" AND l=e:
DATA 23620,p+73,21,1,"//"
Download link

Any further optimisations here that might allow the sounds as well, particularly the obstacle placement beep?
Last edited by patters on Wed Jul 31, 2019 2:03 pm, edited 4 times in total.
User avatar
Joefish
Rick Dangerous
Posts: 2042
Joined: Tue Nov 14, 2017 10:26 am

Re: I've made a one liner - called Line

Post by Joefish »

If it's only checking every 2 pixels, surely you need obstacles that have two-pixel thick lines so you don't skip straight through one?
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

Re: I've made a one liner - called Line

Post by patters »

Joefish wrote: Wed Jul 31, 2019 1:30 pm If it's only checking every 2 pixels, surely you need obstacles that have two-pixel thick lines so you don't skip straight through one?
I have play tested it a lot and I think it's fine. The border lines are two pixels thick, and the stars don't really have corners to skip though if you're on a diagonal trajectory. Basically if you're going to clip the star at all you'll hit it with the subsequent pixel - mainly because of the current grid alignment (which can only change by 2 units at a time). Give it a try. I just updated the latest version btw. Had some issues with it which are now resolved, but it's been tricky to get it back under the one screen limit.
User avatar
patters
Manic Miner
Posts: 467
Joined: Thu Apr 11, 2019 1:06 am

Re: I've made a one liner - called Line

Post by patters »

patters wrote: Wed Jul 31, 2019 12:31 pm Here is a version which sacrifices the better sounds in order to offer the player three lives with a visual indicator in the bottom right of the screen.
Updated again to combine the creation of the gate into the red playfield outline loop. Is there a tighter way to encode these DRAW operations I wonder...

Code: Select all

READ p,q,e,l,d$:
FOR d=0 TO 2:
POKE q,65:
BORDER 0:
CLS :
INK 2:
LET g=8*(l>9)
PLOT 2,170:
FOR n=0 TO 1:
DRAW 247,0:
DRAW 0,n-66-g:
PLOT 249-n,71+g:
DRAW 0,n-65-g:
DRAW n+n-248,0:
DRAW 0,163:
NEXT n:
PRINT INK 3;"LEVEL ";l;AT 20,29+d; INK 1;d$( TO 2-d):
INK RND*4+3.5:
FOR n=0 TO l*3+e:
PRINT AT RND*18+1.5,RND*26+3.5;"*":
NEXT n:
INK 8:
LET y=85:
PLOT 8,y:
FOR x=5 TO 125:
LET k=4*(INKEY$<>"")-2:
LET y=y+k:
POKE p*POINT (2*x,y),34:
DRAW 2,k:
NEXT x:
LET l=l+1:
BEEP .02,30:
POKE p,3+33*(l=e):
BEEP .2,-e:
NEXT d:
DIM a$(32):
INK 1+5*(l=e):
FOR n=0 TO 10:
PRINT AT n,0; OVER 1;a$;AT e-n,0;a$:
NEXT n:
PRINT AT 10,n; INK 7;"GAME OVER" AND l<e;"WELL DONE" AND l=e:
DATA 23620,p+73,21,1,"//"
Download link
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

Instead of this:

Code: Select all

FOR d=0 TO 2: ...       PRINT INK 3;"LEVEL ";l;AT 20,29+d; INK 1;d$( TO 2-d)
Use this:

Code: Select all

FOR d=1 TO 3: ...       PRINT INK 3;"LEVEL ";l;AT 20,28+d; INK 1;d$(d TO )
However the lives indicator looks much better using INK 3. In this case, the code will be much shorter:

Code: Select all

FOR d=1 TO 3: ...       PRINT INK 3;"LEVEL ";l;AT 20,28+d;d$(d TO )
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

Replace:

Code: Select all

FOR n=0 TO l*3+e
with:

Code: Select all

FOR n=-e TO l*3
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

You can also consider replacing this:

Code: Select all

PRINT AT RND*18+1.5,RND*26+3.5;"*"
with this:

Code: Select all

PRINT AT RND*17+2,RND*25+4;"*"
It won't work exactly the same way, since the incidence of stars in the first and last rows, also first and last columns, will be reduced by 50%. But I think it looks even better this way. It looks good to have a higher concentration of stars closer to the center of the galaxy, not as many stars near the edge...

Alternatively you could expand the stars area sideways, to make the game a little more challenging, as follows:

Code: Select all

PRINT AT RND*17+2,RND*27+3;"*"
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: I've made a one liner - called Line

Post by Einar Saukas »

I suggest replacing this:

Code: Select all

POKE p*POINT (2*x,y),34
with this:

Code: Select all

POKE p*POINT (x+x,y),34
It's the same size, but runs a little bit faster.
Post Reply