【计算机系统】LC-3简单游戏设计

Alex_Shen
2021-05-17 / 0 评论 / 0 点赞 / 115 阅读 / 5,541 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-04-06,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

代码:Github仓库地址

NIM游戏

Nim是一个简单的双人游戏,可能起源于中国。游戏中使用的计数器类型有很多种类,如石子、火柴、苹果等。游戏界面被划分为很多行,每行中有数量不等的计数器,如图1所示:

行号 计数器数量
1 ○○○
2 ○○○○○○
…… ……
n ○○○○○○○○○○
图1 游戏界面

1.游戏规则

本次实验对Nim游戏做了一些小的改变,具体如下:游戏界面由三行组成,计数器类型为石子,其中A行包含3个石子,B行包含5个石子,C行包含8个石子。

规则如下:

  1. 每个玩家轮流从某一行中移除一个或多个石子。
  2. 一个玩家不能在一个回合中从多个行中移除石子。
  3. 当某个玩家从游戏界面上移除最后一个石子时,此时游戏结束,该玩家战败。

2.实验要求

  1. 在游戏开始时,你应该显示游戏界面的初始化状态。具体包括:在每行石子的前面,你应该先输出行的名称,例如“ROW A”。你应该使用ASCII字符小写字母“o”(ASCII码 x006F)来表示石子。游戏界面的初始化状态应该如下:

ROW A: ooo
ROW B: ooooo
ROW C: oooooooo

  1. 游戏总是从玩家1先开始,之后玩家1和玩家2轮流进行。在每一个回合开始时,你应该输出轮到哪一个玩家开始,并提示玩家进行操作。例如,对于玩家1,应该有如下显示:

Player 1,choose a row and number of rocks:

  1. 为了指定要移除哪一行中的多少石子,玩家应该输入一个字母后跟一个数字(输入结束后不需要按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)使光标指向下一行。

  1. 玩家选择有效的输入后,你应该检查获胜者。如果有一个玩家获胜,你应该显示相应的输出来表明该玩家获胜。如果没有胜利者,你的程序应该更新游戏界面中每行石子的数量,重新显示更新的游戏界面,并轮到下一个玩家继续。
  2. 当某个玩家从游戏界面上移除最后一个石子时,游戏结束。此时,你的程序应该显示获胜者然后停止。例如,如果玩家2移除了最后一个石子,你的程序应该输出一下内容:

Player 1 Wins.

3.样例输入/输出

注意:你的程序中输入输出的格式必须完全和样例中的格式相一致

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 2 Wins.
----- Halting the processor -----

4.提示与建议

  1. 记住,程序中所有的输入输出使用ASCII字符,你应该负责进行必要的转换。
  2. 从键盘中输入字符你应该使用TRAP x20(GETC)指令,同时为了回显输入的字符到屏幕上,你应该使用TRAP x21(OUT)指令,该指令紧跟在TRAP x20指令之后。
  3. 你应该在适当的时候使用子程序。
  4. 在你编写的每个子程序中,应该保存并还原所使用的任何寄存器。这将避免你在调试过程中遇到问题。
  5. 在一个回合中,玩家的输入必须包含指定为A,B或C(即大写字母)的行,后面紧跟不大于该行仍然存在的石子数量的数字。

提示:
① 你应该设置程序的开始地址在x3000(如,程序的第一行指令应该为 .ORIG x3000)
② 源文件命名为nim.asm

实验目的

  1. 分析和理解指定的需解决问题。
  2. 利用LC-3的汇编语言设计实现相关程序。
  3. 通过LC-3仿真器调试和运行相关程序并得到正确的结果。

实验内容

实现NIM游戏,规则AB玩家轮流拿取石头,取走最后一块石头的得玩家失败

实验要求

ABC石堆,初始石头数量分别为3,5,8;

实验步骤

  1. 设计程序流程

