One Sunday afternoon with nothing to do I set about writing a program in
8086 assembler that bounces a ball around the screen. I wanted to see how
small I could make it. I was surprised at how small I could actually get
it. I then gave this problem to our third year students who had just
completed a course in assembly programming.
The rules were basically:
1. The ball must bounce in a fashion similar to a given algorithm.
Basically:
Initialize x, y
x1=1
y1=1
Loop:
gotoxy (x,y)
print "0"
delay (1)
gotoxy (x,y)
print " "
x=x+x1
y=y+y1
if (x < 2) or (x > 79) x1 = -x1
if (y < 2) or (y > 24) y1 = -y1
goto Loop
2. The ball need not be the same character between iterations (hint: xor)
3. The screen contents (sp?) must not be destroyed by the ball.
4. The program must bounce the ball round at a speed that makes the path
clearly visable. (An empty delay of 65536 on my 486 is fine).
4. The program must terminate gracefully and return to DOS if the ESC
key is pressed.
My first attemptcame in at 56 bytes. The students were quite creative
and knocked several bytes off. One came in at 15 bytes. Using the mouse
cursor and bouncing the ball by hand. :-)
The idea is not to cheat on the rules, but to get a really small program ;)
Well, any takers? I'll give you some time to think, and then I'll post our
smallest programs.
Regards
Stefan
--------------------
swes...@cs.up.ac.za
I guess you mean on a graphics screen, huh? What screen mode? CGA? VGA? EGA?
And 56 bytes ... that's pretty small ... I'm interested 8-)
-spc (Should be working, but ... 8-)
with interest I have read Stephan Wessels' challenging post and I have
given it a try, without beating Stephan by the way. But I thought,
perhaps someone could go further from here, and perhaps Stephan could
give some comments. I worked on this for about 3 hours now and I don't
see how it can be shrunk. But it is a nice competition.
I look forward to any other "solutions".
Regards,
Wimjan Jansen van de Laak
kug...@kuhub.cc.ukans.edu
"War doesn't decide who is right, just who is left." - unknown
--------8<--------8<--------8<--------8<--------8<--------8<--------8<--------
; ball program - my try.
code segment para public 'Code'
assume cs:code, ds:code
org 100h
ProgStart:
xor dx,dx ; dx = x and y
AnotherTime:
mov ah,1h ; KeyPressed?
int 16h
jnz TheEnd ; yes -> TheEnd
GotoXY:
mov ah,02h ; x and y are in dx
int 10h
GetCurrChar:
mov ah,08h ; get char at current cursor location
int 10h
mov ah,0eh ; prepare ax for later
push ax ; and save it
PrintBallOrSo:
xor al,96 ; change the "ball"
int 10h ; and print it to the screen
DumLoop: ; some delay
loop DumLoop
GotoXYAgain:
mov ah,02h ; x and y still in dx
int 10h
PrintPrevChar:
pop ax ; restore prev char
int 10h
inc dl ; x = x + 1
RevXoffs equ $-1
jz ReverseX ; if x == 0 then reverse delta x
cmp dl,79 ; also if x is getting too big
jb TestY
ReverseX:
xor byte ptr [RevXoffs],8 ; switches between "dec dl", "inc dl"
TestY:
inc dh ; y = y + 1
RevYoffs equ $-1
jz ReverseY ; if y == 0 then reverse delta y
cmp dh,23 ; getting too big? then also reverse
jna ToTheStart
ReverseY:
xor byte ptr [RevYoffs], 8 ; switches between "dec dh", "inc dh"
ToTheStart:
jmp short AnotherTime
TheEnd:
ret
code ends
end ProgStart
--------8<--------8<--------8<--------8<--------8<--------8<--------8<--------
width equ 80 ;width used; 160 bytes/line still assumed
height equ 25 ;height to use
ball equ 'O' ;character for the ball
main:
mov ah,0b8 ;al=0 **PROVIDED** no command-line params!
mov es,ax ;es=screen segment
xor di,di ;start at origin of screen
mov bl,162 ;offset to next position (bx=0 for .COM file)
mov dx,(width-1) by (height-1);no. of columns (dh)/rows (dl) left
l0:
mov al,ball ;ball character
xchg b es:[di],al ;store ball on screen, and get original byte
loop $ ;delay (cx=0 at start of .COM file)
stosb ;store original character back
lea di,[di+bx-1] ;di=di+bx-1=next screen position
dec dh ;column count
jz >l1 ;all columns done -- swap x
dec dl ;row count
jnz >l9 ;another row -- don't swap y yet
mov dl,height-1 ;dl=count
neg bx ;swap y-direction
jmp >l2 ;need this done, too
l1:
dec dx ;1 byte smaller than dec dl
mov dh,width-1 ;reset this
l2:
xor bl,60 ;swap x-direction
l9: ;jump to here to check key then repeat
mov ah,1 ;check keyboard buffer non-destructively
int 016
jz l0 ;no key, so repeat
ret ;come here when done -- 0 is already on stack.
>This was the best I could get it down to; it's 49 bytes long.
>width equ 80 ;width used; 160 bytes/line still assumed
>height equ 25 ;height to use
>ball equ 'O' ;character for the ball
>main:
> mov ah,0b8 ;al=0 **PROVIDED** no command-line params!
> mov es,ax ;es=screen segment
> xor di,di ;start at origin of screen
> mov bl,162 ;offset to next position (bx=0 for .COM file)
> mov dx,(width-1) by (height-1);no. of columns (dh)/rows (dl) left
"xor di,di" could be replaced by "pop di" for a .com file and thus saving
one byte. Is Bx=0 officially ensured for a .com file?
Morten Welinder
te...@diku.dk
--
-------------------------------------------------------------------------
Visit the lyrics archive at ftp.uwp.edu (mirrored to nic.funet.fi, a site
in Finland). All kinds of lyrics available -- upload "yours" and join.
-------------------------------------------Morten Welinder, te...@diku.dk
>cah...@nyx.cs.du.edu (Chris Hall) writes:
>>This was the best I could get it down to; it's 49 bytes long.
>>width equ 80 ;width used; 160 bytes/line still assumed
>>height equ 25 ;height to use
>>ball equ 'O' ;character for the ball
>>main:
>> mov ah,0b8 ;al=0 **PROVIDED** no command-line params!
>> mov es,ax ;es=screen segment
>> xor di,di ;start at origin of screen
>> mov bl,162 ;offset to next position (bx=0 for .COM file)
>> mov dx,(width-1) by (height-1);no. of columns (dh)/rows (dl) left
>"xor di,di" could be replaced by "pop di" for a .com file and thus saving
>one byte. Is Bx=0 officially ensured for a .com file?
Don't know about whether BX=0 is guaranteed, but it seems to be true.
However, doing the "pop di" is a very good way to lock up the computer
when the program terminates; did the original poster require a well-
behaved program (as well as being short :-)?
And how about correctness? It turns out that if you let the program run
long enough, the ball eventually reaches the lower left corner of the
screen and is eaten by a black hole. Chris Hall tried to finesse things
by using the same "xor" for both the change in x- and y-directions;
however, at the corners, the "xor" has to be done *twice*. What's
interesting is that if you fix the logic, the program is still only 49
bytes long; the correct code is given below. Enjoy!
-Alan
;
; 49-byte code to display a ball bouncing off the edges of the screen. The
; logic and first version originated with Chris Hall (cah...@nyx.cs.du.edu);
; however, it did not handle corners correctly, requiring a simple
; modification of the code by Alan Raskin (ras...@fafner.physics.umanitoba.ca)
; which amazingly did *not* increase the size of the executable.
;
code SEGMENT PARA PUBLIC 'Code'
ASSUME cs:CODE, ds:CODE
ORG 100h
wwidth EQU 80 ; width used; 2 bytes/character assumed
height EQU 25 ; height used
ball EQU 001 ; character for the ball (happy face)
start:
mov ah, 0b8h ; 2 - AL=0 if no command-line parameters?
mov es, ax ; 2 - ES=screen segment
xor di, di ; 2 - start at origin of screen
mov bl, 2*(wwidth+1) ; 2 - offset to next position (BX=0 for
; .COM file?)
mov dx, (wwidth-1)*256+(height-1)
; 3 - # of columns (DH) & rows (DL) left
; before change in direction
l0:
mov al, ball ; 2 - load ball character
xchg es:[di], al ; 1+2 - get original character, and
; store ball on screen
loop $ ; 2 - delay (CX=0 at start of .COM file)
stosb ; 1 - store original character back
lea di, [di+bx-1] ; 3 - DI+BX-1=next screen position
dec dh ; 2 - decrement column count
jnz l1 ; 2 - another column -- don't swap x yet
; for a bounce off of the left or right side of the screen, BX changes in
; magnitude from 162 to 158 (or vice versa) with no change of sign; this is
; accomplished by an exclusive or:
;
; 162 = 1010 0010
; 158 = 1001 1110
; 3Ch = 0011 1100
mov dh, wwidth-1 ; 2 - reset column count
xor bl, 3Ch ; 3 - swap x-direction
l1:
dec dl ; 2 - decrement row count
jnz l2 ; 2 - another row -- don't swap y yet
; for a bounce off of the bottom or top of the screen, BX changes in magnitude
; as before, but also changes in sign
mov dl, height-1 ; 2 - reset row count
neg bx ; 2 - start to swap y-direction...
xor bl, 3Ch ; 3 - done!
l2: ; jump to here to check if key
; has been pressed
mov ah, 01h ; 2 - load fcn. # for Get Keyboard Status
int 16h ; 2 - call keyboard interrupt
jz l0 ; 2 - if key not pressed, repeat
ret ; 1 - otherwise exit
code ENDS
END start
Version 1 : 42 Bytes
Version 2 : 37 Bytes
Version 1
----------
code segment para 'code'
org 100h
assume cs:code,ds:code,ss:code
begin:
xor dx, dx
mov bl,01h ; Col inc
mov ax,0201h ; ah = Set Cursor, Al = Row inc
Main: add dl,bl ; Cols inc/dec
jz Wrap ; Left hand side of screen?
cmp dl,79 ; Right hand side of screen
jne NoWrap ; Nope
Wrap: neg bl ; Swop direction
NoWrap: add dh,al ; Rows inc/dec
jz RWrap ; Top of screen? Zero=y=swop dir
cmp dh,24 ; Bottom?
jne NoRWrap ; no
RWrap: neg al ; swop direction
NoRWrap:
int 10h ; position cursor
Delay: loop Delay ; delay to make visable
push ax
in al,60h ; read keyboard controller
cmp al,1 ; ah = 1 = ESC key pressed
pop ax
jnz Main ; ah <> 1 - Continue
ret ; return to DOS
code ends
end begin
Version 2
----------
; code by Rudi Engelbrecht
;
CODE_SEG SEGMENT PARA 'Code'
ASSUME CS:CODE_SEG
ORG 100h
Toets PROC NEAR
mov bx, 0008h
mov dx, bx
STARTLOOP:
mov di, offset MODIFY+1
cmp dh, 24
jb @@99
NEXT:
xor byte ptr [di], bl
@@99:
TEMPLOOP: loop TEMPLOOP
MODIFY:
inc dh
inc dx
inc di
mov ah, 02h
int 10h
cmp dl, 4Eh
ja NEXT
; Get keyboard character
KEYBOARD:
mov ah, 01h
int 16h
jz STARTLOOP
ret
Toets ENDP
EINDE:
CODE_SEG ENDS
END Toets