So for some reason I had the idea that I wanted to make a version of snake that fit within 256 bytes, in assembly. I ended up with this!



I spent a few hours optimizing and adding some minor features, and now here's the new version


I of course have a wait loop to slow it down because otherwise it's unplayably fast. (it almost is too fast as it is)

I'm quite happy with how it turned out, even getting a score counter in there.
Here's the source (assembled with BRASS). It's not very well commented but tomorrow I'll see if I can comment it up for you. I'll also upload it to the archives if anyone wants to try it.


Code:

.nolist
#include "ti83plus.inc"
#include "dcs7.inc"
.variablename SNAKE
.list
.org UserMem - 2
.db t2ByteTok, tAsmCmp
    xor d
    ret
    jr main
    .dw 0000h ;Description
    .db $07, $00
    .dw 0000h ;Icon
    .dw 0000h ;ALE

.dw $BEEF ;I have 2 extra bytes left, everyone loves beef!

;Positioning is important here.
;I want to be able to inc my way from FOOD_POS to HEAD_POS,
;from HEAD_OFF to TAIL_OFF, from GROWTH to BSIZE, from BODY_X to BODY_Y
;I also want to be able to dec from GROWTH to TAIL_OFF
FOOD_POS = saveSScreen
FOOD_X = FOOD_POS + 1
FOOD_Y = FOOD_POS

HEAD_POS = saveSScreen + 2
HEAD_X = HEAD_POS + 1
HEAD_Y = HEAD_POS

HEAD_OFF = saveSScreen + 4
TAIL_OFF = saveSScreen + 5

GROWTH = saveSScreen + 6
BSIZE = saveSScreen + 7

VEL = saveSScreen + 8
VEL_X = VEL + 1
VEL_Y = VEL

TEXT = saveSScreen + 10

BODY_X = 8000h ;appData
BODY_Y = 8100h ;ramCode

INITIAL_LEN = 4 ;First food gen increases to 5

main:
    b_call(_ClrLCDFull)
    ld hl,InitialData
    ld de,HEAD_POS
    ld bc,InitialDataEnd - InitialData
    ldir
    set textWrite, (iy + sGrFlags)

    ;Draw border of board
    ld hl,64 << 8 ;X=64,Y=0
    ld d,h ;X=64,Y=64
    ld e,h
    call fastlineb
    call growAndGenFood

gameLoop:
    ld de,0
    b_call(_GetCSC)

    cp skClear
    ret z
inputKeys:
    dec a ;Down key
    jr nz,$+3
    inc e

    dec a ;Left key
    jr nz,$+3
    dec d

    dec a ;Right key
    jr nz,$+3
    inc d

    dec a ;Up key
    jr nz,$+3
    dec e

    dec a ;Wrap around from up key
    cp 252 ;If Down was pressed, A will be 252. If it's less, ignore key press
    jr c,noInput

    ld hl,VEL_Y
    ld a,(hl)
    and e
    jr nz,{@}
    ld (hl),e
    @:

    inc hl ;VEL_X
    ld a,(hl)
    and d
    jr nz,{@}
    ld (hl),d
    @:
noInput:
    ld hl,(VEL) ;H = VelX, L = VelY

    ld de,HEAD_POS+1 ;HEAD_X
    ld a,(de)
    add a,h
    and 31 ;Clamp X to board (wall wraparound)
    ld h,a
    ld (de),a

    dec de ;HEAD_Y
    ld a,(de)
    add a,l
    and 31 ;Clamp Y to board (wall wraparound)
    ld l,a
    ld (de),a

    ld de,(FOOD_POS)
    call cphlde ;Test if head position = food position
    push af ;Save flag for decided whether or not to fill in head
    push hl ;Save head position

    ld bc,noCollisionCheck ;Save return spot to stack
    push bc
    jr z,growAndGenFood ;Jump to growAndGenFood if head pos == food pos

;COLLISION CHECKING
;No food gen, so check for collision. HL contains head position
    add hl,hl
    call pixeltesthl
    ret z ;noCollisionCheck is still on stack, so we can use this to jump to it if we didn't collide

;End game due to collision
    ;Pop return addr, head pos, flags
    pop hl
    pop hl
    pop hl
    ret
;END COLLISION CHECKING

noCollisionCheck:
    ld hl,GROWTH
    dec (hl)
    jr nz,{@}
    inc (hl)
    dec hl ;HL = TAIL_OFF
    inc (hl)
    call DispBodyPart
    @:

    pop de ;Current head position

    ld hl,HEAD_OFF
    inc (hl)
    ld c,(hl)
    ld b,BODY_X >> 8
    ld a,d
    ld (bc),a

    inc b
    ld a,e
    ld (bc),a
    pop af ;Z will be set if we ate food
    call nz,DispBodyPart
    call ifastcopy ;re-enables interrupts

    ld a,1800/22
    @:
    djnz $+0
    dec a
    jr nz,{-1@}
    jr gameLoop

growAndGenFood:
    ;Set pen position for displaying score
    ld hl,(4 << 8) | 70 ;32 = pen row, 70 = pen col
    ld (penCol),hl

    ld hl,GROWTH
    inc (hl)

    ;Increment and display score
    inc hl ;HL = BSIZE (score)
    inc (hl)
    ld l,(hl)
    ld h,0
    call VDispHL
    ;End of display score
genFood:
    ld c,31 ;Mask for values 0-31
    call rand127 ;Y value
    and c
    ld l,a

    call rand127 ;X value
    and c
    ld h,a

    push hl
    add hl,hl
    call pixeltesthl
    pop hl ;H = x, L = y
    jr nz,genFood
    ld (FOOD_POS),hl ;Save food position
    ;Fall down to DispSquare

;HL = X/Y in squares
DispSquare:
    add hl,hl ;Convert to pixels
    ld a,h ;iputsprite takes X in A
    ld b,2
    ld ix,SquareSprite
    jp iputsprite

;Displays a body part, offset is given in A
DispBodyPart:
    ld a,(hl)
    ld h,BODY_X >> 8
    ld l,a ;HL = BODY_X + OFFSET
    ld a,(hl)

    inc h ;HL = BODY_Y + OFFSET
    ld l,(hl) ;Y
    ld h,a
InitialData:
    jr DispSquare ;also HEAD_Y/HEAD_X
;    .db 0 ;HEAD_Y
;    .db -1 ;HEAD_X
;It doesn't matter what HEAD_OFF and TAIL_OFF are as long as
;they are the same, why not also use it as sprite data
SquareSprite
    .db %11000000 ;HEAD_OFF
    .db %11000000 ;TAIL_OFF
    .db INITIAL_LEN + 1 ;GROWTH (In the code a growth of 1 means no growth, so we add 1 to get desired growth)
    .db INITIAL_LEN ;SCORE
    .db 0 ;VEL_Y
    .db 1 ;VEL_X
InitialDataEnd
Well done, you whipped that up fast and the result is impressive Smile.
Now that's impressive Razz Now Tunnel ! Very Happy
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement