⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proj5_2.asm

📁 ART OF Assembly Language Programming, 很不错
💻 ASM
📖 第 1 页 / 共 2 页
字号:
; or west, if possible.

IsNS:		mov	ch, East		;See if we can move East
		call	CanMove
		jnc	NotEast
		mov	ch, West		;See if we can move West
		call	CanMove
		jnc	DoEast
		call	RandNum			;Get a random direction
		and	ax, 1b			;Make it East or West
		or	al, 10b
		ret

DoEast:		mov	ax, East
		ret

DoWest:		mov	ax, West
		ret

NotEast:	mov	ch, West
		call	CanMove
		jc	DoWest

; Gee, we can't switch to a perpendicular direction, see if we can
; turn around.

TryReverse:	mov	ch, cl
		xor	ch, 1
		call	CanMove
		jc	ReverseDir

; If we can't turn around (likely), then keep going in the same direction.

		mov	ah, 0
		mov	al, cl			;Stay in same direction.
		ret

; Otherwise reverse direction down here.

ReverseDir:	mov	ah, 0
		mov	al, cl
		xor	al, 1
		ret
SetDir		endp



; Stuck-	This function checks to see if a demon is stuck and cannot
;		move in any direction.  It returns true if the demon is
;		stuck and needs to be killed.

Stuck		proc	near
		mov	ch, North
		call	CanMove
		jc	NotStuck
		mov	ch, South
		call	CanMove
		jc	NotStuck
		mov	ch, East
		call	CanMove
		jc	NotStuck
		mov	ch, West
		call	CanMove
NotStuck:	ret
Stuck		endp



; NextDemon-	Searches through the demon list to find the next available
;		active demon.  Return a pointer to this guy in es:di.

NextDemon	proc	near
		push	ax

NDLoop:		inc	DemonIndex		;Move on to next demon,
		and	DemonIndex, ModDemons	; MOD MaxDemons.
		mov	al, size pcb		;Compute index into
		mul	DemonIndex		; DemonList.
		mov	di, ax			;See if the demon at this
		add	di, offset DemonList	; offset is active.
		cmp	byp [di].pcb.NextProc, 0
		je	NDLoop

		mov	ax, ds
		mov	es, ax
		pop	ax
		ret
NextDemon	endp



; Dig-		This is the demon process.
;		It moves the demon one position (if possible) in its current
;		direction.  After moving one position forward, there is
;		a 25% chance that this guy will change its direction; there
;		is a 25% chance this demon will spawn a child process to
;		dig off in a perpendicular direction.

Dig		proc	near

; See if the current demon is stuck.  If the demon is stuck, then we've
; go to remove it from the demon list.  If it is not stuck, then have it
; continue digging.  If it is stuck and this is the last active demon,
; then return control to the main program.

		call	Stuck
		jc	NotStuck

; Okay, kill the current demon.
; Note: this will never kill the last demon because we have the timer
; process running.  The timer process is the one that always stops
; the program.

		dec	DemonCnt

; Since the count is not zero, there must be more demons in the demon
; list.  Free the stack space associated with the current demon and
; then search out the next active demon and have at it.

MoreDemons:	mov	al, size pcb
		mul	DemonIndex
		mov	bx, ax

; Free the stack space associated with this process.  Note this code is
; naughty.  It assumes the stack is allocated with the Standard Library
; malloc routine that always produces a base address of 8.

		mov	es, DemonList[bx].regss
		mov	di, 8				;Cheating!
		free

; Mark the demon entry for this guy as unused.

		mov	byp DemonList[bx].NextProc, 0	;Mark as unused.


; Okay, locate the next active demon in the list.

FndNxtDmn:	call	NextDemon
		cocall				;Never returns




; If the demon is not stuck, then continue digging away.

NotStuck:	mov	ch, cl
		call	CanMove
		jnc	DontMove

; If we can move, then adjust the demon's coordinates appropriately:

		cmp	cl, South
		jb	MoveNorth
		je	MoveSouth
		cmp	cl, East
		jne	MoveWest

; Moving East:

		inc	dl
		jmp	MoveDone

MoveWest:	dec	dl
		jmp	MoveDone

MoveNorth:	dec	dh
		jmp	MoveDone

MoveSouth:	inc	dh

; Okay, store a NoWall value at this entry in the maze and output a NoWall
; character to the screen (if writing data to the screen).

