Code Density Alone Coder As you remember, in Inferno #3 Shiru opu─ glare Snake length 255 bytes, and in Info Guide #10 I published a simplified one Snake length 121 bytes. It was written in codes calculator Basic 48 and seemed quite dense. However, thenFirestarteroffered co─ completely new algorithmSnake.He didn’t write to the editor, he wrote onHabr,and then here I deleted the article. But save the source itself─ l.s. The game took93bytes, but it worked yes. All the "rabbits" are scattered across the field already at the beginning of the level and are stored directly─ especially in the screen attributes. Array with core─ There are no snake dinatas either, there is only go─ fishing that movesand a certain definition is drawn─ line attribute code meaning “adult─ "loyalty" of the snake. I reduce every game frame─ there are attribute codes throughout the playing field, except for empty spaces and rabbits. It turns out that behind the head there is a trace - a “tail”, a collision with which ends in pla─ obviously. The more mature the snake, the longer it is this tail. And if she grew up to a certain level─ level, corresponding to full absence of rabbits on the field, then the game begins─ appears first (but there is no point in this). Thus, you only need to write ef─ efficient rabbit generation code, checks cells in the position of the future head, decrement colors while counting rabbits and key polling. After Firestarter abandoned the project disappeared, the source code was optimized krt17. He got 85 bytes same behavior. But it was clear that85bytes - not the limit. Moreover, it is known that IBM PC Game mat 64byte, and Nibbles (snake that ra─ always walks, without rabbits or tail movement─ that) from the competitionHugi compo - total 48 bytes. After preliminary acquaintance with version fromkrt17I won a few bytes by changing the order of pieces of code. Then took registers into account when calling from BASIC. But this It was not the most important reduction. Op code─ the dew of the keys remained quite greasy (after─ lui, fatter than in mine Snake121 ). And I stepped in the most radical way - keyboard─ Our controls are chosen in such a way that translated into delta head movement most briefly: sub (hl):ld c,a:sbc a,a: ld b,a. To do this, I had to choose enough─ but the original control keys are "," left, "." right, ENTER up, M down. The result was worth it - 55 bytes,tremble, pussies! At the last moment I discovered that I could─ but win a couple more bytes if you serve collision with a tail that still exists─ it does, but is already visible as black. So in in the source code you can switch two options - 55 bytes and 53 bytes! ;Alone Coder 53/55 bytes 11/10/2020 ;from basic: ;de=0x5d83/5dcc, hl=0x2d2b, bc=start ;from TR-DOS RUN "..." CODE: ;de=0x5d83, hl=0x2d2b, bc=start l1 ld d,0x5b if 1==0 ;55 bytes ld a,(hl) inc a cp 9 jr nc,restart ;collided with visible ;tail else ;53 bytes ;a=0xff in most cases add a,(hl) cp d ;0x5b jr c,restart ;collided with visible ;or invisible tail endif ld a,h inc a and 00000011b ;screen margin jr nz,norestart restart ;at restart: e=0xff, d=0x5b ld h,d ;0x5b rabbit1 ld a,r ld (hl),e ;0xff cpl jr z,rabbit2 inc (hl) ;0x00 rabbit2 dec hl bit 3,h jr nz,rabbit1 ;l=0xff ;bc=direction (delta) inc h ;0x58 norestart ld (hl),0x2d ;0x21 ;head ;, LEFT ;. RIGHT ;ENTER UP ;M DOWN ld a,(23560) sub (hl) ;0x2d ld c,a sbc a a ld b,a ;bc=1/-1/32/-32 ;ld d,0x5a move1 ld a,(de) dec a cp 0xfe jr nc,move2 ;was 0xff = rabbit ;or 0x00 = empty ld (de),a ;move snake ;(decrease colour) move2 jr nz,move3 dec (hl) ;was 0xff = uneaten rabbit, ;so decrease snake size ;(head color) move3 dec de bit 6,d jr nz,move1 ;e=0xff ;d=0x3f add hl,bc jr l1 * * * Пожалуй, самым коротким Тетрисом для Спектрума долгое время был Impetris - пла─ гин для ACEdit. Занимал он 745 байт, кидал цветные фигуры, показывал следующую, счи─ тал очки (они даже прыгали на экране) и даже ускорялся по мере прохождения. Что касается прыгающих очков и ускорения, это было довольно излишне в этом классе, да и остальное выглядит необязательным для ре─ корда. А рекорд на IBM PC кpresent time dropped below256 bytes (without under─ points count). What can we do? I took as a basis notImpetris,but Tetris from NedoOS.There was quite loose, but very clear code, previously written in two hours as a tutorial. I did the work on the stream, or rather, on two streams - posko─ lku Tetris is really not bad for the game─ assembly language lessons. For example, what I did: - replaced the coordinates of the figure with the address. - combined drawing and erasing procedures and checks. - combined the procedures storeposition and restoreposition. -reduced key polling to a minimum. - optimized search and removal of complete ones lines (contrary to intuition,CPIRdid not help!) I stopped streaming when I reached256 byte. But I couldn't decideShould I leave the walls? (their absence led to looping fields and the inability to show the score). But then they suggested a simple procedure for me─ chat, and a few more came to mind ideas, so the final version fits 256 bytes along with display of the score, that is turns out better than the version forIBM PC! Please note: the game expects that at the beginning of the printer buffer (0x5b00) lie zeros, as required on a48K machine. Cro─ besides, again, as it should be, ek─ the wound is filled with the attribute0x38.Memory after The program is also considered empty. The shapes take1bytes for each, except the last one, and the first two are even used as a parameterjp. The walls are at a distance 16 know─ places apart from each other to draw them one cycle, not two (the bottom is guaranteed printer buffer). And you can even play it! ;Alone Coder 02.28.12.2020;48K or usr0 only! ;(0x5b00..5b1f must be clean) SCORE=1 WALLS=1 if WALLS fieldwid=16 else fieldwid=32 endif fieldhgt=24 fieldx=16-fieldwid/2 fieldy=0 addrDropFig=0x580c emptyattr=0x38 newfig=%0110011011000110 if WALLS ;begin=0x6100-(fieldx-1)-16 begin=newfig-13 else begin=newfig endif display "begin=",begin,"=",/D,begin ;hl=0x2d2b ;de=0x5dxx ;bc=begin ;hx=0 ;iy=0x5c3a ;bc'=0x1114 ;hl'=10072 if WALLS xor a ld hl,0x5800+(fieldx-1) ld (hl),a ld de,0x5800+(fieldx-1)+fieldwid ;ld b,2 ;bc,0x300-(fieldx-1)-32 ld bc,0x300-(fieldx-1)-16 ldir ;newfig endif if (WALLS == 0) && (SCORE == 1) ld (iy+86),0xff endif ld a,r and 7 ld hl,figs add a,l ld l,a xor a ld de,curfig ld (de),a inc de ld b,3 ;- rld ld (de),a inc de ;e djnz $-4 ld hl,addrDropFig ld (curxy),hl gameloop ld a,prfig_pixel&0xff ;proc addr call prfig_curxy halt halt halt ld a,prfig_clearpixel&0xff ;procaddr call prfig_curxy ;nz!!! call storeposition_ldir ;bc=0 ld hl,(curxy) ld (oldcurxy),hl ld hl,(curxy) xor a ;z! in a,(0xfe) rra ;'q' jr c,$+3 dec l rra ;'w' jr c,$+3 inc l ;rra ;'e' ;jr nc,godown ;bug with right+down!! nodown jr nz,noautodown ;left or right ;pressed - don't fall exx rlc b ;was 0x11, then random(?) with ;few bits on exx jr nc,noautodown godown ld c,32 ;also flag for stopfig add hl,bc noautodown ld (curxy),hl rra ;'e';'r' jr c,norotfig ld hl,curfig ld sp,hl pop bc pop de ld sp,hl rotfig0 xor a rr c rla rr b rla rr e rla rr d rla ld (hl),a inc l jr nz,rotfig0 ld c,l ;0 ;or else rotation near a ;wall can stop fig!!! norotfig ld lx,c ;32=stopfig for godown, ;0=no godown ld a,prfig_checkpixel&0xff ;procaddr call prfig_curxy ;z=collision call z,restoreposition ;can't move ;in that direction jr nz,gameloop ;no collision ;a=0 cp lx ;32=stopfig for godown, ;0=no godown jr z,gameloop ;collided not with gnd stopfig ld hl,(oldcurxy) ld a,prfig_pixel&0xff ;proc addr call prfig ;search a filled line from above ;if found, shift down (with lddr) ;ld hl,0x5800+fieldx-1 ;ld lx,fieldhgt ld hl,0x5a00+fieldx-1 ;only lowest 8 ;lines can be fired finddellines0 xor a ;for "or (hl)" ld b,fieldwid checkfilledline0 inc hl or (hl) djnz checkfilledline0 jr nz,finddellines_nofire ;ld a,emptyattr ;ld bc,fieldwid ;cpir ;jr z,finddellines_nofire ;extrabyte ;hl=last byte of current line push hl ex de,hl ld hl,-32 add hl,de ld a,h sub 0x58 ld b,a ld c,l ;bc=(y-1)*32 ;bc=hl-#5800=de-#5820 lddr if SCORE inc hx ld c,hx ld a,22 rst 16 ;requires iy=23610 xor a rst 16 rst 16 ;call 11563 ;call 11747 call 0x1a1b ;print bc endif pop hl finddellines_nofire ;ld de,32-fieldwid ;add hl,de ;xor a ;for "or (hl)" in next line ;dec lx ;jr nz,finddellines0 ld a,l add a,32-fieldwid ld l,a jr nc,finddellines0 if SCORE ;ld b,hx ;lines fired (0..4) ;inc a ;ld c,1 ;if there are fired ;lines, c=0 (if there aren't, ;c<<256 = 0) ;add a,a ;djnz $-1 ;a=2,4,8,16 ;exx ;add a,h ;ld h,a ;exx ;ld c,a ;ld a,22 ;rst 16 ;requires iy=23610 ;xor a ;rst 16 ;rst 16 ;call 11563 ;6683 ;call 11747 ;- endif ;if WALLS ;jp newfig ;else db 0xc3 ;endif figs display "figs=",figs db %11000110 ;zigzag2 db %01100110 ;square db %00110110 ;zigzag1 db %11110000 ;I db %00101110 ;L db %01000111 ;J db %01001110 ;T db %01001110 ;T (8 figs) nfigs=($-figs) display "nfigs=",nfigs restoreposition ;z ld hl,(oldcurxy) ld (curxy),hl storeposition_ldir restoreposition_ldir ;nz=store ;z=restore ld bc,4 ld de,curfig ld hl,oldcurfig jr z,$+3 ex de,hl ldir prfig_clearpixel ld (hl),emptyattr ret prfig_pixel ld (hl),0 prfig_checkpixel and (hl) ret prfig_curxy ld hl,(curxy) prfig ;NC!!! ld (prfig_calladdr),a or h ;(a&8) != 0 ld de,curfig prfig_lines ex de,hl ld b,(hl) ;%0000pppp set 4,b ;%0001pppp ex de,hl prfig_pixels prfig_calladdr=$+1 call c,prfig_pixel inc hl ;x srl b ;pixel jr nz,prfig_pixels ld c,32-5 add hl,bc inc e jr nz,prfig_lines or a ret end ;это конец файла игры! curxy dw 0 oldcurxy dw 0 align 256 ds 256-4 curfig ds 4 nop ;for spoiling oldcurfig ds4 * * * Many have seen the ray trace source on BASIC, which counts two balls 8cha─ owls This source flashed on the Internet in2018 and disappeared, but made me think─ Xia: what speed can you expect? in assembler, and is it possible to fit the render into 1 kilobyte (procedural graphics genre)? To check, I did the following: om: - first rewrote this render in C++ Builder and got the correct picture. - then replaced the floats with 32-bit ones─ ly numbers. -then rewrote the code for compatibility withNedoLang. - moved the code to NedoLang and added it to performance. - procedures compiled by NedoLang into assembler, optimized one after another. - determined the required ranges of numbers and ne─ I rewrote everything to 16-bit integers. -only after that began to drive into the ki─ lobyte taking into account the compressor (Hrum turned out better than MegaLZ ) and add small op─ timization to be on the edge. Pos─ The latest optimization was on-the-fly calculation squares, beyond which you definitely will not go─ balls are moving. (I did not enter these times─ measures firmly and even made a version from anime─ tion.) So, my result (demonstrated on Cosmonautics Day in 2019 year): exactly 1024 bytes, less than 71 seconds at the Pentagon. Acceleration400times at the same resolution 256x176,as in the original! It’s interesting thatDaniel A.Nagyalso provo─ did the same experiment, but used your library of 2-byte floats (lpfp). Its version is packaged about 4 kilobytes and renders the screen more than5 minutes, with the quality just a little bit better, than in our 16-bit integers... I’ll save my version as a keepsake in the app─ marriage. The color version is in the repository NedoOS. Maybe someone can speed it up or come up with a useful application for this raytrace? * * * There were a few more interesting things on Hugi compo resin size compo: -evaluating expressions with +-*/ , brackets and unary +- ( 117 bytes) -gamePong ( 142 bytes) - game "tic-tac-toe" ( 213 bytes) - game Sokoban with a given map ( 189 byte) - interpreter brainfuck ( 98 bytes) - search for prime numbers up to a million ( 76 byte) There are also known records for the size of the shah─ matte programs (several less versions 512 bytes, game qualitywhich are yet to come─ worth comparing) and in terms of the size of the hatch lo─ gotype Unix ( http://www.deater.net/weave/ vmwprod/asm/ll/ll.html - however, the code for Z80 is written very poorly there). Usually x86 outperforms all others processors. But does this mean that it is impossible come up with a tighter command system? Of course not. There's quite a lot of bits in there is spent on specifying register numbers, addresses and word width. The byte size itself in 8bit is also not necessarily ideal. Commands can be shorter, up to4 bits per station─ kov processor. I conducted such an experiment in a newspaper ACNews #59;then I finished this engine, but never used it; then I tried to write stack processor with 4-bit instructions and forFPGA. My last thought on interpretability─ mu stack processorlooked like this (with─ absolutely not tested for functionality─ ness): ;for conditions, outputs and branches 3 commands ; jrNC N, ifZ{scf} ;for mathematics 4 commands ; sub, add, sub1, inc(+rcf) ;for stack 3 commands ; push(dup), pop(skip), swap ;for variables 4 commands: ; getvar N, putvar N, peek8, poke8 ;3 commands to control ; callr N, ret, z80 (z80 allows you to further write machine code) ;enter the script using rst #10, for this you need ;patch the address in the channel descriptor #5cb6 ;(#5d26 in TR-DOS) ;104b: _startscript pophl ;skip #15fe (return from call ;#162c) pop hl ;restore hl' exx ;de=вершина стека pop hl ;address after RST #10 _callq: ld c,0x55 _getcmd: ld a,(hl) rlc c jr nc,$+2+5 ;первый раз не сдвигаем rrca rrca rrca rrca inc hl and 15 ret z ;0=ret ;флаги сейчас в f', ;на выходе из call они достанутся ld b,a push hl ;return addr ld l,(hl) ;read 8bit djnz _ncall ;1 ;call N ;lies at the end of the byte, so now ;c=0x55, hl=next byte call jphl ;jp (hl);call machine code ;procedure ;output flags in f' _popincq ;flags are now in f' pop hl ;return addr after call-ret inc hl ;skip 8bit jr _callq ;can be converted to ;push bc... pop bc (slower, but ;does ex af,af') _ncall: ld h,vars/256 djnz _nputvar ;2 ; putvar N: (var)<=reg (do not delete it, ;otherwise there's an extra pop) ;lies at the end of the byte, so now ;c=0x55, hl=next byte ld (hl),e inc hl ld (hl),d jr _popincq ;can't throw away _nputvar: djnz _ngetvar ;3 ; getvar N: reg<=(var) (overwriting the old one ;TOS, otherwise there is an extra push - but without it you can ;merge branches) ;lies at the end of the byte, so now ;c=0x55, hl=next byte ld e,(hl) inc hl ld d,(hl) jr _popincq _ngetvar: pop hl ex af,af' ;flags djnz _njrnc ;4 jr c,_getcmd ld l,(hl) _njrnc: djnz_npush ;5 push de _npush: djnz _npop ;6 pop de _npop: djnz _nswap ;7 ex de,hl ex (sp),hl ex de,hl _nswap: ex (sp),hl djnz _nsub ;8 ;reg<=pop-reg-CY ;_oldminusnew sbc hl,de _nsub: djnz _nadd ;9 ;reg<=reg+pop add hl,de _nadd: djnz _nsub1 ;A ;sub1 scf ld d,b ;0 ld e,b ;0 sbc hl,de _nsub1: ex de,hl pop hl djnz _ninc ;B ;inc(+rcf) inc de or a _ninc: djnz _npeek8 ;C ;peek8 ;можно сделать h<-l<-(hl)? ld l,(hl) ld h,b ;0 _npeek8: djnz _npoke8 ;D ;poke8 ld a,l pop hl ld (hl),a _npoke8: djnz _nifzscf ;E ;ifZ{scf} jr nz,_nifzscf scf _nifzscf: ex af,af' ;flags djnz _getcmd ;F ;z80 - no output to _getcmd ;lies at the end of the byte, so now ;c=0x55, hl=next byte jp (hl) We, of course, do not believe in fantastic numbers like "The code for the M-machine was in three─ three times less code for PDP-11 and i8086 two to three times less code for Motorola 68000 and one and a half to two times less code for National Semiconductor 32000",but what the hell not kidding? After all, teams can even be floating length. And if you sharpen it at all processor for a specific task (for example─ measures, matrix calculations), then the program for it may be half as much as for regular CPU: https:// nabbla1.livejournal.com/234532.html But the question is: if you didn’t depend on those─ current command systems and ready-made compilations─ ditch, and they designed it themselvesprocessor, then ka─ What command system would you suggest? Auto─ ryRISC-Vclaim that despite the request─ this command system, they have reached density code is no worsex86.Is this really true? le? Is it possible to somehow prove “almost-opti─ smallness" of the command system in size for typical tasks? For example, what is more than 10% can no longer be reduced at the given limits─ tions (say, no more than256 commands)? Write your thoughts!
Share your thoughts about the article