Anyone else taking part in this (https://logiker.com/Vintage-Computing-Christmas-Challenge-2023)?
(https://logiker.com/data/_uploaded/image/VCCC/VCCC2023compo.png)
(https://logiker.com/data/_uploaded/image/VCCC/muster_003.png)
The info from the webpage:
- Software:
- Create a program that creates the object as seen within the images above, 1:1
- Exactly the same shape
- The final screen may not include any additional characters(, which are not from the operating system itself).
Your program must not draw anything else on screen than the object itself. - Prompt like READY may appear.
- No need to clear the screen. But you can. And you may write spaces.
- The object can be anywhere on the screen. e.g. left top, centred, a.s.o.
- Any colour is allowed (but please not the same as background one)
- Program termination:
- The program can finish normally afterwards (return to prompt)
- The program may loop
- It may wait for key
- It may not crash
- Hardware:
- Use any machine you like, preferable vintage computers ;-)
- Make the size of the program file (e.g. PRG on C64) as small as possible
- Don't manipulate the file (e.g. truncating the last bytes, changing the start address, etc. Mainly valid for "standard files" in BASIC and other languages.)
- About languages:
- Use any language you like, preferable on vintage computers ;-)
- If you use BASIC:
- Do not include own assembler code
- PEEK and POKE are allowed
- Even SYS is allowed (though not preferred)
- If possible, provide the basic code as text format
- If you use assembler:
- Measure the size of the executable (including BASIC starter stub)
- If possible, measure the size of the code only
- Please provide the source code and tell us which assembler was used
- Release
- You should not publish the code, or it's exact size, before the deadline. Please respect the personal challenge of others.
- Your submitted code will be released to the public (for example on sites like scene.org or demozoo.org)
- Target:
- Use your old computer / programming language (or new one, if you want)
- Try to optimize the program (for minimum size or maximum beauty ;-)
- Have fun!
I'm trying an entry in ASM.
I made a quick try and reached 81 bytes in assembler on a CPC, without CLS, wait for key etc, just printing the characters, using the firmware (#BB5A).
Maybe there is some cool math behind it and you can do it with much smaller code, no idea.
This sounds like fun. I will throw something together just for the hell of it. :)
I won't have time, but the math part seems simple, just from the initial point of horizontal position 4(repeated 3 times) next line is +1/-1 from char 4(repeated 3 times) until horizontal char is at position 1 then invert so -1/+1 repeating 3 times.
Repeat the loop 3 times for vertical.
81 bytes is impressive, surely can be done in ~45 bytes though?
It's a really nice problem(and challenge) to optimize.
Oh, indeed, you are right!
My first approach was using some kind of compressed text data.
Now with using a math based approach I reached 50 bytes (including a CLS).
I thought I was doing well to get under 100 bytes!
:D
Seriously, it's a fascinating challenge.
74 bytes.
How on earth are you getting 49 bytes
@Prodatron?
I know my algorithm skills are nowhere near as good as yours, but 49 bytes is incredible!
As CLS doesn't seem to be required, and it doesn't need to return to the prompt, I am now at 43 bytes.
But I am sure someone like MadRam can do it with half of the bytes :D
To optimise for short code: understood! 8)
Optimize for maximum beauty?
Beauty of the code or the picture?
Picture shall have 'Exactly the same shape'
Please explain. :)
For a 'short code' I can go down to two bytes. By unfair means or course.
On CPC: Do we need to count the file-header?
Quote from: GUNHED on 15:13, 13 December 23For a 'short code' I can go down to two bytes. By unfair means or course.
You won't be able to produce this shape with a 2 byte code.
Quote from: GUNHED on 15:13, 13 December 23On CPC: Do we need to count the file-header?
No, at the end only the pure Z80 code will be counted (see last year).
Btw, I reached 38 bytes now :D
38 bytes without cheating is great! :) :) :)
However if the header doesn't count: Even zero bytes can be reached - with cheating of course. ;)
Shiiiit, I made a mistake and now I am back at 49 bytes >:( I wonder if there is still another better approach...
@GUNHED, maybe you can share your thoughts about how to cheat and need 0 bytes. No idea, what you are talking about.
If you don't beat me up for this... :laugh:
Cheating means to start a 0-bytes program. And the 'start address' of the program points just at an address of the OS itself. And right there at his address the OS has a small routine just painting the stars. :-X :-\ :picard:
53 bytes (without CLS).
I have no idea how this is possible in 38 bytes!
Quote from: ervin on 05:40, 15 December 2353 bytes (without CLS).
I have no idea how this is possible in 38 bytes!
Oops, I noticed that the latest attempt was 49 bytes.
I still don't know how that's possible!
53 bytes is good already!
I am now at 43 bytes again.
But an MSX friend now did it with 32 bytes, phew!!
I can't wait to see the code!
32 bytes... wow.
Wow! This is damn good! My first approach reached 46 bytes (with no CLS). Need to rethink about it
37 now. Still 5 Bytes too Lame :D
37 bytes? Unbelievable. :o
This is a really nice challenge. The pattern to reproduce has much of symmetries and structures. And it clearly fits to this time in the year - a few days ago I helped my brother to place something similar at his hedge.
I started with a simple BASIC program. Then I found another approach, and another. Finally I had five BASIC programs. I picked the one that seems to be the simplest and shortest one and transferred it to assembler. Here I reached 55 bytes. Maybe I can press out 7 more bytes. But then even 11 more, this is something I cannot imagine. Maybe I should have a look at one of the other approaches ...
The 7 bytes are gone. And then, with some scary tricks, I could also remove 11 more bytes. So I reached 37 bytes, too. But now I'm quite sure that this approach cannot be compressed further.
I do not have much experience with size coding. If two people come up with a program with the same size and the optimization steps looks similar, does this mean it is the same approach, or can it still be something completely different?
I spent some time analysing this in Java today just to get a quick analysis of the problem in a few mins.
It's fascinating and a brilliant problem at the same time.
After analysing the problem I just let my subconscious do its thing(sounds a bit mad but that's how I do most programming, let my subconscious do the heavy lifting and let my conscious know when there's a result, which in this case was Christmas shopping today lol).
Anyways for sure I have the concepts required to have the most effecent code to generate this, the intriguing thing is code wise it has huge optimization possibilities.
Sub 30 byte code is easily possible with potential to hit 20 bytes, that MSX guys 22 bytes should be achievable.
I'll give it a try tomorrow if I have time, otherwise after tomorrow the first person to PM me I will send the solution concept.
Quote from: lmimmfn on 21:09, 16 December 23I spent some time analysing this in Java today just to get a quick analysis of the problem in a few mins.
It's fascinating and a brilliant problem at the same time.
After analysing the problem I just let my subconscious do its thing(sounds a bit mad but that's how I do most programming, let my subconscious do the heavy lifting and let my conscious know when there's a result, which in this case was Christmas shopping today lol).
Anyways for sure I have the concepts required to have the most effecent code to generate this, the intriguing thing is code wise it has huge optimization possibilities.
Sub 30 byte code is easily possible with potential to hit 20 bytes, that MSX guys 22 bytes should be achievable.
I'll give it a try tomorrow if I have time, otherwise after tomorrow the first person to PM me I will send the solution concept.
I can't imagine doing this in 30 bytes (or even 40), and certainly not 20!!!
And I've been staring at this pattern for days!
I'm not very good at obscure z80 tricks though, so that's a problem. :laugh:
I was about to start thinking about it today, but 32 bytes! Chapeau!
I participated in the last 2 years but this pattern is for sure the most interesting and hard one to tackle...
Quote from: ervin on 07:27, 17 December 23Quote from: lmimmfn on 21:09, 16 December 23I spent some time analysing this in Java today just to get a quick analysis of the problem in a few mins.
It's fascinating and a brilliant problem at the same time.
After analysing the problem I just let my subconscious do its thing(sounds a bit mad but that's how I do most programming, let my subconscious do the heavy lifting and let my conscious know when there's a result, which in this case was Christmas shopping today lol).
Anyways for sure I have the concepts required to have the most effecent code to generate this, the intriguing thing is code wise it has huge optimization possibilities.
Sub 30 byte code is easily possible with potential to hit 20 bytes, that MSX guys 22 bytes should be achievable.
I'll give it a try tomorrow if I have time, otherwise after tomorrow the first person to PM me I will send the solution concept.
I can't imagine doing this in 30 bytes (or even 40), and certainly not 20!!!
And I've been staring at this pattern for days!
I'm not very good at obscure z80 tricks though, so that's a problem. :laugh:
i will eat humble pie, lol, while the routine i created is small i hadn't realised that the firmware calls and register corruption(all 4 with printing the cursor at a location) add about 10-12 bytes to the execution size.
Hats off to Prodatron and lightforce6128, i cant imagine on the CPC that it can be reduced further.
Without any optimization on the Z80 front i got 64 bytes(code in actual routine is very small vs overall size) but i'm quite happy with that :)
Quote from: Prodatron on 22:52, 15 December 2337 now. Still 5 Bytes too Lame :D
I'm at 37 as well now – with a ridiculously simple approach (maybe the same as you?). I don't see yet where I could spare more bytes, but let's sleep over it ;-)
@arnolde: You were one of the best last year anyway, and now it's funny that we are three with the same code size (you,
@lightforce6128, me). I still think that I didn't use the same approach like my MSX friend from Finland, as he told me very strange crazy things (typical for him).
I agree with you, let's sleep over it :D
Quote from: Prodatron on 22:04, 17 December 23funny that we are three with the same code size
And 37 is also the same size as I had last year ;D ;D
Gute Nacht!
I can't wait to find out what approaches you all took.
I'm very interested in your algorithms. My approach is probably very naive compared with yours.
Quote from: lmimmfn on 21:24, 17 December 23Quote from: ervin on 07:27, 17 December 23Quote from: lmimmfn on 21:09, 16 December 23I spent some time analysing this in Java today just to get a quick analysis of the problem in a few mins.
It's fascinating and a brilliant problem at the same time.
After analysing the problem I just let my subconscious do its thing(sounds a bit mad but that's how I do most programming, let my subconscious do the heavy lifting and let my conscious know when there's a result, which in this case was Christmas shopping today lol).
Anyways for sure I have the concepts required to have the most effecent code to generate this, the intriguing thing is code wise it has huge optimization possibilities.
Sub 30 byte code is easily possible with potential to hit 20 bytes, that MSX guys 22 bytes should be achievable.
I'll give it a try tomorrow if I have time, otherwise after tomorrow the first person to PM me I will send the solution concept.
I can't imagine doing this in 30 bytes (or even 40), and certainly not 20!!!
And I've been staring at this pattern for days!
I'm not very good at obscure z80 tricks though, so that's a problem. :laugh:
i will eat humble pie, lol, while the routine i created is small i hadn't realised that the firmware calls and register corruption(all 4 with printing the cursor at a location) add about 10-12 bytes to the execution size.
Hats off to Prodatron and lightforce6128, i cant imagine on the CPC that it can be reduced further.
Without any optimization on the Z80 front i got 64 bytes(code in actual routine is very small vs overall size) but i'm quite happy with that :)
Yes, a few CALLs significantly increase the binary size :(
I was happy to find firmware routines that at least save all registers, so that I do not have to spent byte after byte for PUSH and POP commands.
I also considered to set up one RST to shorten the calls. But setting this up requires so many bytes, that it does not pay off for such a short program - at least not in my case.
To get the program this small, I had to make use of these rules (and maybe even bend them a bit :-[ ):
- No need to clear the screen.
- The object can be anywhere on the screen.
- You may write spaces.
- Prompt like READY may appear. No additional characters, which are not from the operating system itself
- The program may wait for key.
The usage of the last two rules is the scary part.
After
@arnolde wrote something about a "ridiculously simple approach", I'm a bit uncertain, if it is possible to reach the 37 bytes without this balancing act of interpreting rules. And if so, then maybe I could use this simpler approach AND apply the scary optimizations to press out even more bytes ... ;D
Quote from: lightforce6128 on 01:36, 18 December 23I was happy to find firmware routines that at least save all registers, so that I do not have to spent byte after byte for PUSH and POP commands.
I also considered to set up one RST to shorten the calls. But setting this up requires so many bytes, that it does not pay off for such a short program - at least not in my case.
Great tip 👍
On the rules, I was more struggling with "
The program may loop" and whether an infinite loop was OK lol
37 bytes? Heh
I was just pleased I've just managed to break 100 so far. It's very fun nonetheless
I'm stuck at 34, but in a not very beautiful version without cls.
Some tips:
If you are working with text coordinates, take a look at the Amstrad escape codes (ascii<32): sometimes it takes less bytes to output a newline character than a syscall for setting the cursor.
If you have free registers, store values that you use more than twice. So far, that's common sense, but if you play around with things like coordinate offsets of using counters the other way round you might find more possible constants.
Don't forget that if you have the negative of a value you need somewhere, you can sub instead of add and vice versa
Also, if you have a value that is 1 apart from the one you need, consider the possibillity of using adc or sbc in a place where carry is set.
Sometimes you get lucky and you find a value you can use in some register after a syscall.
And of course, always assign 16-bit values whenever possible (ld bc,&xxyy instead of ld b,&xx:ld c,&yy)
Had tried different approaches this days, all of them aligned to
@arnolde tips, but still way bigger...42 bytes best of them (with CLS) Need to try that ridiculously simple approach!! Let's see if I can find it...
really thinking outside the box here, but maybe cheating with a small screen height of 7 chars duplicated 3 times, but with 1 line for last 4th one might be an approach?
Every year at this time, I'm cursing Locomotive Software. They did a terrific job, but WHY ARE THE TEXT COORDS OF THE TOP LEFT CORNER NOT 0,0 ? ??? :picard2:
Well, I would like to see the quickest way to perform the task too. 8)
Quote from: GUNHED on 17:21, 18 December 23Well, I would like to see the quickest way to perform the task too. 8)
Why? That would be VERY boring and stupid and not a good cross-platform comparison at all.
On the CPC you mainly just copy a stupid bitmap,
and on most of the other 8bit platforms you just copy prepared patterns/texts (CPC will loose anyway in this case).
Quote from: lmimmfn on 13:40, 18 December 23really thinking outside the box here, but maybe cheating with a small screen height of 7 chars duplicated 3 times, but with 1 line for last 4th one might be an approach?
I was also thinking about this. Changing the "screen height" and "duplicated 3 times" sounds like a hardware effect. The main problem here would be to make the duplication stop after three screens. But changing the screen width should be less problematic and maybe helps to avoid newline handling at the end of a line. This can be done via hardware or with system text windows. The latter one can be influenced with the TXT pack (TXT WIN ENABLE, &BB66), with the BASIC command "WINDOW" or even with a control sequence (character 26).
Quote from: arnolde on 14:05, 18 December 23Every year at this time, I'm cursing Locomotive Software. They did a terrific job, but WHY ARE THE TEXT COORDS OF THE TOP LEFT CORNER NOT 0,0 ? ??? :picard2:
I think it is like this in most BASIC variants.
Quote from: Prodatron on 21:33, 18 December 23Quote from: GUNHED on 17:21, 18 December 23Well, I would like to see the quickest way to perform the task too. 8)
Why? That would be VERY boring and stupid and not a good cross-platform comparison at all.
On the CPC you mainly just copy a stupid bitmap,
and on most of the other 8bit platforms you just copy prepared patterns/texts (CPC will loose anyway in this case).
Optimizing for size requires compromises that really hurt if you are used to optimize for speed. With some of the approaches I tried you can easily see how slow the graphics build up, although it is an assembler program (that makes heavy use of system routines and does some tasks multiple times). So besides smallest size (which heavily depends also on the available OS routines on the target platform), for one target platform (CPC) I would also like to see if there is a small solution that is also fast.
But this just out of curiosity, the challenge is clearly about optimizing size (and optimizing beauty in the side challenge).
Ooopsie, I just noticed: The rules state that we are not allowed to publish the size of our code, so we should stop bragging about who has the smallest ;) (Size, as we all know, doesn't matter anyway, it's about what you are doing with it :P )
So, just for the record: The size I mentioned earlier in this forum is NOT the size of my final submission.
Quote from: arnolde on 10:44, 19 December 23So, just for the record: The size I mentioned earlier in this forum is NOT the size of my final submission.
So, in line with the anatomical analogy provided, if you allow me, you can now state to have a micro penis? Amazing! I wish I could had too. Surgery please! :P
Quote from: Prodatron on 21:33, 18 December 23Quote from: GUNHED on 17:21, 18 December 23Well, I would like to see the quickest way to perform the task too. 8)
Why? That would be VERY boring and stupid and not a good cross-platform comparison at all.
On the CPC you mainly just copy a stupid bitmap,
and on most of the other 8bit platforms you just copy prepared patterns/texts (CPC will loose anyway in this case).
So, Programming quick is ' VERY boring and stupid' in your opinion?
Quote from: GUNHED on 17:56, 21 December 23So, Programming quick is ' VERY boring and stupid' in your opinion?
I think it's more that, in this specific case, the quickest solution is probably not interesting because you can just throw RAM at it. Probably just setting a few registers and then a big chain of PUSH instructions.
Now, doing it in some other clever way might be more intriguing. What's the least amount of screen RAM you can use (by repeating blocks) etc might lead to more ingenious thinking.
Well, 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. ;) :)
Of 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.
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.
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.
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. :)
"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...
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?
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?
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
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.
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.
Oh, i'm excited only 39 mins to go
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
Congratulations as well, chapeau to the other entries, especially to the other CPC ones!
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
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.
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
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
;
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 (http://www.sizecoding.org/wiki/Commodore_64#Program_file_overhead)). 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.
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.
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
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
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 ).
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)
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
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
Quote from: Urusergi on 22:20, 11 January 24To improve the speed a bit you can take the ret out of the loop
Optimizing the CPU on this exercise does not help much and that is not the objective.
It's a question of scale. ;)
Each character is displayed either 256 times or 128 times with BB5A, or approximately 840,000 µsec for each use of B (58 times x 840,000).
Gaining 116 µsec isn't really useful. ::)
Quote from: Overflow on 17:15, 11 January 24Also 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).
Rings some bells (ah! see what I did there?). In CPCT uncruncher I used the relative "n" in JR cond,n as an opcode. Twice I believe.
Targhan was flabbergasted after disassembling the routine.
Long story short, the beauty is appreciated.
Quote from: Longshot on 00:42, 12 January 24Optimizing the CPU on this exercise does not help much and that is not the objective.
It's a question of scale. ;)
I expected it. There is always someone who has to answer the obvious ;)
Of course, any loop that involves calls to the firmware doesn't improve much. This is more of a crusade, an attempt to get us all to program more efficiently.
I've been studying commercial game code for three or four years and it's horrible, a real disappointment, since I really believed that they were very professional.
Although thanks to that I've been able to optimize the necessary bytes to be able to enter my code in the GX4000 conversions ;D