06月 9th, 2008 俺也汇编一下:EMU8086
对不住各位看官了……这个EMU8086模拟器是Windows下的,还是破解的……我只是为了完成计组老师的作业而已。只是有道题比较有意思,我深深地想了好久,发现一些问题,估计老师不会认真改我的作业,我把它发上来发泄发泄,嗯。
话说EMU8086预先弄了几个PORT,其中PORT9就是实现了一个机器人的东东。具体描述如下:在一个9X6的地图内,有墙、灯、机器人三种东西。机器人碰到墙和灯都过不去,但是碰到灯的时候会自动改变灯的状态,也就是关灯或者开灯。
现在在地图上画一个地图,机器人使用给定的算法会产生死角,问怎么样消除死角。
话说原来给定的代码太弱了,一眼看出破绽:机器人碰墙只能单纯地朝一个方向转,那么碰到开了一口的闭合空间时,一旦进去就出不来了(如图),必然得改进。改进的方法有两个,一个是把行走改成随机方向,那么机器人再怎么囧最后也能走出去,可是老师不提倡随机,那么只好接着改了。
在不使用随机走法的情况下,使用回溯法是更好的解决方案。回溯法用在走迷宫的时候比较实用,遵循“右手法则”地回溯搜索路径,最后走出死角。
然而一般“右手法则”下的回溯会产生另一个问题,就是在空白面积比较大的时候,会出现“绕某点打转”的现象,如下图:
这在机器人行走中是致命的。
我原计划采用的是“撒米标记法”解决此问题。但是由于对数组的使用不熟悉,没有解决这个问题。(关键在这,- -b)在这里仅写出思路:“撒米标记法”。使用一个数组来记录当前点是否已经被车子移到过,如果当前点在之前已经在同个方向上被访问过,则机器人不再继续前进,而是直接选择一个其他方向,继续按照右手法则行走。
第二个死角的产生比较麻烦,是软件本身产生的“副作用”。此“副作用”在如下情况下执行关灯/开灯操作时出现:
当程序员手动执行机器人转向操作时,软件会记录这一次转向。一次左转和一次右转会抵消。不连续的两次转向不相关。所以转向结束后,会有一个“净转向”值。此时机器人如果正好面对一盏灯,在执行关灯/开灯操作之后,机器人会自动逆着“净转向”的方向转动相应次数。例如下图:
机器人在两次右转之后,面对的是灯。在关完灯的同时,机器人会自动向左转两次,恢复到原来状态。
了解了转向的副作用,便可知下图会产生一个死角:
为了解决这个死角,可以采用“抵消副作用”法。对于以上右手法则,可以很容易获得其状态机:(其实这个状态机挺扯的,原谅我自动机课没学好T_T)
圈内数字表示当前状态下的净转向值。
具体解法可看附件的代码。
#MAKE_BIN#
#CS = 500#
#DS = 500#
#SS = 500# ; stack is set
#SP = FFFF# ; automatically.
#IP = 0#
R_PORT EQU 9
;BL 255: turned left
; 0: turned none
; 1: turned right
;BH 0: initial state
; 1: try right
; 2: try ahead
; 3: try left
; 4: try back
; when it moves ahead, BH should be 0
eternal_loop:
CALL WAIT_ROBOT
MOV AL, 4
OUT R_PORT, AL
CMP BH, 0 ; judge if initial state
JE first_step ; first_step
CALL WAIT_EXAM ; else judge how to move
IN AL, R_PORT + 1
CMP AL, 0 ; nothing?
JE forward ; so, forward
CMP AL, 255 ; wall?
JE meet_wall ; so, turn right
CMP AL, 7 ; switched-on lamp?
JE switch_off ; so, switch it off and do something
CMP AL, 8 ; switched-off lamp?
JE switch_on ; so, switch it on and do something
first_step:
ADD BH, 1
MOV BL, 1
JMP turn_right
meet_wall:
ADD BH, 1
SUB BL, 1
JMP turn_left
meet_lamp:
ADD BH, 1
CMP BL, 255
JE turn_around
SUB BL, 1
CMP BL, 0
JE eternal_loop
JMP turn_left
turn_left:
CALL WAIT_ROBOT ; turn left operation
MOV AL, 2
OUT R_PORT, AL
JMP eternal_loop ; go again
forward:
MOV BH, 0 ; when forward, back to initial state
MOV BL, 0 ; no turn mark
CALL WAIT_ROBOT ; go ahead
MOV AL, 1
OUT R_PORT, AL
JMP eternal_loop ; go again!
switch_off:
CALL WAIT_ROBOT ; turn off the lamp
MOV AL, 6
OUT R_PORT, AL
JMP meet_lamp
switch_on:
CALL WAIT_ROBOT ; turn on the lamp
MOV AL, 5
OUT R_PORT, AL
JMP meet_lamp
turn_right:
CALL WAIT_ROBOT ; turn right operation
MOV AL, 3
OUT R_PORT, AL
JMP eternal_loop ; go again
turn_around:
CALL WAIT_ROBOT ; turn right twice to turn around
MOV AL, 3
OUT R_PORT, AL
CALL WAIT_ROBOT
MOV AL, 3
OUT R_PORT, AL
JMP eternal_loop ; go again
WAIT_ROBOT PROC
busy:
IN AL, R_PORT+2
TEST AL, 00000010b
JNZ busy ; busy, so wait.
RET
WAIT_ROBOT ENDP
WAIT_EXAM PROC
busy2:
IN AL, R_PORT+2
TEST AL, 00000001b
JZ busy2 ; no new data, so wait.
RET
WAIT_EXAM ENDP
写完了。反正问题就在,会绕圈……
等考完事再来看。估计也就是几个register的问题。
最后附上一个可启动的小东东:打字训练——所谓的“操作系统”作业,Orz。专门为某打字不按指法的家伙准备的。
谢帆说还要把Loader和Kernel分开写,我继续Orz了,这个小东西填MBR的牙缝都不够呢,还分开……
如果您第一次光临本站,欢迎订阅我的RSS feed以方便阅读。欢迎给我留言,您的留言是对本站最好的支持!
If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!
Related Posts
---------- COPYRIGHT (C) CasparAnt.COM 2008 ----------
本站所有文章均遵循“创作共用条款(CC)3.0版本”, 允许转载演绎本站文章,仅需遵循以下原则:保留文章出处(URL及站名Caspar Ant), 并且给我一个 引用通告(trackback)。如果您觉得本站的文章很好,欢迎选择下面的网络书签收藏本文; 如果您觉得本站值得浏览,欢迎点击侧边栏进行订阅;欢迎您对文章发表评论,您的留言是对我最好的鼓励!
This entry is under CREATIVE COMMON ATTRIBUTION 3.0 LICENSE. Please remain "Caspar Ant" and the URL stay in your site when you share or remix this entry. It's necessary to give me a trackback from your own site. If you think this entry is good enough, welcome to put it to your own web bookmark. You can select from the bookmark sites at follows:






















