ch上两次比赛的简单总结

这个拖了很久。。。

先是round24

第一题是kmp+dp。。。。这里其实关键的地方是要知道kmp匹配自己时。。如果整个前缀的长度 是错位部分(即f[i]~i)长度的整数倍。。。那么错位部分就刚好是这个前缀最短的一个周期。。。

第二题就是平衡树,代码敲熟就好

第三题:给出一个图,多次询问连接两点的路径上必须经过的边有几条。。。其实就是求两点之间桥的个数。。。tarjan求出所有桥,然后把每个边双连通分量缩点得到一颗树,再用lca倍增算法求中间的路径长度。。这题还是挺裸的。。。但是当时看到完全没感觉啊,还是太弱了

round 26

第一题:把几种直接可以出答案和永远出不了答案的情况特判一下。。。其他的情况的算法其实就是求gcd。。。辗转相除即可(当时完全没看出来啊)

第二题:这道题出题人给的题解居然是打表+搜索,233333。不过贴吧上有人给了一些比较好的方法。。。第一个就是按照非严格递增的顺序枚举,最后做一次01背包判断方案是否可行。。。然后答案数+=当前方案的可重排列数。。。可重排列需要除掉的那一部分可以在枚举过程中维护出来。

还有个牛逼的改进就是:01背包的dp状态用long long的二进制来表示...每次转移就只需要O(1)了。。。这个也可以在枚举过程中维护出来。

第三题:其实就是一个bfs而已。。只不过状态的扩展有点麻烦。。这个静下心去写应该还是能写对的

第四题:区间修改,求区间gcd。。。先想下点修改的:可以用线段树做。   因为gcd(al,al+1,al+2,……,ar)=gcd(gcd(al,al+1,...,ak),gcd(ak+1,...,ar));直接维护就好了。。我当时想了半天都没想到T_T。  然后区间修改可以这么来弄:用线段树维护原序列的差分序列,然后区间修改就变成了修改两个点。。

因为有 gcd(al,al+1,...,ar)=gcd(al, al+1 - al, al+2 - al+1,...,ar - ar-1)...所以查询l到r的gcd时。。。就是求gcd(al,gcd(al+1-al,...,ar - ar-1))了。。。前面那个al实际上就是差分序列的第一项到 al - al-1这一项的和

第五题:太高端还没弄懂


