持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天, 点击查看活动详情
Nim是一个简单的双人游戏,可能起源于中国。游戏中使用的计数器类型有很多种类,如石头、火柴、苹果等。游戏界面被划分为很多行,每行中有数量不等的计数器:
计数器数量
○○○○○○
○○○○○○○○○○
本次实验对Nim游戏做了一些小的改变,具体如下:游戏界面由三行组成,计数器类型为石头,其中A行包含3个石头,B行包含5个石头,C行包含8个石头。
规则如下:
⑴ 每个玩家轮流从某一行中移除一个或多个石头。
⑵ 一个玩家不能在一个回合中从多个行中移除石头。
⑶ 当某个玩家从游戏界面上移除最后剩余的石头时,此时游戏结束,该玩家获胜。
⑴ 在游戏开始时,你应该显示游戏界面的初始化状态。具体包括:在每行石头的前面,你应该先输出行的名称,例如“ROW A”。你应该使用ASCII字符小写字母“o”(ASCII码 x006F)来表示石头。游戏界面的初始化状态应该如下:
ROW A: ooo
ROW B: ooooo
ROW C: oooooooo
⑵ 游戏总是从玩家1先开始,之后玩家1和玩家2轮流进行。在每一个回合开始时,你应该输出轮到哪一个玩家开始,并提示玩家进行操作。例如,对于玩家1,应该有如下显示:
Player 1,choose a row and number of rocks:
⑶ 为了指定要移除哪一行中的多少石头,玩家应该输入一个字母后跟一个数字(输入结束后不需要按Enter键),其中字母(A,B或C)指定行,数字(从1到所选行中石头的数量)指定要移除的石头的数量。你的程序必须要确保玩家从有效的行中移除有效数量的石头,如果玩家输入无效,你应该输出错误提示信息并提示该玩家再次进行输入。例如,如果轮到玩家1:
Player 1, choose a row and number of rocks: D4
Invalid move. Try again.
Player 1, choose a row and number of rocks: A9
Invalid move. Try again.
Player 1, choose a row and number of rocks: A*
Invalid move. Try again.
Player 1, choose a row and number of rocks: &4
Invalid move. Try again.
Player 1, choose a row and number of rocks:
你的程序应保持提示玩家,直到玩家选择有效的输入为止。确保你的程序能够回显玩家的输入到屏幕上,当回显玩家的输入后,此时应该输出一个换行符(ASCII码x000A)使光标指向下一行。
⑷ 玩家选择有效的输入后,你应该检查获胜者。如果有一个玩家获胜,你应该显示相应的输出来表明该玩家获胜。如果没有胜利者,你的程序应该更新游戏界面中每行石头的数量,重新显示更新的游戏界面,并轮到下一个玩家继续。
⑸ 当某个玩家从游戏界面上移除最后的石头时,游戏结束。此时,你的程序应该显示获胜者然后停止。例如,如果玩家2移除了最后的石头,你的程序应该输出一下内容:
Player 2 Wins.
样例输入/输出
ROW A: ooo
ROW B: ooooo
ROW C: oooooooo
Player 1, choose a row and number of rocks: B2
ROW A: ooo
ROW B: ooo
ROW C: oooooooo
Player 2, choose a row and number of rocks: A1
ROW A: oo
ROW B: ooo
ROW C: oooooooo
Player 1, choose a row and number of rocks: C6
ROW A: oo
ROW B: ooo
ROW C: oo
Player 2, choose a row and number of rocks: G1
Invalid move. Try again.
Player 2, choose a row and number of rocks: B3
ROW A: oo
ROW B:
ROW C: oo
Player 1, choose a row and number of rocks: A3
Invalid move. Try again.
Player 1, choose a row and number of rocks: C2
ROW A: oo
ROW B:
ROW C:
Player 2, choose a row and number of rocks: A1
ROW A: o
ROW B:
ROW C:
Player 1, choose a row and number of rocks: A*
Invalid move. Try again.
Player 1, choose a row and number of rocks: &4
Invalid move. Try again.
Player 1, choose a row and number of rocks: A1
Player 1 Wins.
----- Halting the processor -----
提示与建议
⑴ 记住,程序中所有的输入输出使用ASCII字符,你应该负责进行必要的转换。
⑵ 从键盘中输入字符你应该使用TRAP x20(GETC)指令,同时为了回显输入的字符到屏幕上,你应该使用TRAP x21(OUT)指令,该指令紧跟在TRAP x20指令之后。
⑶ 你应该在适当的时候使用子程序。
⑷ 在你编写的每个子程序中,应该保存并还原所使用的任何寄存器。这将避免你在调试过程中遇到问题。
⑸ 在一个回合中,玩家的输入必须包含指定为A,B或C(即大写字母)的行,后面紧跟不大于该行仍然存在的石头数量的数字。
① 你应该设置程序的开始地址在x3000(如,程序的第一行指令应该为 .ORIG x3000)
② 源文件命名为nim.asm
.orig x3000
again jsr print
jsr datain1
jsr print
jsr datain2
br again
print st r0,save_r0
st r1,save_r1
st r7,save_r7
lea r0,row_a
ld r0,stone
ld r1,num_a
loop_a out
add r1,r1,#-1
brp loop_a
ld r0,cr
lea r0,row_b
ld r0,stone
ld r1,num_b
loop_b out
add r1,r1,#-1
brp loop_b
ld r0,cr
lea r0,row_c
ld r0,stone
ld r1,num_c
loop_c out
add r1,r1,#-1
brp loop_c
ld r0,cr
ld r0,save_r0
ld r1,save_r1
ld r7,save_r7
save_r0 .fill #0
save_r1 .fill #0
stone .fill x006f
cr .fill x000d
row_a .stringz "ROW A: "
row_b .stringz "ROW B: "
row_c .stringz "ROW C: "
num_a .fill #3
num_b .fill #5
num_c .fill #8
cue1 st r0,save_r0
st r7,save_r7
lea r0,play1
ld r0,save_r0
ld r7,save_r7
play1 .stringz "Player 1,choose a row and number of rocks:"
cue2 st r0,save_r0
st r7,save_r7
lea r0,play2
ld r0,save_r0
ld r7,save_r7
play2 .stringz "Player 2,choose a row and number of rocks:"
save_r7 .fill #0
datain1 st r0,save_r0
st r2,save_r2
st r3,save_r3
st r7,saver7
try1 jsr cue1
add r2,r0,#0
not r2,r2
add r2,r2,#1
add r3,r0,#0
ld r0,lf
test1a ld r0,char_a
add r0,r2,r0
brnp test1b
ld r0,char_0
not r0,r0
add r0,r0,#1
add r0,r0,r3
brn error1
ld r3,num_a
not r0,r0
add r0,r0,#1
add r3,r0,r3
brn error1
st r3,num_a
ld r3,sum_abc
add r3,r3,r0
brz win1
st r3,sum_abc
br save
test1b ld r0,char_b
add r0,r2,r0
brnp test1c
ld r0,char_0
not r0,r0
add r0,r0,#1
add r0,r0,r3
brn error1
ld r3,num_b
not r0,r0
add r0,r0,#1
add r3,r0,r3
brn error1
st r3,num_b
ld r3,sum_abc
add r3,r3,r0
brz win1
st r3,sum_abc
br save
test1c ld r0,char_c
add r0,r2,r0
brnp error1
ld r0,char_0
not r0,r0
add r0,r0,#1
add r0,r0,r3
brn error1
ld r3,num_c
not r0,r0
add r0,r0,#1
add r3,r0,r3
brn error1
st r3,num_c
ld r3,sum_abc
add r3,r3,r0
brz win1
st r3,sum_abc
br save
win1 ld r0,lf
lea r0,wins1
error1 lea r0,invalid
ld r0,lf
br try1
datain2 st r0,save_r0
st r2,save_r2
st r3,save_r3
st r7,saver7
try2 jsr cue2
add r2,r0,#0
not r2,r2
add r2,r2,#1
add r3,r0,#0
ld r0,lf
test2a ld r0,char_a
add r0,r2,r0
brnp test2b
ld r0,char_0
not r0,r0
add r0,r0,#1
add r0,r0,r3
brn error2
ld r3,num_a
not r0,r0
add r0,r0,#1
add r3,r0,r3
brn error2
st r3,num_a
ld r3,sum_abc
add r3,r3,r0
brz win2
st r3,sum_abc
br save
test2b ld r0,char_b
add r0,r2,r0
brnp test2c
ld r0,char_0
not r0,r0
add r0,r0,#1
add r0,r0,r3
brn error2
ld r3,num_b
not r0,r0
add r0,r0,#1
add r3,r0,r3
brn error2
st r3,num_b
ld r3,sum_abc
add r3,r3,r0
brz win2
st r3,sum_abc
br save
test2c ld r0,char_c
add r0,r2,r0
brnp error2
ld r0,char_0
not r0,r0
add r0,r0,#1
add r0,r0,r3
brn error2
ld r3,num_c
not r0,r0
add r0,r0,#1
add r3,r0,r3
brn error2
st r3,num_c
ld r3,sum_abc
add r3,r3,r0
brz win2
st r3,sum_abc
br save
win2 ld r0,lf
lea r0,wins2
error2 lea r0,invalid
ld r0,lf
br try2
save ld r0,lf
ld r0,saver0
ld r2,save_r2
ld r3,save_r3
ld r7,saver7
lf .fill x000a
char_a .fill x0041
char_b .fill x0042
char_c .fill x0043
char_0 .fill x0030
wins1 .stringz "Player 1 Wins."
wins2 .stringz "Player 2 Wins."
invalid .stringz "Invalid move. Try again."
sum_abc .fill #16
saver0 .fill #0
save_r2 .fill #0
save_r3 .fill #0
saver7 .fill #0
程序总体设计
核心数据结构
1、显示游戏页面
首先将寄存器的值存进内存,待子函数完成任务后再将该内存的值存进寄存器,用伪操作.stringz开辟内存用来存储字符串,将Row A、Row B和Row C的石头数目也存储在内存中。
先用LEA指令将字符串的首地址存进R0,然后通过PUTS输出,用LD指令将字符o的ascll码存进R0,然后用LD指令将石头的数目存进R1,R1作为计数器,用OUT循环输出字符o,最后用LD指令将换行符的ascll码存进R0,用OUT输出。
2、用户操作
(1)输出提示
用伪操作.stringz将提示字符串存进内存中,先将用到的寄存器R0和R7的值存进内存保存起来,然后用LEA指令将字符串的首地址存进R0,用PUTS输出提示,然后将R0和R7的值恢复。
(2)用户输入
用GETC读取输入的第一个数据,然后用OUT回显,ADD指令将R0的数据转入R2,然后用NOT将R2取反,ADD将R2加一,即将R2取负,再用GETC读取输入的第二个数据,OUT回显,ADD指令将R0的数据转入R3。
(3)判断数据是否有效
用伪操作.fill将字符A、B和C的ascll码存进内存,用LD指令将相应字符的ascll码存进R0,然后ADD指令将R0和R2相加的结果存在R0,通过判断R0是否为0来判断是A、B、C或无效输入。
(4)取石头
用LD指令将字符0的ascll码存进R0,然后将R0取负,与R3相加的结果存放到R0中,然后用LD指令将石头的数目存进R3,将R0取负,与R3相加的结果存进R3,最后将R3的值存进内存。
1、显示游戏页面
2、player操作
_心灵骇客_
36.4k