原题目:
http://tieba.baidu.com/p/5112596208汇编实现猜数字游戏
;这代码比楼主的长一倍,主要是在输入上做了许多阻挡,防止一切的[错误输入]
;程式里建立一个[核对占用表格],用户输入了某数字,占用表就设1,以限制以后的重复,
;若用backspace修改,这个占用重设为0,这[占用表]还可以用作限制 [取乱数 ]时的重复选取.
;另外,程式有两个常数可以修改
; StepDefault equ 8 ;尝试次数,可更改,可超过10,但别太过份,代码其余部份不必改.
; GameField equ 4 ;即10猜4,但可改为5,6,7...等数字,代码其余部份不必改.
; 若是10猜6就是这样子.
;------------ master mind猜数字版代码------------------
GameNumber equ 10 ;可猜数目 0-9 ;不可更改
GameField equ 4 ;10猜4 ,可更改4,5,6,但别太过份
StepDefault equ 8 ;尝试次数,可更改,可超过10,但别太过份
Esc_key equ 1bh ;离开键
Enter_key equ 0dh ;回车键
BS_key equ 08h ;退位键
DATA SEGMENT
TitleStr db 'Number MasterMind',13,10,17 dup ('-'),13,10,'$'
Winstr db 13,10,'You are win, play next (y/n)?$'
StepStr db '00:$'
HintStr db 20h,20h,'-',20h ;提示
HintStrOffset db GameField dup (0),13,10,'$' ; ?=猜错, X=猜对这数,位置不对;Y=全猜对
MyAnsStr db 20h,'<',20h
MyAns db GameField dup (0),20h,'>',13,10,'$'
LossStr db 13,10,'You are loose.',13,10,'$'
UserAns db GameField dup (0)
RandomTable db GameNumber dup (0) ;核对占用表格
StepCount db ?
AskShowAnsStr db 13,10, 'Show Answer ?(y/n)$'
ShowAnsFlag db 0 ;是否显示答案标旗
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA
START:
mov ax,DATA
mov ds,ax
mov es,ax
mov dx,offset AskShowAnsStr ;询问是否显示答案
mov ah,9
int 21h
call AskYN ;等得输入(y/n)子程序
or ax,ax ;答y, ax=1
jz StartGame
mov ShowAnsFlag,1 ;显示答案标旗
StartGame:
call ClrScr ;清屏
call GetGameNumber ;乱数取得答案
mov dx,offset TitleStr
mov ah,9
int 21h
cmp ShowAnsFlag,0 ;是否显示答案
jz @f
call ShowAnswer
@@:
mov StepCount,1 ;初始化尝试次数
cld
ReTry:
call OutputStep ;印出猜次数
call GetInput ;输入子程序
jc exit ;若返回cf=1,表示使用者输入ESC
call CheckWin ;核对输入
or ax,ax ;若ax=1,表示全对
jz Loss ;否则不全对
mov dx,offset WinStr
mov ah,9
int 21h
Askplay:
call AskYN
or ax,ax
jz exit
jmp StartGame
Loss:
inc StepCount ;累加尝试次数
cmp StepCount,StepDefault ;是否超过限制次数, 8?
ja LossX ;超过 ----- 为要被开百度和阶JB,用了ja ,其实这句和下句用jbe ReTry即可
jmp short ReTry ;下一次
LossX:
mov ah,9 ; 超过限制次数,以下印出答案,并离开
mov dx,offset MyAnsStr
int 21h
mov dx,offset LossStr
int 21h
exit:
MOV AX,4C00H
INT 21H
;---------------------------------------
AskYN: ;等得输入(y/n)子程序
push bx
@@:
mov ah,7 ;等待输入无显示
int 21h
mov bl,al
and bl,5fh ;转大写
cmp bl,'Y'
mov ax,1
jz @f ;
cmp bl,'N' ;n则离开
jnz @b
mov ax,0
@@:
pop bx
ret
;---------------------------------------
OutputStep: ;印出猜次数子程序
mov al,StepCount ;取次数
aam ;转bcd
or ax,3030h ;转ascii
xchg ah,al ;交换
cmp al,'0' ;十位是否'0'
jnz @f
mov al,20h ; 十位是'0',换成空白
@@:
mov word ptr StepStr,ax ;以下印出猜次数
mov dx,offset StepStr
mov ah,9
int 21h
ret
;---------------------------------------
GetInput: ;读取使用者输入子程序
mov si,0 ;清0, 输入字节计数
mov bx,0
call InitTable
GetI10:
mov ax,0c07h ;读键不显示
int 21h
cmp al,Esc_key ;ESC ?
jnz GetI15
stc ;按ESC , cf=1离开
ret
GetI15:
cmp al,Enter_key ;回车?
jnz GetI20 ;不是
cmp si,GameField ;si = GameField(4),表示4个数字输入
jnz GetI10
jmp short GetI90
GetI20:
cmp al,BS_key ;backspace 退位?
jnz GetI50 ;不是
cmp si,0 ;si = 0,表示没有输入
jz GetI10 ;没有输入,不许退位
; 退位
call backspace ;退位子程序
dec si
mov bl,UserAns[si]
sub bl,'0'
mov RandomTable[bx],0 ;解除占用
jmp short GetI10
GetI50:
cmp si,GameField ;si = GameField(4),表示4个数字输入
jz GetI10 ;已满,不接受输入
mov dl,al
sub al,'0' ;ascii转值
cmp al,9 ;是否0-9
ja GetI10
mov bl,al
cmp RandomTable[bx],1 ;是否占用
jz GetI10
mov RandomTable[bx],1 ;占用
mov ds:UserAns[si],dl ;保存使用者输入
inc si ;下一个输入
mov ah,2 ;印出使用者输入
int 21h
jmp GetI10 ;下一个
GetI90:
clc ; cf=0,走
ret
;---------------------------------------
CheckWin: ;核对子程序
mov bp,0 ;全对计数
mov si,0 ;比对位置0-4 ?
cw10:
mov al,UserAns[si] ;取使用者猜的数字
mov di,0
mov cx,GameField ; 4 ?
cw20:
cmp al,MyAns[di] ;和答案比较
jz cw40 ;对
inc di ;不对则一下个
loop cw20
mov ah,'?' ;猜错
jmp short cw60
cw40:
mov ah,'X' ;猜到数字,位置不对
cmp si,di ;位置是否对
jnz cw60 ;不对
inc bp ;增加全对次数
mov ah,'Y' ;全对
cw60:
mov HintStrOffset[si],ah ;根据错,不全对,全对存入 ?, X 或 Y
inc si ;下一个
cmp si, GameField ; 是否超过限制, 4 ?
jae cw70 ;----- 为要被开百度和阶JB,用了jae ,其实这句和下句用jb cw10即可
jmp short cw10 ;并未
cw70:
mov dx,offset HintStr ;已全比较,印出提示
mov ah,9
int 21h
mov ax,0
cmp bp,GameField ;是否猜全对4次
jnz cw80
mov ax,1
cw80:
ret
;---------------------------------------
; dos / 16 bit 取乱数子程序
; cpu每5ns累加一次,用RDTSC读取,放EDX:EAX
; 因为某些编译器不懂RDTSC, 0fh,31h是机器码植入
Random: ; (Return AX : 0 - 65535)
push cx
push dx
db 0fh,31h ;RDTSC
db 66h
mov dx,ax ; mov edx,eax
mov cl,16
db 66h
shr dx,cl ;shr edx,cl
xor al,dh ;乱一些
xor ah,dl ;更乱一些
pop dx
pop cx
ret
;---------------------------------------
ClrScr: ;清屏
mov ax,0600h ;cls
mov bh,7 ;normal attribute
mov cx,0 ;top left
mov dx,6079 ;bottom right
int 10h
mov ah,02 ;move curvor to left top
mov bx,0 ;zero page
mov dx,0000 ;top left
int 10h
ret
;---------------------------------------
InitTable: ;核对占用表格初始化子程序
push cx
push di
mov al,0
mov di,offset RandomTable
mov cx,GameNumber
repe stosb
pop di
pop cx
ret
;---------------------------------------
backspace: ;退位动作子程序
mov dl,8 ;退一位
mov ah,2
int 21h
mov dl,20h ;印空白清除原来字符
int 21h
mov dl,8 ;退一位
int 21h
ret
;---------------------------------------
GetGameNumber: ;以乱数获取答案子程序
;Get 4 Random diff Number
call initTable ;初始化核对占用表格
mov cx,GameField ;初始化
mov di,0 ;初始化
mov bx,0 ;初始化
Init10:
Call Random ;乱数子程序,ax=0-65535
cmp ax,65529 ;6553 x 10 ,限制10的乘积,达到每个数0-9机会均等
ja Init10
inc ax
mov si,GameNumber ; 10
xor dx,dx
div si ; 取余数,dl=0-9
mov bl,dl
cmp RandomTable[bx],1 ;是否占用
jz init10 ;不是
mov RandomTable[bx],1 ;占用制能
or dl,'0' ;转回ascii
mov MyAns[di],dl ;存答案
inc di ;下一个
loop Init10
ret
;---------------------------------------
ShowAnswer: ;显示答案作测试用,可在前加 ';' ,令其除能
mov ah,9
mov dx,offset MyAnsStr
int 21h
ret
;---------------------------------------
CODE ENDS
END START
;------------ master mind猜数字版-- 完-----------------