;列數行數分別用1-8標記.所以八皇後的位置申請了9個
;調試感慨:匯編調試實在麻煩,不像C中在任何地方加個printf就可以知道
;哪錯了.跳來跳去的,不知哪裏死循環了,實在不好調試.
.model small,stdcall
;由於皇後位置都是壹位數,所以加上30H後作字符打印出.
printResult macro
local again,print,first
push si ;不能改變它的值.
mov ah,02h ;輸出狀態不變.
mov cx,2 ;對稱的結果,所以打兩個結果.
again:
mov si,1
print:
mov dl,queen[si]
cmp cx,2
je first
mov bl,9
sub bl,dl
mov dl,bl
first:
add dl,30h
int 21h
inc si
cmp si,9 ;到第9個就是說打完了.
jnz print
mov dl,' ' ;輸出兩個空格,為好看.
int 21h
int 21h
loop again
pop si
endm
.data
;改來改去,何必那麽小氣呢?用9個多方便,就壹個字節,不必這麽小氣!
queen db 9 dup(0)
used db 9 dup(0)
Nresult dw 0 ;結果的個數.
prompt db "The positions are:",0ah,0dh,'$'
over db 0ah,0dh,"The number of the result is $"
.code
;函數功能:把存在ax寄存器裏的二進制數用十進制打印出來.
printaxd proc near
mov bx,10000d ;二個字節的數最大就3萬多.
mov ch,0 ;還沒出現第壹個要打印的數(最高位的非0不需要打印)
mov cl,5 ;最多有五位,所以壹***除五次.
mov si,ax ;哈哈,寄存器太聰明了.
go:
mov ax,si
mov dx,0 ;既然是除法,就要保證高位的絕對值最小.
div bx
dec cl ;除壹次就減壹次.
mov di,ax ;除完就把商移走,位置讓出來給bx/10
mov si,dx ;保證余數.
;實現bx/10.
mov ax,bx
mov bx,10 ;記住乘除法運算不能用立即數.
mov dx,0 ; 實際上dl的最大值也就是9小於10,但為了保險和習慣,還是用這壹句.
div bx
mov bx,ax
mov ax,di
cmp cl,0 ;如果到最後壹位了,無論是0還是不為0,都要打印了.
jz next
or ch,al
jz go
next:
mov ch,1 ;有打印的了
mov dl,al
add dl,30h
mov ah,02h
int 21h
cmp cl,0
jnz go
ret ; This line cann't be forgotten.
printaxd endp
main proc far
mov ax,@data
mov ds,ax
mov es,ax
mov dx,offset prompt
mov ah,09h
int 21h
mov si,1 ;當然是從第壹列開始.
go:
inc queen[si] ;當前列向下走壹步.
;測試是否走出8*8的格子了
cmp queen[si],9
jnz stay
;剛好踏出格子,就把當前列置0,把上壹列所在行置空,然後繼續go.
mov queen[si],0
dec si
;取消所占的行.
mov al,queen[si] ;不知何以不能用movzx di,queen[si]
cbw
mov di,ax
mov used[di],0
;是否完成搜索.
cmp si,1
jnz go
;調試記語:為什麽為5時不退出呢?改成4後結果居然對了.最後壹個疑問了!
;對!原來如此!退出是要在queen[1]為5時,當4變成5時,這個增加的過程
;在go的第壹句,也就是說此時還為4.
;於是退出條件就是當此時第壹列為4而又要向前址走壹步時根據對稱性
;就要退出了.
cmp queen[si],4 ;利用對稱性,如果第壹列算到5行,就不用算了.
je exit
jmp go
stay: ;留在方格內,那麽就剩下是否滿足不在同壹行同壹斜行的問題了.
mov al,queen[si] ;不知何以不能用movzx di,queen[si]
cbw
mov di,ax
cmp used[di],1 ;如果為1就說明當前列的當前行已使用.
je go
;循環檢查是否有在同壹斜行的皇後.
mov di,si
dec di ; bx指向與當前列比較的列.
check:
cmp di,0
je checkover
mov dx,si ;dx裝著當前列與檢測列的差.,差最大不過7,所以也可以說是裝在dl中.
sub dx,di
mov al,queen[si] ;al放兩列的行之差.
sub al,queen[di]
cmp al,dl ;相等或相反就是在同壹斜行.
je go
neg al ;求負數.
cmp al,dl
je go
dec di
jmp check
checkover:
;好,現在可以留下來了.
cmp si,8
jz result
;如果不是最後壹列.
mov al,queen[si] ;不知何以不能用movzx di,queen[si]
cbw
mov di,ax
mov used[di],1 ;留下來這壹行就占住了.
inc si
jmp go
result: ;好,壹個結果出來了,根據對稱,實際出來兩個結果.
add Nresult,2
printResult
mov queen[si],0
dec si
;這四行初為設計上的漏洞,想了老半天.
mov al,queen[si] ;不知何以不能用movzx di,queen[si]
cbw
mov di,ax
mov used[di],0
jmp go
exit:
mov dx,offset over
mov ah,09h
int 21h
mov ax,Nresult
call printaxd
mov ah,01h ; to pause
int 21h
mov ah,4ch
int 21h
main endp
end main
要是上面那個不行的話,妳再試壹試這個,用masm5調試
.MODEL
.286
.CODE
ORG 100H
QUEEN: PUSH '$'
PUSH ' '
MOV BP,SP
LEA DX,[BP-08]
NEWL: MOV AH,'1'
NEWC: MOV CL,00
MOV SI,SP
ISOK: CMP SI,BP
JE SAVE
LODSB
SUB AL,AH
JZ NEXT
INC CX
CMP AL,CL
JE NEXT
ADD AL,CL
JZ NEXT
JMP ISOK
SAVE: PUSH AX
INC SP
CMP SP,DX
JNE NEWL
MOV AH,9
INT 21H
BACK: DEC SP
POP AX
NEXT: INC AH
CMP AH,'1'+08
JNE NEWC
CMP SP,BP
JNE BACK
INT 20H
END QUEEN