打印棋盘 -> 玩家一取石子 -> 检查玩家一是否失败 ->
打印棋盘 -> 玩家二取石子 -> 检查玩家二是否失败 ->
打印棋盘 ->…
循环,直至玩家二或玩家二其中一名玩家获胜

  1. 用汇编语言完成主程序设计(数据区见实验步骤4)
			.ORIG X3000;
			AND	R1,R1,#0;
			ADD	R1,R1,#3;
			AND	R2,R2,#0;
			ADD	R2,R2,#5;
			AND	R3,R3,#0;
			ADD	R3,R3,#8;初始化石子数目,r1存A,r2存B,r3存C
			LD	R5,CHAR;
			LD	R6,I;
CONTINUE	JSR	PRINT;打印棋盘
			JSR	AINPUTDATA;玩家一输入数据
			LD	R4,WINNERID;
			ADD	R4,R4,#-2;
			BRZ	WINNERISB;检查胜者是否是选手二
			LD	R0,NEWLINE;
			OUT;			换行
			JSR	PRINT;打印棋盘
			JSR	BINPUTDATA;玩家一输入数据
			LD	R4,WINNERID;
			ADD	R4,R4,#-1;
			BRZ	WINNERISA;检查胜者是否是选手二
			LD	R0,NEWLINE;
			OUT;			换行
			BRNZP	CONTINUE;
			PUTS;
			BRNZP	OVER;输出玩家A获胜信息
WINNERISB	LD	R0,NEWLINE;
			OUT;
			LEA	R0,BWIN;
			PUTS;
			BRNZP	over;输出玩家B获胜信息
over		HALT;
;以上是主程序部分

  1. 设计子程序1(数据区见实验步骤4)

目的:根据参数r1r2r3的数量,打印棋盘

;子程序1 输出棋盘 参数r1r2r3
PRINT	ST	R4,SAVER4;
		ST	R0,SAVER0;
		ST	R7,SAVER7;
		LEA	R4,ROWA;
		ADD	R0,R4,#0;
		PUTS;			输出"ROWA:"		
		LD	R0,ASCofO;	准备输出o
		ADD	R4,R1,#0;	R4计数器,记录A石子数量
		BRNZ	NEXT1;
OUTA	OUT;
		ADD	R4,R4,#-1;
		BRP	OUTA;
NEXT1	LD	R0,NEWLINE;
		OUT;			换行
		LEA	R4,ROWB;
		ADD	R0,R4,#0;
		PUTS;			输出"ROWB:"		
		LD	R0,ASCofO;	准备输出o
		ADD	R4,R2,#0;	R4计数器,记录B石子数量
		BRNZ	NEXT2;
OUTB	OUT;
		ADD	R4,R4,#-1;
		BRP	OUTB;
NEXT2	LD	R0,NEWLINE;
		OUT;			换行
		LEA		R4,ROWC;
		ADD	R0,R4,#0;
		PUTS;			输出"ROWC:"		
		LD	R0,ASCofO;	准备输出o
		ADD	R4,R3,#0;	R4计数器,记录C石子数量
		BRNZ	NEXT3
OUTC	OUT;
		ADD	R4,R4,#-1;
		BRP	OUTC;
NEXT3	LD	R0,NEWLINE;
		OUT;			换行	
		LD	R4,SAVER4;
		LD	R0,SAVER0;
		LD	R7,SAVER7;
		RET;
  1. 设计子程序2,3(数据区见实验步骤4)

目的:
玩家一/二输入操作数,完成石子搬移,参数r1r2r3
过程中会判断操作数1,2是否满足条件
如果石堆ABC数量同时为0,说明玩家失败,另一名玩家获胜,并将获胜选手ID(1或2)存入WINNERID
注:子程序2,3基本相同,区别在于区分玩家一二,故只展示子程序2

;子程序2 作用是玩家一输入操作数,完成石子搬移,参数r1r2r3
AINPUTDATA		ST		R0,SAVER0;	
				ST		R7,SAVER7;
				ST		R5,SAVER5;
				ST		R6,SAVER6;
