News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

The Vintage Computing Christmas Challenge 2023

Started by Typhon, 23:54, 12 December 23

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

andycadley

Quote from: GUNHED on 00:32, 22 December 23Well, the shortest solution depends pretty much on the OS (which PRINT functions are there? How much registers do need to be set? Which registers are saved?) and if there is a way of dealing with stings.

F.e.: In some environments you have control codes which are capable to 'repeat' short 'repeats' of characters. (Can characters be zoomed? - Yes, helpful here btw.)

Eventually your OS decides how small your program can get. Basically size depends mostly on which kind of computer you're using.

Speccy won last year btw.  ;) :)
Indeed, OS support as well as processor architecture can be make or break if you try to compare across platforms. I was tempted to do a GX4000 solution, but with absolutely no OS help at all it would naturally be massive in comparison.

Quote from: arnolde on 00:38, 22 December 23Of course, all the computers with direct text support by the hardware (Speccy, C64) have an advantage in this kind of competition. Two years ago, i tried to go the hard & honest way by not even using system routines for drawing the stars. My program was of course not the winner.
The Speccy doesn't have direct text support in hardware, it's display is always a bitmap. It does use RST 10 for the "print a character held in A" routine though, which saves some bytes over the full CALL required on CPC.

arnolde

Quote from: andycadley on 00:53, 22 December 23The Speccy doesn't have direct text support in hardware, it's display is always a bitmap. It does use RST 10 for the "print a character held in A" routine though, which saves some bytes over the full CALL required on CPC.
Yes, you're right, sorry. I was thinking more about the "text-friendly" screen memory arrangement in lines of the "fastest" solution discussion. Just INC the hibyte to get to the next scanline, don't loose time with applying color bitmasks etc., I guess the speccy just needs less instructions to get a character on the screen. Which makes the code faster AND shorter. 

GUNHED

Just put your CPC program in the RST region and use RST x instead of CALL TXT_OUT.
Of course you need to have this here too: "RSTx JP TXT_OUT". So the JP begins at the RST address, for example &30 for RST 6.
Of course the program must be assembled in a way that the correct part 'hits' the right address for alignment with RST.  :)
http://futureos.de --> Get the revolutionary FutureOS (Update: 2023.11.30)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)

arnolde

"CALL TXT_OUT" only appears once in my code (called repeatedly of course), so that doesn't really help me.
But I found another, very very dirty trick to reduce the firmware call to 2 bytes. I won't say more...

andycadley

Quote from: arnolde on 20:33, 22 December 23"CALL TXT_OUT" only appears once in my code (called repeatedly of course), so that doesn't really help me.
But I found another, very very dirty trick to reduce the firmware call to 2 bytes. I won't say more...
Put your code near enough to the jumpblock and JR to them?

ZbyniuR

#55
If we can to use control codes like Ctrl+K, I managed to fit it into 100 bytes in Basic.
Is this good enough or should I try harder?
In STARS, TREK is better than WARS.

Urusergi

Quote from: ZbyniuR on 15:33, 23 December 23If we can to use control codes like Ctrl+K, I managed to fit it into 100 bytes in Basic.
Is this good enough or should I try harder?

100 bytes!! It's incredible 8)

I'll not participate in the contest, so I'm free to publish my improvised idea. If you see that you can take advantage of it using control codes, you have my permission:

10 CLS:y%=1:FOR x%=4 TO 16 STEP 6
:WHILE x%>1:GOSUB 20:x%=x%-1:y%=y%+1:WEND
:WHILE y%<19:GOSUB 20:x%=x%+1:y%=y%+1:WEND
:WHILE x%<19:GOSUB 20:x%=x%+1:y%=y%-1:WEND
:WHILE y%>1:GOSUB 20:x%=x%-1:y%=y%-1:WEND
:NEXT:END
20 LOCATE x%,y%:PRINT"*":RETURN



ZbyniuR

I think if you use command LOCATE you have to use least 3 loops, thats makes program longer, and I made 160 bytes with LOCATE, so I decided to think outside of the box and forget about LOCATE.
Your code (if I took 2 unnesesery space like this "4TO 16STEP"), left 222 bytes, quite much, but I very like the way how stars apeares in your code. It's look realy nice. :)

I just submitted my program to a competition.
In STARS, TREK is better than WARS.

Typhon

#58
I submitted mine earlier. As the deadline has now passed for submission, I can report that I managed to do it sub-100 bytes (just) in asm. Not bad for what really is only my 2nd ever non-trivial asm program ever. Think I'll do more of this sort of thing as it was fun doing it.