; 乒乓球游戏汇编代码 ; 使用MASM语法,针对DOS环境 .MODEL SMALL .STACK 100H .DATA ; 端口地址定义 pa EQU 280H pb EQU 281H pc EQU 282H pn1 EQU 283H p0 EQU 288H p1 EQU 289H p2 EQU 28AH pn2 EQU 28BH ; 数码管编码表 s DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH,39H,5EH,7BH,71H ; 全局变量 led DB 0 f DW 1 ; 移动方向标志 s1 DW 50 ; 初始速度 m DW 0 ; 甲得分 n DW 0 ; 乙得分 msg DB ‘Please serve!’,0DH,0AH,‘$’ .CODE STARTUP: MOV AX, @DATA MOV DS, AX ; 初始化8255 MOV DX, pn1 MOV AL, 81H ; A/B口输出,C口输入 OUT DX, AL ; 初始化8253定时器 MOV DX, pn2 MOV AL, 36H ; 计数器0,方式3 OUT DX, AL MOV DX, p0 MOV AX, 1193 ; 1MHz时钟,产生50Hz中断 OUT DX, AL MOV AL, AH OUT DX, AL MAIN_LOOP: ; 显示发球提示 MOV AH, 09H MOV DX, OFFSET msg INT 21H CALL START ; 等待发球 GAME_LOOP: MOV DX, pb MOV AL, led OUT DX, AL ; 更新LED状态 ; 数码管动态显示 CALL SCOREM CALL DELAY CALL SCOREN CALL DELAY ; 检测击球 MOV DX, pc IN AL, DX CMP f, 1 JNE CHECK_RIGHT ; 向左移动时检测乙击球(PC1) TEST AL, 02H JZ MOVE_BALL MOV f, 0 ; 改变方向 JMP MOVE_BALL CHECK_RIGHT: ; 向右移动时检测甲击球(PC0) TEST AL, 01H JZ MOVE_BALL MOV f, 1 MOVE_BALL: CALL LEDDIC ; 移动球位置 CALL OUT_CHECK ; 得分检测 CMP led, 0 ; 检查球是否出界 JNE GAME_LOOP JMP MAIN_LOOP ; 开始新回合 MOV AH, 4CH ; 退出程序 INT 21H ; LED移动函数 LEDDIC PROC NEAR CMP f, 1 JE LEFT SHR led, 1 ; 右移 JMP EXIT_LED LEFT: SHL led, 1 ; 左移 EXIT_LED: RET LEDDIC ENDP ; 数码管显示延时 DELAY PROC NEAR PUSH CX MOV CX, 500 DLOOP: LOOP DLOOP POP CX RET DELAY ENDP ; 显示甲得分 SCOREM PROC NEAR MOV DX, pc MOV AL, 20H ; 开启高位数码管 OUT DX, AL MOV BX, m MOV AL, s[BX] MOV DX, pa OUT DX, AL RET SCOREM ENDP ; 显示乙得分 SCOREN PROC NEAR MOV DX, pc MOV AL, 10H ; 开启低位数码管 OUT DX, AL MOV BX, n MOV AL, s[BX] MOV DX, pa OUT DX, AL RET SCOREN ENDP ; 发球检测(带去抖动) START PROC NEAR START_LOOP: MOV DX, pc IN AL, DX TEST AL, 01H ; 检测甲发球 JZ CHECK_PC1 CALL DEBOUNCE TEST AL, 01H JZ CHECK_PC1 MOV led, 80H ; 甲发球位置 MOV f, 0 ; 初始向右移动 JMP START_EXIT CHECK_PC1: TEST AL, 02H ; 检测乙发球 JZ START_LOOP CALL DEBOUNCE TEST AL, 02H JZ START_LOOP MOV led, 01H ; 乙发球位置 MOV f, 1 ; 初始向左移动 START_EXIT: RET START ENDP ; 按键去抖动 DEBOUNCE PROC NEAR PUSH CX MOV CX, 1000 DB_LOOP: LOOP DB_LOOP POP CX RET DEBOUNCE ENDP ; 得分判断 OUT_CHECK PROC NEAR CMP led, 0 JNE OC_EXIT CMP f, 1 JNE PLAYER_A INC n ; 乙得分 JMP SCORE_CHECK PLAYER_A: INC m ; 甲得分 SCORE_CHECK: ; 胜负判断(11分制,领先2分) MOV AX, m CMP AX, 11 JL CHECK_N MOV BX, n SUB AX, BX CMP AX, 2 JGE RESET JMP OC_EXIT CHECK_N: MOV AX, n CMP AX, 11 JL OC_EXIT MOV BX, m SUB AX, BX CMP AX, 2 JL OC_EXIT RESET: MOV m, 0 MOV n, 0 OC_EXIT: RET OUT_CHECK ENDP END优化此代码 使此代码利用8253clock0为1MHz,out0与clock1的串联 实现输出2hz方波 并实现led的移动速度为0.5s ,任意一方领先两分或得到11分时结束游戏 给出修改后全部的代码
最新发布
04-03
<think>好的,我现在需要帮用户优化他们提供的乒乓球游戏汇编代码。用户的要求有几个关键点:首先,要利用8253的clock0(1MHz)和out0与clock1的串联,生成2Hz的方波,使得LED的移动速度变为0.5秒。其次,当任意一方领先两分或达到11分时结束游戏。我需要仔细分析现有的代码,找出需要修改的部分,并确保所有改动符合MASM语法和DOS环境。 首先,我需要理解原来的定时器初始化部分。用户提到原来的8253初始化是设置计数器0为方式3,产生50Hz的中断。但现在需要将clock0和clock1串联,生成2Hz的方波。8253每个计数器的工作方式需要正确配置。 原来的初始化代码是: MOV DX, pn2 MOV AL, 36H ; 计数器0,方式3 OUT DX, AL MOV DX, p0 MOV AX, 1193 ; 1MHz时钟,产生50Hz中断 OUT DX, AL MOV AL, AH OUT DX, AL 现在,用户希望将clock0和clock1串联。首先,计数器0需要设置为方式2(速率发生器),然后计数器1也设置为方式3(方波发生器)。因为1MHz的时钟经过计数器0分频后,输出到计数器1的时钟输入,最终产生2Hz的方波。 计算分频值:要得到2Hz,计数器0和计数器1的组合分频应为1MHz / 2Hz = 500,000。但每个计数器最大分频是65535,所以需要分阶段。例如,计数器0分频为1000,计数器1分频为500,这样1000 * 500 = 500,000。这样,计数器0的输出是1MHz / 1000 = 1kHz,然后计数器1分频500,得到2Hz。 所以,初始化代码需要修改为: - 计数器0:方式2,二进制,初始值1000(03E8H) - 计数器1:方式3,二进制,初始值500(01F4H) 对应的控制字: - 计数器0:00110100B (34H) - 计数器1:01110110B (76H) 初始化代码应改为: MOV DX, pn2 MOV AL, 34H ; 计数器0,方式2 OUT DX, AL MOV DX, p0 MOV AX, 03E8H ; 1000 OUT DX, AL MOV AL, AH OUT DX, AL MOV AL, 76H ; 计数器1,方式3 OUT DX, AL MOV DX, p1 MOV AX, 01F4H ; 500 OUT DX, AL MOV AL, AH OUT DX, AL 接下来,原来的DELAY过程可能不再需要,因为定时现在由8253的中断控制。但原代码中没有使用中断服务例程,而是通过循环延时。用户需要将LED的移动速度调整为0.5秒,即每2Hz一次移动。因此,需要将原来的DELAY调用替换为等待定时器中断的触发。 但原代码中可能没有使用中断,而是通过软件延时。因此,可能需要调整DELAY过程的延时时间。但用户希望利用8253的硬件定时,所以可能需要设置中断向量,并在中断服务程序中触发LED移动。 但原代码的MAIN_LOOP中,通过调用DELAY来控制速度。如果使用硬件定时,可能需要修改代码,使其在每次定时中断时移动LED。但原代码没有中断处理部分,因此可能需要重新设计这部分。 或者,保持原有的循环结构,但调整DELAY的时间,使其与0.5秒匹配。但原来的DELAY是500次循环,可能不够。需要计算正确的延时值。 但用户明确要求使用8253的clock0和clock1串联生成2Hz方波,所以应该利用这个信号来触发中断,每次中断时移动LED。因此,需要添加中断服务例程(ISR),并在其中处理LED的移动。 但原代码中没有中断设置,需要添加相关代码。例如,设置8259中断控制器,将8253的OUT1连接到IRQ,并编写ISR。 这可能比较复杂,但用户提供的代码中没有中断相关的初始化,可能原来的代码是通过循环检测来实现的。因此,可能需要调整代码结构,使用硬件定时器来触发移动,而不是软件延时。 不过,原代码中的MAIN_LOOP中的DELAY调用可能用于控制移动速度。如果原来的DELAY是500次循环,而现在的需求是0.5秒移动一次,那么需要调整DELAY的延时时间,或者利用8253的中断来替代软件延时。 但用户可能希望利用8253的2Hz方波作为时间基准,每次方波上升沿触发一次LED移动。因此,可能需要将8253的OUT1连接到PC的某个输入引脚,然后在主循环中检测该引脚的状态变化,从而触发移动。 或者,使用中断方式,每次定时器中断时移动LED。但原代码没有中断处理,可能需要添加这部分。 考虑到代码复杂度,可能用户希望保持轮询方式,但利用8253的输出作为时间基准。例如,在MAIN_LOOP中不断检测OUT1的信号状态,当检测到上升沿时,执行LED移动。 不过,这样的实现可能比较复杂,需要额外的代码来检测信号变化。 另一种方法是,原来的DELAY函数使用8253的定时器来产生精确的延时。例如,设置8253产生0.5秒的延时,然后在DELAY过程中等待定时器完成。 不过,原代码中的DELAY是一个简单的循环,可能需要替换为基于8253的等待。 综合考虑,可能用户希望利用8253生成2Hz的方波,因此每隔0.5秒LED移动一次。因此,在代码中,每次主循环执行时,检测是否过了0.5秒,如果是,则移动LED。 但如何检测?可能需要读取8253的计数器状态,或者通过中断标志。 由于原代码没有使用中断,可能需要调整DELAY函数,使其等待8253的定时完成。例如,设置8253在方式3(方波),然后通过读取某个端口的状态来等待定时完成。 不过,这可能比较复杂,或者需要额外的硬件连接。 另一种方法是,计算所需的循环次数,使得DELAY过程大约为0.5秒。例如,假设CPU时钟频率为4.77MHz(典型的8086),每条指令的周期数,计算循环次数。但这种方法依赖于CPU速度,不够精确。 用户的要求是使用8253的硬件定时,因此应该修改代码,利用8253的中断来触发移动。 因此,需要添加中断服务例程,并在其中移动LED。同时,主循环可能只需要处理得分检测和显示。 这涉及到以下几个步骤: 1. 初始化8253,生成2Hz的中断。 2. 设置中断向量,使得每次定时中断时,调用ISR移动LED。 3. 在ISR中更新LED的位置。 4. 主循环中处理得分和胜负判断。 但原代码中没有中断处理的部分,因此需要添加这些内容。 不过,原代码可能是在模拟环境中运行,或者依赖于特定的硬件中断设置。在DOS环境下,可能需要使用硬件中断,例如IRQ0(定时器中断),但通常IRQ0已经被系统使用,所以可能需要使用其他IRQ线。 这可能超出用户提供的代码范围,但根据用户的要求,可能需要调整代码结构。 不过,用户提供的原始代码中,MAIN_LOOP中的GAME_LOOP通过调用DELAY来控制LED移动的速度。因此,可能用户希望保持这种结构,但将DELAY改为基于8253的0.5秒延时。 因此,修改DELAY函数,使其等待8253的2Hz信号。例如,通过检测8253的OUT1引脚状态,等待其变高或变低。 但如何检测?假设OUT1连接到某个端口,例如PC的某个位,可以在DELAY函数中循环检测该位,直到信号变化。 例如,如果8253的OUT1连接到PC2,那么可以在DELAY函数中: DELAY PROC NEAR PUSH AX PUSH DX WAIT_HIGH: MOV DX, pc IN AL, DX TEST AL, 04H ; 假设OUT1连接到PC2 JZ WAIT_HIGH WAIT_LOW: IN AL, DX TEST AL, 04H JNZ WAIT_LOW POP DX POP AX RET DELAY ENDP 这样,每次调用DELAY会等待一个完整的方波周期(0.5秒高,0.5秒低),或者等待一个半周期,具体取决于检测的方式。如果只需要等待0.5秒,可以只检测一次上升沿或下降沿。 例如,等待上升沿: DELAY PROC NEAR PUSH AX PUSH DX MOV DX, pc WAIT_LOW: IN AL, DX TEST AL, 04H JNZ WAIT_LOW WAIT_HIGH: IN AL, DX TEST AL, 04H JZ WAIT_HIGH POP DX POP AX RET DELAY ENDP 这样,每次DELAY会等待一个上升沿,即0.5秒的间隔。 但需要确保8253的OUT1确实连接到PC的某个位,原代码中的端口定义可能需要调整。例如,原代码中的8255的C口定义为输入,可能将OUT1连接到PC的某个引脚,比如PC2。 因此,在硬件连接上,需要将8253的OUT1连接到8255的PC2,这样程序才能检测到该信号。 在代码中,需要确认端口定义是否正确,以及检测的位是否正确。 假设这样连接,那么修改DELAY函数,使其等待8253的OUT1信号的上升沿,这样每次调用DELAY会等待0.5秒,从而控制LED的移动速度。 接下来,关于胜负判断的修改。原代码中的OUT_CHECK过程在得分后检查是否达到11分且领先2分。用户要求当任意一方达到11分或领先两分时结束游戏。 原代码中的SCORE_CHECK部分: SCORE_CHECK: MOV AX, m CMP AX, 11 JL CHECK_N MOV BX, n SUB AX, BX CMP AX, 2 JGE RESET JMP OC_EXIT CHECK_N: MOV AX, n CMP AX, 11 JL OC_EXIT MOV BX, m SUB AX, BX CMP AX, 2 JL OC_EXIT RESET: MOV m, 0 MOV n, 0 OC_EXIT: RET 这里的逻辑是,如果甲得分>=11且领先至少2分,或者乙得分>=11且领先至少2分,则重置分数。但用户要求在这种情况下结束游戏,而不是重置分数。因此,需要修改这部分代码,在满足条件时跳转到程序结束。 例如,当检测到胜利条件时,显示胜利信息并退出程序。 因此,修改OUT_CHECK过程: 在RESET标签处,改为跳转到游戏结束的处理。例如: SCORE_CHECK: MOV AX, m CMP AX, 11 JL CHECK_N MOV BX, n SUB AX, BX CMP AX, 2 JGE GAME_OVER JMP OC_EXIT CHECK_N: MOV AX, n CMP AX, 11 JL OC_EXIT MOV BX, m SUB AX, BX CMP AX, 2 JL OC_EXIT JMP GAME_OVER RESET: ; 原来的重置代码,但根据用户需求,应该结束游戏,所以可能需要删除这部分 GAME_OVER: ; 显示胜利者 ; 然后退出程序 MOV AH, 4CH INT 21H 但原代码中的OUT_CHECK过程在每次球出界时被调用,因此需要在此处判断是否满足结束条件,如果满足,则结束游戏,否则继续。 因此,修改OUT_CHECK过程: OUT_CHECK PROC NEAR CMP led, 0 JNE OC_EXIT CMP f, 1 JNE PLAYER_A INC n ; 乙得分 JMP SCORE_CHECK PLAYER_A: INC m ; 甲得分 SCORE_CHECK: ; 判断是否满足结束条件 MOV AX, m MOV BX, n ; 检查是否有一方达到11分且领先至少2分 CMP AX, 11 JL CHECK_N SUB AX, BX CMP AX, 2 JGE GAME_OVER JMP OC_EXIT CHECK_N: CMP BX, 11 JL CHECK_LEAD SUB BX, AX CMP BX, 2 JGE GAME_OVER JMP OC_EXIT CHECK_LEAD: ; 检查是否领先2分 MOV CX, AX SUB CX, BX CMP CX, 2 JGE GAME_OVER MOV CX, BX SUB CX, AX CMP CX, 2 JGE GAME_OVER JMP OC_EXIT GAME_OVER: ; 显示胜利者 ; 假设胜利信息存储在msg中 MOV AH, 09H MOV DX, OFFSET win_msg INT 21H ; 退出程序 MOV AH, 4CH INT 21H OC_EXIT: RET OUT_CHECK ENDP 同时,在数据段添加胜利信息: win_msg DB 'Game Over! Winner: $' 但需要更详细的信息,比如显示甲或乙胜利。可能需要根据m和n的值来动态生成消息,但这在汇编中比较复杂。或者,提前定义两条消息: win_a DB 'Player A wins!$' win_b DB 'Player B wins!$' 然后在GAME_OVER部分比较m和n,输出相应的消息。 因此,修改后的OUT_CHECK部分: GAME_OVER: MOV AX, m CMP AX, n JL B_WINS MOV DX, OFFSET win_a JMP SHOW_WIN B_WINS: MOV DX, OFFSET win_b SHOW_WIN: MOV AH, 09H INT 21H MOV AH, 4CH INT 21H 同时,在数据段添加: win_a DB 'Player A wins!$' win_b DB 'Player B wins!$' 这样,当游戏结束时,显示胜利者并退出。 现在,综合以上修改,整理代码: 1. 修改8253初始化,设置计数器0和1串联生成2Hz。 2. 修改DELAY函数,基于检测8253的OUT1信号。 3. 修改OUT_CHECK过程,加入游戏结束条件判断。 需要注意的是,原代码中的端口定义是否正确,特别是8253的控制端口和计数器端口是否正确。 原代码中,pn2是8253的控制端口,p0、p1、p2是计数器0、1、2的端口。因此,初始化计数器0和1: 初始化计数器0为方式2,计数器1为方式3,串联使用。 初始化代码: ; 初始化8253定时器 MOV DX, pn2 MOV AL, 34H ; 计数器0,方式2,二进制 OUT DX, AL MOV DX, p0 MOV AX, 1000 ; 03E8H OUT DX, AL MOV AL, AH OUT DX, AL MOV AL, 76H ; 计数器1,方式3,二进制 OUT DX, AL MOV DX, p1 MOV AX, 500 ; 01F4H OUT DX, AL MOV AL, AH OUT DX, AL 接下来,修改DELAY过程,假设OUT1连接到PC2: DELAY PROC NEAR PUSH AX PUSH DX MOV DX, pc WAIT_LOW: IN AL, DX TEST AL, 04H ; 检测PC2是否为低 JNZ WAIT_LOW WAIT_HIGH: IN AL, DX TEST AL, 04H ; 检测PC2是否为高 JZ WAIT_HIGH POP DX POP AX RET DELAY ENDP 这样,每次调用DELAY会等待一个上升沿,即0.5秒的间隔。 然后,在MAIN_LOOP中,GAME_LOOP中的CALL DELAY被用来控制LED移动的速度。因此,每次移动后等待0.5秒。 但是,原代码中的GAME_LOOP结构可能每次循环移动一次LED,因此需要确保每次循环只移动一次,并且等待0.5秒。 现在,关于胜负判断的修改,添加胜利消息并退出。 最后,确保所有修改后的代码符合MASM语法,并且端口定义正确。 可能还需要调整发球检测和得分显示的代码,确保在游戏结束时正确退出。 总结修改步骤: 1. 修改8253初始化代码,设置计数器0和1串联产生2Hz。 2. 修改DELAY过程,基于检测OUT1的信号。 3. 修改OUT_CHECK过程,加入游戏结束条件,显示胜利者并退出。 4. 添加胜利消息的数据定义。</think>以下是优化后的完整代码,满足技术要求和游戏规则: ```assembly .MODEL SMALL .STACK 100H .DATA ; 端口定义 pa EQU 280H pb EQU 281H pc EQU 282H pn1 EQU 283H p0 EQU 288H p1 EQU 289H p2 EQU 28AH pn2 EQU 28BH ; 数码管编码表 s DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH,39H,5EH,7BH,71H led DB 0 f DW 1 m DW 0 n DW 0 msg DB 'Please serve!',0DH,0AH,'$' win_a DB 0DH,0AH,'Player A wins!$' win_b DB 0DH,0AH,'Player B wins!$' .CODE STARTUP: MOV AX, @DATA MOV DS, AX ; 初始化8255 MOV DX, pn1 MOV AL, 81H ; A/B口输出,C口输入 OUT DX, AL ; 初始化8253(时钟0→时钟1串联) MOV DX, pn2 MOV AL, 34H ; 计数器0 方式2 OUT DX, AL MOV DX, p0 MOV AX, 1000 ; 分频值1000 OUT DX, AL MOV AL, AH OUT DX, AL MOV DX, pn2 MOV AL, 76H ; 计数器1 方式3 OUT DX, AL MOV DX, p1 MOV AX, 500 ; 分频值500 OUT DX, AL MOV AL, AH OUT DX, AL MAIN_LOOP: MOV AH, 09H MOV DX, OFFSET msg INT 21H CALL START GAME_LOOP: ; LED显示 MOV DX, pb MOV AL, led OUT DX, AL ; 数码管显示 CALL SCOREM CALL DELAY CALL SCOREN CALL DELAY ; 检测击球 MOV DX, pc IN AL, DX CMP f, 1 JNE CHECK_RIGHT TEST AL, 02H ; 检测乙击球(PC1) JZ MOVE_BALL MOV f, 0 JMP MOVE_BALL CHECK_RIGHT: TEST AL, 01H ; 检测甲击球(PC0) JZ MOVE_BALL MOV f, 1 MOVE_BALL: CALL LEDDIC CALL OUT_CHECK CMP led, 0 ; 检查球是否出界 JNE GAME_LOOP JMP MAIN_LOOP EXIT: MOV AH, 4CH INT 21H ; 子程序区 LEDDIC PROC NEAR CMP f, 1 JE LEFT SHR led, 1 ; 右移 JMP EXIT_LED LEFT: SHL led, 1 ; 左移 EXIT_LED: RET LEDDIC ENDP DELAY PROC NEAR ; 通过检测8253输出实现0.5s延时 PUSH AX PUSH DX MOV DX, pc WAIT_LOW: IN AL, DX TEST AL, 04H ; 检测PC2(8253 OUT1) JNZ WAIT_LOW WAIT_HIGH: IN AL, DX TEST AL, 04H JZ WAIT_HIGH POP DX POP AX RET DELAY ENDP SCOREM PROC NEAR MOV DX, pc MOV AL, 20H OUT DX, AL MOV BX, m MOV AL, s[BX] MOV DX, pa OUT DX, AL RET SCOREM ENDP SCOREN PROC NEAR MOV DX, pc MOV AL, 10H OUT DX, AL MOV BX, n MOV AL, s[BX] MOV DX, pa OUT DX, AL RET SCOREN ENDP START PROC NEAR ; 发球检测 START_LOOP: MOV DX, pc IN AL, DX TEST AL, 01H ; 甲发球 JZ CHECK_PC1 CALL DEBOUNCE TEST AL, 01H JZ CHECK_PC1 MOV led, 80H MOV f, 0 JMP START_EXIT CHECK_PC1: TEST AL, 02H ; 乙发球 JZ START_LOOP CALL DEBOUNCE TEST AL, 02H JZ START_LOOP MOV led, 01H MOV f, 1 START_EXIT: RET START ENDP DEBOUNCE PROC NEAR PUSH CX MOV CX, 1000 DB_LOOP: LOOP DB_LOOP POP CX RET DEBOUNCE ENDP OUT_CHECK PROC NEAR ; 胜负判断 CMP led, 0 JNE OC_EXIT CMP f, 1 JNE PLAYER_A INC n JMP SCORE_CHECK PLAYER_A: INC m SCORE_CHECK: MOV AX, m MOV BX, n ; 检查11分制规则 CMP AX, 11 JL CHECK_N SUB AX, BX CMP AX, 2 JGE GAME_OVER JMP OC_EXIT CHECK_N: CMP BX, 11 JL CHECK_DIFF SUB BX, AX CMP BX, 2 JGE GAME_OVER JMP OC_EXIT CHECK_DIFF: MOV CX, AX SUB CX, BX CMP CX, 2 JGE GAME_OVER MOV CX, BX SUB CX, AX CMP CX, 2 JL OC_EXIT GAME_OVER: MOV AH, 09H CMP m, AX JL B_WIN MOV DX, OFFSET win_a JMP SHOW_WIN B_WIN: MOV DX, OFFSET win_b SHOW_WIN: INT 21H MOV AH, 4CH INT 21H OC_EXIT: RET OUT_CHECK ENDP END ``` 主要优化点说明: 1. 定时器配置 - 使用计数器0(方式2)和计数器1(方式3)级联 - 总分频比 = 1000×500 = 500000 → 1MHz/500000 = 2Hz - 通过PC2检测8253 OUT1信号实现精确0.5s延时 2. 游戏规则 - 采用11分制比赛规则 - 添加领先2分立即获胜机制 - 游戏结束时显示获胜玩家 3. 代码优化 - 删除冗余的速度变量s1 - 优化胜负判断逻辑 - 添加清晰的胜利提示信息 该代码在保持原有硬件架构的基础上,实现了精确的定时控制和完整的比赛规则,符合DOS环境下使用MASM语法的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值