AGAIN1			LEA		R0,PLAYER1;
				PUTS;
				GETC;接受字母指令
				OUT;
				AND	R5,R5,#0;
				ADD	R5,R0,#0;将字母ASCII码复制到R5
				GETC;
				OUT;接受数字指令
				AND	R6,R6,#0;
				LD		R6,NUMASC;
				ADD	R6,R0,R6;将数字复制到R5
				LD		R0,NEWLINE;
				OUT;换行
				ADD	R6,R6,#0;
				BRNZ	ERROR1;数字小于0,输入错误
				LD		R4,MINUSA;
				ADD	R4,R5,R4;字母ABC对应0,1,2
				BRN	ERROR1;
				ADD	R4,R4,#-2;字母ABC对应-2,-1,0
			BRP		ERROR1;字母输入错误
				BRNZP	RIGHT1;满足两项,输入正确
ERROR1			LEA		R0,TRYAGAIN;
				PUTS;输出错误信息,重新输入
				LD		R0,NEWLINE;
				OUT;换行
				BRNZP	AGAIN1;返回重新输入
RIGHT1			ADD	R4,R6,#0;
				NOT	R4,R4;
				ADD	R4,R4,#1;R4数字取相反数
				LD		R0,MINUSB;
				ADD	R0,R5,R0;R0存字母,ABC对应-1,0,1
				BRZP	A1;如果是A继续,否则跳过
				ADD	R7,R4,R1;
				BRN	ERROR1;判断数字是否大于剩余石头数量
				ADD	R1,R7,#0;更新A石堆数量
				BRZ		WIN111;若更新后A石堆数量为0,检查游戏是否结束
				BRNZP	JUMP1;
WIN111			AND	R7,R7,#0;
				ADD	R7,R7,R1;
				ADD	R7,R7,R2;
				ADD	R7,R7,R3;
				BRNP	JUMP1;
				AND	R4,R4,#0;
				ADD	R4,R4,#2;若剩余石头数量为0,则玩家二胜利
				ST		R4,WINNERID;
				BRNZP	JUMP1;
A1				ADD	R0,R0,#0;
				BRP		A2;如果是B继续,否则跳过
				ADD	R7,R4,R2;
				BRN	ERROR1;判断数字是否大于剩余石头数量
				ADD	R2,R7,#0;更新B石堆数量
				BRZ		WIN111;若更新后B石堆数量为0,检查游戏是否结束
				BRNZP	JUMP1;
A2				ADD	R7,R4,R3;
				BRN	ERROR1;判断数字是否大于剩余石头数量
				ADD	R3,R7,#0;更新C石堆数量
				BRZ		WIN111;若更新后C石堆数量为0,检查游戏是否结束
				BRNZP	JUMP1;
JUMP1			LD	R0,SAVER0;
				LD	R5,SAVER5;
				LD	R6,SAVER6;
				LD	R7,SAVER7;
				RET;
  1. 数据区
WINNERID		.BLKW		1;
MINUSA			.FILL		XFFBF;
MINUSB			.FILL		XFFBE
NEWLINE			.FILL		X000A;
ASCofO			.FILL		X006F;
SAVER0			.FILL		X0;
SAVER4			.FILL		X0;
SAVER5			.FILL		X0;
SAVER6			.FILL		X0;
SAVER7			.FILL		X0;
NUMASC			.FILL		XFFD0;
AWIN			.STRINGZ	"PLAYER 1 Wins.";
BWIN			.STRINGZ	"Player 2 Wins.";
ROWA			.STRINGZ	"ROW A:";
ROWB			.STRINGZ	"ROW B:";
ROWC			.STRINGZ	"ROW C:";
TRYAGAIN		.STRINGZ	"Invalid move. Try again.";
PLAYER1			.STRINGZ	"Player 1, choose a row and number of rocks:";
PLAYER2			.STRINGZ	"Player 2, choose a row and number of rocks:";
.END;
  1. 寄存器用途解释

R0:字符输出或字符串输出
R1:记录Row A石头数量
R2:记录Row B石头数量
R3:记录Row C石头数量
R4:临时寄存器,存储计算中间变量
R5:存储输入字母
R6:储存输入数字
R7:储存主程序地址(有时用作临时寄存器)

  1. 实验结果验证
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    经测试,若输入字符不是ABC会报错,输入数字非数码或大于剩余石头数或等于零也会报错。并且最终获胜人提示正确,实验结果正确。
0

评论区