Longshot

Rhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!

lmimmfn

Oh, i'm excited only 39 mins to go
6128 for the win!!!

Prodatron

Wow, that was just fantastic!!

Congratulation to Logon System/Overflow/Longshot and also to ArnoldE for one of the best entries!

Well somehow I already knew, that someone from the Spectrum would win again in Z80 :D

GRAPHICAL Z80 MULTITASKING OPERATING SYSTEM

arnolde

Congratulations as well, chapeau to the other entries, especially to the other CPC ones!

lightforce6128

Thank you to all participants and especially to the organizer of this challenge. Congratulations to Overflow and Longshot. 28 bytes is really an achievement.

The discussion about the sizes of intermediate program versions in this channel was quite interesting. But as the organizer suspected, knowing a program size smaller the one oneself has achieved motivates first to try harder, but demotivates to participate further if no improvement seems to be possible. So I did not hand in my program.  :-[

All in all I tried 5 approaches in BASIC and 7 approaches in assembler. The smallest one (42 bytes) checks if a character lies on a diagonal crossing. It can get even smaller (37 bytes) by removing the first and last instruction, but only if one bends the rules a bit. The program needs to be adapted to different CPC versions in line 11 and has to be called from CPC BASIC prompt with CALL &1336 (a bit inconvenient, but saves some bytes).

I thought about when to publish this and hesitated to do it too early. Now it should be the right time: no interference with the challenge and soon enough after the presentation to avoid speculations where this program could have its origins.  ;)

NOLIST

SIDE_LENGTH EQU 19
Z_MAX EQU 14
Z_MIN EQU -40
Z_RANGE EQU Z_MAX - Z_MIN
Z_STEP EQU 6
TXT_OUTPUT EQU &BB5A
CHAR_SPC EQU 32
CHAR_AST EQU 42
BASIC_PRINT_LF EQU &C398 ;; C34E C39B C398 ;; This needs adaption.
TWO_CONSTANTS EQU SIDE_LENGTH*256 + Z_RANGE

ORG TWO_CONSTANTS

first:

    LD DE,TWO_CONSTANTS ;; This can be removed.
    LD B,D
yLoop:    LD C,D
xLoop:    LD H,CHAR_SPC
    LD L,E
zLoop:    LD A,B
    ADD A,L
    SUB A,-Z_MIN
    JR NC,is_pos
    NEG
is_pos:    INC A
    SUB A, C
    JR NZ,not_eq
    LD H,CHAR_AST
not_eq:    LD A,L
    SUB A,Z_STEP
    LD L,A
    JR NZ,zLoop
    LD A,H
    CALL TXT_OUTPUT
    DEC C
    JR NZ,xLoop
    RST &10
    DEFW BASIC_PRINT_LF AND &3FFF
    DJNZ yLoop
    RET ;; This can be removed.

last:

IF1
SIZE EQU last-first
PRINT "call: $first"
PRINT "size: &SIZE"
ENDIF

ZbyniuR

I've never seen so much Magic Kind of Basic before.

My mouth still open, I take a bow for every programmer better than me.

I have 2nd place in CPC Basic , and I feel very humble. :)

Only two Basic program shorter than my I understand good enough to translate into CPC.
Rest is for me like unknown Galaxy.
In STARS, TREK is better than WARS.

ervin

Wow! There were some truly mind-blowing programs submitted this year.
Pure sorcery!

I didn't submit an entry, but my best effort is below.
Including CLS, it is 56 bytes.

org &8000
;write "code.bin"

call &bc14 ; SCR CLEAR

ld hl,&0401 ; x=4 y=1
ld de,DRAW_DIAMOND

ld b,3
DRAW_DIAMOND:
inc h ; will be changed by self-modifying code
inc l ; will be changed by self-modifying code

push hl
call &bb75 ; TXT SET CURSOR
pop hl
ld a,42 ; *
call &bb5a ; TXT OUTPUT

ex de,hl
ld a,d
call CHECK_BORDER_HIT
inc l
ld a,e
call CHECK_BORDER_HIT
dec l
ex de,hl

ld a,l
dec a
jr nz,DRAW_DIAMOND

ld a,h
add a,6
ld h,a
djnz DRAW_DIAMOND

jr $+0

CHECK_BORDER_HIT:
cp 19
jr nz,BORDER_HIT
inc (hl)
BORDER_HIT:
dec a
ret nz
dec (hl)
ret

Longshot

#66
Thanks for your comments.

Congratulations to everyone and especially to NESU for his entry!
(and also to Logiker for his huge work for compiling all these entries).

Those who did the exercise know how difficult it is to scrape each byte. ;)

I didn't know that you could call the executable code from Basic (memory/load/cls/call) rather than launching the code via a run"exefile".
We could guess it in the FAQ (although I still don't really know what a "stub" is...a "launcher" would perhaps be a more appropriate term?)

By applying this rule (call from Basic), Logon System's output can go down to 25 bytes :
;=======================================================================
; Vintage Computing Christmas Challenge 2023 (VC3 2023)
; Amstrad CPC / Overflow & Longshot (Logon System)
; December 2023 / 31.12.2023
; 25 bytes
;=======================================================================
_firm_dispchar    equ #bb5a        ; firmware TXT OUTPUT
_firm_locatexy    equ #bb75        ; firmware TXT SET CURSOR
orgcode        equ #1341
sizecode     equ end_c-start_c

    org orgcode
start_c
                ; on run (de=orgcode=#1341 (19 & X)
                ; E = #41 = 5 + 6*n ; 5 would be ok
loopbig             ; 1st loop for half of the shape
                       ; 2nd loop for the other half
                    ; then loops for ever on 2nd loop
    ld a,c             ; X
    ld b,d             ; Y dec from 19 to 1
loop
    inc a             ; pre-inc X
    ld h,a             ; X=...
    ld l,b             ; Y=...
    call _firm_locatexy     ; locate X,Y ; X-- Y--   
    ld a,h
    cp d            ; output windows X-1 <19
    ld a,"*"         ;
    call c,_firm_dispchar    ; print "*"
    ld a,h
    sub 6            ; next start is at X-6
    jr nc,loop        ; is X still > 0 ?
    sub e             ; adjust start slide for next line
    djnz loop         ; next line
    ld e,h             ; for next loop E = #03 = 3 + 6*n
    jp (hl)         ; jp loopbig = #300 = HL
end_c
;
Rhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!

lightforce6128

A friend explained to me that a "stub" is something from C64 where a binary file needs a small BASIC program (a single line with a CALL resp. SYS command) to make it runnable with "RUN" (see e.g. here). On CPC the needed information (the start address) can be embedded in the file header.

Using the start address from a manual CALL to load some constants to DE bends the rules a bit. If one applies the rules strict, then information the program needs is stored outside the program. Consequently, the size of the BASIC command should also be added to the size. Even if counted as compacted to tokens, this is at least 3 bytes, the same length a "LD DE,&xxxx" command would take.

On the other hand, starting the program from disk reinitializes the system and clears the screen. This does not happen if the program is called manually and might require additional three bytes to call CLS.

lightforce6128

Quote from: ervin on 07:31, 31 December 23ld de,DRAW_DIAMOND
...
DRAW_DIAMOND:
inc h ; will be changed by self-modifying code
inc l ; will be changed by self-modifying code
...
CHECK_BORDER_HIT:
inc (hl)
dec (hl)


Very interesting. I never noticed before that "inc hl" and "dec hl" have neighboring opcodes that can be manipulated by indirect "inc" and "dec" commands.

Prodatron

Quote from: Longshot on 11:50, 31 December 23By applying this rule (call from Basic), Logon System's output can go down to 25 bytes :
Brilliant!
So you used the following tricks/knowledge/etc:
- C is #FF at start; saves 1 byte (ld a,-1)
- DE is the entry address and so it can be predefined with ORG (I used this trick as well); saves 3 bytes
- _firm_locatexy decreases H and L by 1 (I thought it would just "destroy" them); saves 2 bytes (push af, dec a)
- the area between #300 and ORG is empty, full of NOPs, so you can just jump there; saves 1 byte (jr relative)

Still crazy that H is 3 at the end and so can be used to update E.
I am really impressed! :o

GRAPHICAL Z80 MULTITASKING OPERATING SYSTEM

Urusergi

If I'm not wrong, Logiker has achieved the best position in amstrad cpc basic, so congratulations! :)

This is the code:
1for i=0 to 18:for x=3 to 21:?chr$(32-10*(abs(x mod 6-3)=abs(i mod 6-3)));:next:?:next
With a size of: 42249-42167= 82 bytes + last two zeros = 84 bytes.

It's wonderful 8) but it can still be improved a little in size and especially in speed:

1for i%=0to 18:for x%=3to 21:?chr$(9-33*(abs(x% mod 6-3)=abs(i% mod 6-3)));:next:?:next
With a size of: 42249-42170= 79 bytes + last two zeros = 81 bytes.

In terms of speed (with and without scroll):

Original: ~4.95s and ~4.7s

New code: ~3.78s and ~3.44s

Nesu

Quote from: lightforce6128 on 15:17, 31 December 23Using the start address from a manual CALL to load some constants to DE bends the rules a bit....
At the FAQ section of the rules says "... Exception: start address. Every program needs to start. So, if the starting process sets a register or zero-page address, you can use this side effect.". I understand that means it can be used.
Regarding the 'cls', it is mostly for convenience copypasting the full command into the emulator. In the description file I mention that you can also manually load the file into memory, scroll down until the screen clears, and then call the code (crappy method of loading, but it's a method of loading ;D ).

Longshot

#72
Quote from: Prodatron on 15:37, 31 December 23Brilliant!
So you used the following tricks/knowledge/etc:
- C is #FF at start; saves 1 byte (ld a,-1)
- DE is the entry address and so it can be predefined with ORG (I used this trick as well); saves 3 bytes
- _firm_locatexy decreases H and L by 1 (I thought it would just "destroy" them); saves 2 bytes (push af, dec a)
- the area between #300 and ORG is empty, full of NOPs, so you can just jump there; saves 1 byte (jr relative)
Thank you Prodatron and Happy New Year 2024 to all!
Still a few bytes to scrape and the CPC can get a very good score this year ;D

You can also add these little tricks
- _Firm_Locatexy returns 2 according to the state of the cursor. (&B72E) = 2/0
  After a call &bc0e or in run (which performs a CLS), (&B72E) = 2
- Use a conditional call to simplify the calculation of the positions by avoiding displaying localized characters outside a window (see call c,&BB5A)

Quote from: Nesu on 21:20, 31 December 23Exception: start address. Every program needs to start
That's for sure ::)

But then can we have its code located in &4000, and make a call &062a? Is it valid ? ;D
(like a saved program: Save "Mycode", B,&4000,23,&062A)
Rhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!

Overflow

Happy New Year 2024 !  :D

I had much fun with "VCCC 2023". My very first lines of code since early 2018. I believe that sizecoding is rising my motivation to spend some time again brainstorming on Z80 and possibly release those small things.

Back to the Christmas challenge : I'd like to share another 26B piece of code. Likely some of you guys may learn from it for better achievement next year. Learn as I did from you guys : nice trick @arnolde with those system variables at #B726 instead of locate by call #BB75. Or from other guys on Spectrum : writing same char by calling #BB75 128 times ouch !

  org #3483-#14
; de = #0613 by CALL thru BASIC
; bc = #20ff
  ld a,#09
  ld c,58
loop
  ld hl,#b726+1 ; y then x
  ld (hl),a ; x
  ld a,"*"
  call #BB5A
  ld a,e
  sub (hl)
  djnz loop ; 1st b=#20 then #00
  dec hl
  sub d
  jp c,here ;
here equ $-2 ; =#3483
;  add a,e     =#  83
;  inc (hl)    =#34
  dec c
  ret z
  jr loop

I still believe this is cheating : assemble this at org #346F but call it from basic by CALL &0613 ; assuming #0613 to #346F is full of 0=NOP this allows to preset DE=#0613. Hmm ok I got it for next year.

Also this kind of beauty - at least for me : JP cond,$+1 with adress is #3483 so that opcodes at that place are #83 then #34 = ADD A,E then INC (HL).

;D

Unregistered from CPCwiki forum.

Urusergi

#74
Wow! very good trick 8)

To improve the speed a bit you can take the ret out of the loop:

  ...
  dec c
  jr nz,loop
  ret


EDIT: and a bit more
  org #3483-#14
; de = #0613 by CALL thru BASIC
; bc = #20ff
  ld a,#09
  ld c,58
loop
  ld hl,#b726+1 ; y then x
loop1
  ld (hl),a ; x
  ld a,"*"
  call #BB5A
  ld a,e
  sub (hl)
  djnz loop1 ; 1st b=#20 then #00
  dec l
  sub d
  jp c,here ;
here equ $-2 ; =#3483
;  add a,e     =#  83
;  inc (hl)    =#34
  dec c
  jr nz,loop
  ret


Powered by SMFPacks Menu Editor Mod