Survol
Nous allons faire un jeu de
morpion ! Ce jeu n'utilisera pas de sprite, à moins que vous ne considériez
qu'un curseur se déplaçant sur un tableau ne soit un sprite :) Je remercie
spécialement Robert Senser pour m'avoir fourni ce
programme!
Préparation
Tout d'abord je vais expliquer les ROM calls
_grfufclr
et
_grbufcpy. _Grfufclr
vide le buffer vidéo et tous les 768 octets de plotsscreen
sont remis à zéro.
Le
_grbufcpy
affichera ce qui est stocké dans le buffer plotsscreen.
Programmation
Le programme ci-dessous est
long, mais n'est pas plus difficile que tout ce que nous avons vu jusqu'à
maintenant.
Attention... Prêt... Programmez!
empty
.equ 0
oh
.equ 1
ohwin
.equ 3
;oh * 3!
ex
.equ 4
exwin
.equ 12
;ex * 3!
false
.equ 0
true
.equ 1
keyquit
.equ $40
keyins
.equ $0B
keyup
.equ $03
keydn
.equ $04
keyrght
.equ $01
keyleft
.equ $02
keyentr
.equ $05
#define
B_CALL(xxxx) rst 28h \ .dw xxxx
;
Nous allons
seulement utiliser
B_CALL
_RunIndicOff
=4570h
_grbufclr
= 4BD0h
_grbufcpy
= 486Ah
plotsscreen
= 9340h
_getkey
= 4972h
_puts = 450Ah
_putc = 4504h
_newline
= 452Eh
_clrlcdfull
= 4540h
_clrscrf = 4546h
_homeup
= 4558h
appTextSave
.equ 1
appFlags
.equ
13
textInverse
.equ 3
textflags
.equ
5
.org $9D95
B_CALL(_RunIndicOff)
;
Désactive l'indicateur d'exécution
B_CALL(_grbufclr)
;
vide le buffer
ld hl,picture
;
prend l'adresse
get address of splash screeen
ld de,plotsscreen
;
prend l'adresse
du buffer graphique de la TI
ld bc,768 ;
Définit le
nombre d'octets à copier
(96*64)/8
ldir ;
copie les octets
B_CALL(_grbufcpy)
;
lie l'image
graphique
; set the
flip-flip flag
ld a,false
ld (flag),a
ld (skip),a
;
start of game
newgme
B_CALL(_getkey)
; wait for a key to be
pressed
cp keyquit
jp z,bye
; exit
newgme2 ld
a,empty ;
clear the playing grid
ld (grid0),a
ld hl,grid0
ld de,grid0
ld bc,8
ldir
ld a,true
; preset the cursor grid
ld (cur0),a
ld a,false
ld (cur0+1),a
ld hl,cur0+1
ld de,cur0+2
ld bc,8
ldir
;
pick symbol for person and ti
ld a,(flag)
cp true
jr z,new1
ld
a,true
ld (flag),a
ld a,ex
ld (person),a
ld a,oh
ld (tisymb),a
ld a,false
ld (skip),a
ld hl,youex
jr main2
new1
ld a,false
ld (flag),a
ld a,oh
ld (person),a
ld a,ex
ld (tisymb),a
ld a,true
ld (skip),a
ld hl,youoh
jr main2
;
main processing loop
main
ld hl,nomsg
main2
call show ; show the current grid
ld a,(skip)
cp true
jp z,aihere
; let the ti go first
B_CALL(_getkey)
; get the next
key input
cp keyquit
jp z,bye
; exit
cp keyins
jp z,newgme2
cp
keyup
jr nz,trydn
; up pushed
call up3
jp main
trydn
cp keydn
jr nz,tryrght
; down pushed
call dn3
jp main
tryrght
cp keyrght
jr nz,tryleft
; right pushed
call rght3
jp main
tryleft
cp keyleft
jr nz,tryentr
; left pushed
call left3
jp main
tryentr cp
keyentr
ld hl,badmsg
jp nz,main2
; enter pushed, other keys ignored
; find the current cursor location
ld hl,cur0
ld b,9
fdloop
ld a,(hl)
cp true
jr
nz,fdnext
;
found cursor location!
ld bc,-9
add hl,bc
; back into the grid
;
see if empty
ld a,(hl)
cp empty
jr nz,fderr
;
if so, insert symbol
ld a,(person)
ld (hl),a
call chkwin
cp true
jp z,newgme
jr aihere
fderr
ld hl,badloc
jp main2
;
CAUTION -- AI at work here!!!
aihere
ld a,false
ld (skip),a
call timove
call chkwin
cp true
jp z,newgme
ld a,(flag)
cp true
jr z,fdmsg
ld hl,youoh
;show oh msg
jp
main2
fdmsg
ld hl,youex ;show
ex msg
jp main2
fdnext
inc hl
djnz fdloop
jp z,main
; something is wrong...
;
ignore error
jp main
;
main exit point
bye
call clrhme
; clear screen
ld hl,byemsg
B_CALL(_puts)
B_CALL(_newline)
ret ;
return to being a mere calculator
;
clrhme
set appTextSave,(iy+appFlags)
; get text shadow too
B_CALL(_clrlcdfull)
; clear lcd
B_CALL(_clrscrfull)
; clear scr
B_CALL(_homeup)
; home the cursor
ret
;TI GAME
STRATEGY
; ti makes a
move
; strategy:
; 1) Can ti
win, if so then do it
; 2) Can
"wet-ware" win, if so then take it the square first
; 3) Can ti
take the center, if so then take it
; 4) Can ti
take a corner, if so then take it
; 5) else, take
an open spot
timove
ld b,9
ld hl,grid0
tiloop1
ld a,(hl)
cp empty
jr nz,tinext1
push hl
push bc
ld a,(tisymb)
ld (hl),a
call chkwin
pop bc
pop hl
cp true
jr z,tifnd
; winning move!
ld a,empty
ld (hl),a
; remove trial move
tinext1 inc
hl
djnz tiloop1
;check
for defensive move
ld b,9
ld hl,grid0
tiloop2
ld a,(hl)
cp empty
jr nz,tinext2
push hl
push bc
ld a,(person)
ld (hl),a
call chkwin
pop bc
pop hl
ld d,a
ld a,empty
ld (hl),a
ld a,d
cp true
jr z,tifnd
; good defensive move!
tinext2
inc hl
djnz tiloop2
;check
the center
ld hl,grid0+4
ld a,(hl)
cp empty
jr z,tifnd
;check
the corners (and center again)
ld b,5
ld hl,grid0
tiloop4
ld a,(hl)
cp empty
jr z,tifnd
inc hl
; +2 goes corner to corner
...
inc
hl
djnz tiloop4
;try
anyplace (could optimize, but....)
ld b,9
ld hl,grid0
tiloop5
ld a,(hl)
cp empty
jr z,tifnd
inc hl
djnz tiloop5
jr tiexit
tifnd
ld a,(tisymb)
ld (hl),a
tiexit
ret
;
check for a winner, return true in a if so, else false
chkwin
ld hl,chktab
push hl
pop ix
;table addr
-> ix
;start
outer loop
chkloop
ld a,(hl)
;are we done?
cp 0
jr z,chknaw
;yes, then no winner!
inc hl
;get to address
ld e,(hl)
;woaw!!!
(hl) -> hl
inc hl
; woaw!!!
ld d,(hl)
; woaw!!!
push de
; woaw!!
pop hl
; de -> hl
ld d,0
ld e,a
;de is increment value
ld b,3
;b is loop count
ld a,0
;a is sum
add hl,de
;start
inner loop
chk1
add a,(hl)
add hl,de
djnz chk1
cp ohwin
jr nz,chk1n
ld hl,ohwins
; O wins!
jr chkwinr
chk1n
cp exwin
jr nz,chkno
ld hl,exwins
; X wins
jr chkwinr
;end inner
chkno
push ix
pop hl
; ix -> hl
inc hl
; add 3
inc hl
inc hl
push hl
pop ix
; hl -> ix
jr chkloop
;no win this line
;end
outer
;
exit outer loop early, crow about success and mark win
chkwinr
call show
ld a,true
jr chkbye
chknaw
ld hl,grid0
;See about the cat
ld b,9
chklop
ld a,(hl)
cp empty
jr z,chkncat
inc hl
djnz chklop
ld hl,catmsg
;Darn cat!
call show
ld a,true
jr chkbye
chkncat
ld a,false
chkbye
ret
;
this routine works by summing values in grid, 8 possible cases
chktab
.db 1
;covers the 8 cases!
.dw grid0
.db 1
.dw grid1
.db 1
.dw grid2
.db 3
.dw grid0
.db 3
.dw grid0+1
.db 3
.dw grid0+2
.db 4
.dw grid0
.db 2
.dw grid0+2
.db 0
;end of table marker
;
move "cursor" up
up3
ld hl,cur0
ld de,curx
call mov3
ld hl,cur1
ld de,cur0
call mov3
ld hl,cur2
ld de,cur1
call mov3
ld hl,curx
ld de,cur2
call mov3
ret
;
move "cursor" down
dn3
ld hl,cur0
ld de,curx
call mov3
ld
hl,cur2
ld de,cur0
call mov3
ld hl,cur1
ld de,cur2
call mov3
ld hl,curx
ld de,cur1
call mov3
ret
;
helper routine
mov3
ld bc,3
ldir
ret
;
move "cursor" right
rght3
ld hl,cur0
call shtr3
ld hl,cur1
call shtr3
ld hl,cur2
call shtr3
ret
;
helper routine
shtr3
push hl
ld a,(hl)
inc hl
ld b,(hl)
inc hl
ld c,(hl)
pop hl
ld (hl),c
inc hl
ld (hl),a
inc hl
ld (hl),b
ret
;
move "cursor" left
left3
ld hl,cur0
call shtl3
ld hl,cur1
call shtl3
ld
hl,cur2
call shtl3
ret
;
helper routine
shtl3
push hl
ld a,(hl)
inc hl
ld b,(hl)
inc hl
ld c,(hl)
pop hl
ld (hl),b
inc hl
ld (hl),c
inc hl
ld (hl),a
ret
;
show the tic-tac-toe grid on the screen
show
push hl
; keep possible message
call clrhme
; clear/home screen
ld hl,grid0
; process row 0
call showrow
ld hl,dashs
B_CALL(_puts)
B_CALL(_newline)
ld hl,grid1
; process row 1
call showrow
ld hl,dashs
B_CALL(_puts)
B_CALL(_newline)
ld hl,grid2
; process row 2
call showrow
pop hl
; process message if there
ld a,(hl)
cp 0
jr z,showby
push hl
B_CALL(_newline)
B_CALL(_newline)
pop hl
B_CALL(_puts)
showby
ret
showrow
push hl
call showspot
; show first spot
ld a,(bar)
B_CALL(_putc)
pop hl
inc hl
push hl
call showspot
; show 2nd spot
ld a,(bar)
B_CALL(_putc)
pop hl
inc hl
call showspot
; show 3rd spot
B_CALL(_newline)
ret
;
show the symbol at (hl), and handle cursor
showspot
push hl
; need this later
ld bc,9
add hl,bc
ld a,(hl)
; load cursor flag
pop hl
cp false
res textInverse,(iy+textflags)
jr z,shownch
set textInverse,(iy+textflags)
shownch
;
load actual item in spot
ld a,(hl)
cp empty
jr nz,shownot1
ld a,(space)
jr showgun
shownot1
cp oh
jr nz,shownot2
ld a,(leto)
jr showgun
shownot2
ld a,(letx)
showgun
bcall(_putc)
res textInverse,(iy+textflags)
ret
;
these are really variables
grid
.equ *
grid0
.db empty,empty,empty
grid1
.db empty,empty,empty
grid2
.db empty,empty,empty
;
this must be 9 bytes past grid0 or else it will fail
cur0
.db true,false,false
cur1
.db false,false,false
cur2
.db false,false,false
curx
.db 0,0,0
person
.db 0
tisymb
.db 0
flag
.db 0
skip
.db 0
;
basically, these are constants
nine
.db 9
space
.db "
"
leto
.db "O"
letx
.db "X"
bar
.db "|"
dashs
.db "-----",0
; youmsg
.db "Your
move!",0
youex
.db "Your
move 'X'!",0
youoh
.db "Your
move 'O'!",0
ohwins
.db "**
O ** Wins!",0
exwins
.db "**
X ** Wins!",0
catmsg
.db "*
Cat got it *",0
nomsg
.db 0
badmsg
.db "Invalid
key!",0
badloc
.db "Place
taken!",0
byemsg
.db "Game
over.",0
picture:
#include "title.asm"
; graphic image from file poets.asm
.end
END
This is the title.asm screen that
will be displayed at the start of the program, start a new text file and copy
this into it. Don't try to copy it by hand, it won't help you unless you know
what it is. Name the text file "title.asm". Then make sure it is in
the same folder as the Tic Tac Toe game when you assemble it.
; title.asm
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,1,254,192,31,224,0,31,224,0,0,0,0,1,254,0,31,224,0,31,224
.db
0,0,0,0,0,48,207,3,7,207,3,7,143,0,0,0,0,48,223,3,15,223,3,15,223,128,0,0,0,48,216
.db
3,12,216,3,12,217,128,0,0,0,48,216,3,12,216,3,12,219,128,0,0,0,48,216,3,12,216,3,12,216,0
.db
0,0,0,48,223,3,14,223,3,15,223,0,0,0,0,48,207,3,6,207,3,7,143,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,3,192,0,0,0,1,128,0,0,0,0,0,1,32,0,0,0,0,128,0,0,0
.db
0,0,3,96,0,0,0,1,128,0,0,0,0,0,2,108,198,97,172,145,38,72,0,0,0,0,3,149,40,128,82
.db
145,73,72,0,0,0,0,6,51,236,195,247,179,159,216,0,0,0,0,4,34,4,68,165,35,16,144,0,0,0,0
.db
4,34,68,68,164,194,146,96,0,0,0,0,30,115,187,135,237,134,220,207,192,0,0,0,0,0,0,0,1,0,0
.db
128,0,0,0,0,0,0,0,0,2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,12,0,0,0,0,0,0,0,0,0,0,6
.db
18,0,0,0,0,0,0,0,0,0,0,6,54,0,0,0,0,0,0,34,107,60,214,4,36,0,0,0,0,0,0
.db
34,149,69,41,4,36,0,0,0,0,0,0,61,252,111,123,12,108,0,0,0,0,0,0,41,8,42,82,8,72,0
.db
0,0,0,0,0,17,40,42,82,8,72,0,0,0,0,0,0,49,221,219,182,63,112,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.db
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Conclusion
What do you think? Cool eh'?
Pressing the "on" key seems to put the game into greyscale for some
reason, oh well. If you think the title screen was cool, you can make them by
using Bill Nagel's Pic83. Click here for instructions.
This will be the last tutorial in this version of TI-83 Plus Asm tutorials v1.01. Don't worry though ,if you finish this tutorial early, look out for version 2.01 very soon (2 weeks).
Cliquez pour revenir au menu du site... ou ici pour retourner au menu du tutorial.