MoveDone:	MazeAdrs
		mov	bx, ax
		mov	Maze[bx], NoWall

		ifdef	ToScreen
		ScrnAdrs
		mov	bx, ax
		push	es
		mov	ax, ScreenSeg
		mov	es, ax
		mov	word ptr es:[bx], NoWallChar
		pop	es
		endif

; Before leaving, see if this demon shouldn't change direction.

DontMove:	call	RandNum
		and	al, 11b			;25% chance result is zero.
		jne	NoChangeDir
		call	SetDir
		mov	cl, al

NoChangeDir:


; Also, see if this demon should spawn a child process

		call	RandNum
		and	al, 11b			;Give it a 25% chance.
		jne	NoSpawn

; Okay, see if it's possible to spawn a new process at this point:

		call	CanStart
		jnc	NoSpawn

; See if we've already got MaxDemons active:

		cmp	DemonCnt, MaxDemons
		jae	NoSpawn

		inc	DemonCnt			;Add another demon.


; Okay, create a new demon and add him to the list.

		push	dx				;Save cur demon info.
		push	cx

; Locate a free slot for this demon

		lea	si, DemonList- size pcb
FindSlot:	add	si, size pcb
		cmp	byp [si].pcb.NextProc, 0
		jne	FindSlot


; Allocate some stack space for the new demon.

		mov	cx, 256				;256 byte stack.
		malloc

; Set up the stack pointer for this guy:

		add	di, 248				;Point stack at end.
		mov	[si].pcb.regss, es
		mov	[si].pcb.regsp, di

; Set up the execution address for this guy:

		mov	[si].pcb.regcs, cs
		mov	[si].pcb.regip, offset Dig

; Initial coordinates and direction for this guy:

		mov	[si].pcb.regdx, dx

; Select a direction for this guy.

		pop	cx			;Retrieve direction.
		push	cx

		call	SetDir
		mov	ah, 0
		mov	[si].pcb.regcx, ax

; Set up other misc junk:

		mov	[si].pcb.regds, seg dseg
		sti
		pushf
		pop	[si].pcb.regflags
		mov	byp [si].pcb.NextProc, 1	;Mark active.


; Restore current process' parameters

		pop	cx			;Restore current demon.
		pop	dx

NoSpawn:

; Okay, with all of the above done, it's time to pass control on to a new
; digger.  The following cocall passes control to the next digger in the
; DemonList.

GetNextDmn:	call	NextDemon

; Okay, we've got a pointer to the next demon in the list (might be the
; same demon if there's only one), pass control to that demon.

		cocall
		jmp	Dig
Dig		endp


; TimerDemon-	This demon introduces a 1/18th second delay between
;		each cycle in the demon list.  This slows down the
;		maze generation so you can see the maze being built
;		(which makes the program more interesting to watch).

TimerDemon	proc	near
		push	es
		push	ax

		mov	ax, 40h			;BIOS variable area
		mov	es, ax
		mov	ax, es:[6Ch]		;BIOS timer location
Wait4Change:	cmp	ax, es:[6Ch]		;BIOS changes this every
		je	Wait4Change		; 1/18th second.

		cmp	DemonCnt, 1
		je	QuitProgram
		pop	es
		pop	ax
		call	NextDemon
		cocall
		jmp	TimerDemon

QuitProgram:	cocall	MainPCB			;Quit the program
TimerDemon	endp




; What good is a maze generator program if it cannot solve the mazes it
; creates?  SolveMaze finds the solution (if any) for this maze.  It marks
; the solution path and the paths it tried, but failed on.
;
; function solvemaze(x,y:integer):boolean

sm_X		textequ	<[bp+6]>
sm_Y		textequ	<[bp+4]>

SolveMaze	proc	near
		push	bp
		mov	bp, sp

; See if we've just solved the maze:

		cmp	byte ptr sm_X, EndX
		jne	NotSolved
		cmp	byte ptr sm_Y, EndY
		jne	NotSolved
		mov	ax, 1			;Return true.
		pop	bp
		ret	4

; See if moving to this spot was an illegal move.  There will be
; a NoWall value at this cell in the maze if the move is legal.

NotSolved:	mov	dl, sm_X
		mov	dh, sm_Y
		MazeAdrs
		mov	bx, ax
		cmp	Maze[bx], NoWall
		je	MoveOK
		mov	ax, 0			;Return failure
		pop	bp
		ret	4

; Well, it is possible to move to this point, so place an appropriate
; value on the screen and keep searching for the solution.

MoveOK:		mov	Maze[bx], Visited

		ifdef	ToScreen
		push	es			;Write a "VisitChar"
		ScrnAdrs			; character to the
		mov	bx, ax			; screen at this X,Y
		mov	ax, ScreenSeg		; position.
		mov	es, ax
		mov	word ptr es:[bx], VisitChar
		pop	es
		endif

; Recusively call SolveMaze until we get a solution.  Just call SolveMaze
; for the four possible directions (up, down, left, right) we could go.
; Since we've left "Visited" values in the Maze, we will not accidentally
; search back through the path we've already travelled.  Furthermore, if
; we cannot go in one of the four directions, SolveMaze will catch this
; immediately upon entry (see the code at the start of this routine).

		mov	ax, sm_X		;Try the path at location
		dec	ax			; (X-1, Y)
		push	ax
		push	sm_Y
		call	SolveMaze
		test	ax, ax			;Solution?
		jne	Solved

		push	sm_X			;Try the path at location
		mov	ax, sm_Y		; (X, Y-1)
		dec	ax
		push	ax
		call	SolveMaze
		test	ax, ax			;Solution?
		jne	Solved

		mov	ax, sm_X		;Try the path at location
		inc	ax			; (X+1, Y)
		push	ax
		push	sm_Y
		call	SolveMaze
		test	ax, ax			;Solution?
		jne	Solved

		push	sm_X			;Try the path at location
		mov	ax, sm_Y		; (X, Y+1)
		inc	ax
		push	ax
		call	SolveMaze
		test	ax, ax			;Solution?
		jne	Solved
		pop	bp
		ret	4

Solved:
		ifdef	ToScreen		;Draw return path.
		push	es
		mov	dl, sm_X
		mov	dh, sm_Y
		ScrnAdrs
		mov	bx, ax
		mov	ax, ScreenSeg
		mov	es, ax
		mov	word ptr es:[bx], PathChar
		pop	es
		mov	ax, 1			;Return true
		endif

		pop	bp
		ret	4
SolveMaze	endp



; Here's the main program that drives the whole thing:

Main		proc
		mov	ax, dseg
		mov	ds, ax
		mov	es, ax
		meminit


		call	Init			;Initialize maze stuff.
		lesi	MainPCB			;Initialize coroutine
		coinit				; package.

; Create the first demon.
; Set up the stack pointer for this guy:

		mov	cx, 256
		malloc
		add	di, 248
		mov	DemonList.regsp, di
		mov	DemonList.regss, es

; Set up the execution address for this guy:

		mov	DemonList.regcs, cs
		mov	DemonList.regip, offset Dig

; Initial coordinates and direction for this guy:

		mov	cx, East		;Start off going east.
		mov	dh, StartY
		mov	dl, StartX
		mov	DemonList.regcx, cx
		mov	DemonList.regdx, dx

; Set up other misc junk:

		mov	DemonList.regds, seg dseg
		sti
		pushf
		pop	DemonList.regflags
		mov	byp DemonList.NextProc, 1	;Demon is "active".
		inc	DemonCnt
		mov	DemonIndex, 0




; Set up the Timer demon:

		mov	DemonList.regsp+(size pcb), offset EndTimerStk
		mov	DemonList.regss+(size pcb), ss

; Set up the execution address for this guy:

		mov	DemonList.regcs+(size pcb), cs
		mov	DemonList.regip+(size pcb), offset TimerDemon

; Set up other misc junk:

		mov	DemonList.regds+(size pcb), seg dseg
		sti
		pushf
		pop	DemonList.regflags+(size pcb)
		mov	byp DemonList.NextProc+(size pcb), 1
		inc	DemonCnt

; Start the ball rolling.

		mov	ax, ds
		mov	es, ax
		lea	di, DemonList
		cocall

; Wait for the user to press a key before solving the maze:

		getc

		mov	ax, StartX
		push	ax
		mov	ax, StartY
		push	ax
		call	SolveMaze

; Wait for another keystroke before quitting:

		getc

		mov	ax, 3		;Clear screen and reset video mode.
		int	10h

Quit:		ExitPgm			;DOS macro to quit program.
Main		endp

cseg		ends

sseg		segment	para stack 'stack'

; Stack for the timer demon we create (we'll allocate the other
; stacks dynamically).

TimerStk	byte	256 dup (?)
EndTimerStk	word	?


; Main program's stack:

stk		byte	512 dup (?)
sseg		ends

zzzzzzseg	segment	para public 'zzzzzz'
LastBytes	db	16 dup (?)
zzzzzzseg	ends
		end	Main

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -