计算机系统(1) 实验四 Nim游戏

计算机系统(1) 实验四 Nim游戏

实验目的

(1)分析和理解试验指定的需解决问题。

(2)利用子程序代码设计实现相关程序。

实验内容与实验要求

实验要求:

(1)熟悉和理解LC-3的子程序指令格式。

(2)掌握利用子程序解决问题的思路,加深对底层硬件的理解。

实验内容:

⑴ 在游戏开始时,你应该显示游戏界面的初始化状态。具体包括:在每行石子的前面,你应该先输出行的名称,例如“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 1 Wins.

实验步骤

(1)根据题目要求编写程序代码。注意寄存器的保存和恢复。本程序使用了四个子程序,将程序涉及需要判断的内容写到子程序中,使主程序更加简洁。
在这里插入图片描述
在这里插入图片描述
(2)输入测试数据,判断代码是否正确。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过运行测试,程序结果与样例一致,代码编写正确。

实验代码及注释

	.ORIG	x3000
;R1存放ROWA棋子的数量,R2存放ROWB棋子的数量,R3存放ROWC棋子的数量,R4输入行号,R5输入减少的棋子数
	AND	R1,R1,#0;
	ADD	R1,R1,#3;R1初始值为3,存放ROWA棋子的数量
	AND	R2,R2,#0;
	ADD	R2,R2,#5;R2初始值为5,存放ROWB棋子的数量
	AND	R3,R3,#0;
	ADD	R3,R3,#8;R3初始值为8,存放ROWC棋子的数量
;主程序代码
	JSR	SHOW

;		
NEXT1	JSR	P1;输入正确后判断是否结束游戏
;
	ADD	R1,R1,#0
	BRnp	SHOW1
	ADD	R2,R2,#0
	BRnp	SHOW1
	ADD	R3,R3,#0
	BRz	OVER1;判断R1,R2,R3是否为0,同时为0结束游戏
SHOW1	LD	R0,NEXTLINEMAIN
	TRAP	x21
	JSR	SHOW
;
	
NEXT2	JSR	P2;输入正确后判断是否结束游戏
	ADD	R1,R1,#0
	BRnp	SHOW2
	ADD	R2,R2,#0
	BRnp	SHOW2
	ADD	R3,R3,#0
	BRz	OVER2;判断R1,R2,R3是否为0,同时为0结束游戏
SHOW2	LD	R0,NEXTLINEMAIN
	TRAP	x21
	JSR	SHOW
	BRnzp	NEXT1
;
OVER1	LEA	R0,PLAYER2WIN
	TRAP	x22
	BRnzp	OVER
OVER2	LEA	R0,PLAYER1WIN
	TRAP	x22
OVER	HALT
;主程序数据区
NEXTLINEMAIN	.FILL	x000A
PLAYER1WIN	.STRINGZ	"Player 1 Wins."
PLAYER2WIN	.STRINGZ	"Player 2 Wins."
;子程序P1代码:子程序P1的作用是轮到选手1输入,判断输入是否正确,直到输入正确为止 
P1	ST	R7,P1STORER7
AGAINP1	LEA	R0,PLAYER1
	TRAP	x22
	TRAP	x20
	TRAP	x21
	ADD	R4,R0,#0;将输入的第一个字符存入R4,即行号
	TRAP	x20
	TRAP	x21
	ADD	R5,R0,#0;将输入的第二个字符存入R5,即需要减少的棋子数
	LD	R0,NEXTLINEP1
	TRAP	x21
	JSR	P3
	ADD	R6,R6,#0;如果输出错误则持续输出
	BRp	OUTP1
	BRnzp	AGAINP1
OUTP1	LD	R0,NEXTLINEP1
	TRAP	x21
	LD	R7,P1STORER7
	RET
;子程序P1数据区
P1STORER7	.FILL	0
NEXTLINEP1	.FILL	x000A
PLAYER1		.STRINGZ	"Player 1, choose a row and number of rocks: "


;子程序P2代码:子程序P2的作用是轮到选手2输入,判断输入是否正确,直到输入正确为止
P2	ST	R7,P2STORER7
AGAINP2	LEA	R0,PLAYER2
	TRAP	x22
	TRAP	x20
	TRAP	x21
	ADD	R4,R0,#0;将输入的第一个字符存入R4,即行号
	TRAP	x20
	TRAP	x21
	ADD	R5,R0,#0;将输入的第二个字符存入R5,即需要减少的棋子数
	LD	R0,NEXTLINEP2
	TRAP	x21
	JSR	P3
	ADD	R6,R6,#0;如果输出错误则持续输出
	BRp	OUTP2
	BRnzp	AGAINP2
OUTP2	LD	R7,P2STORER7
	RET	

;子程序P2数据区
P2STORER7	.FILL	0
NEXTLINEP2	.FILL	x000A
PLAYER2		.STRINGZ	"Player 2, choose a row and number of rocks: "

;子程序P3代码:子程序P3的作用是判断输入的字母和号码是否合法,合法返回0,不合法返回1 (R6为返回值01)
P3	ST	R7,P3STORER7	
	LD	R6,A
	ADD	R6,R6,R4
	BRz	JUDGER5A
	LD	R6,B
	ADD	R6,R6,R4
	BRz	JUDGER5B
	LD	R6,C
	ADD	R6,R6,R4
	BRz	JUDGER5C
	BRnzp	FLVAL
JUDGER5A	LD	R6,ZERO
		ADD	R6,R6,R5
		BRnz	FLVAL;判断R5是否小于等于0
		NOT	R6,R1
		ADD	R6,R6,#1;
		LD	R7,ZERO
		ADD	R6,R6,R7;因为输入的值为ASC码值,R6为R1的相反数,目的是判断棋子数目是否在范围内
		ADD	R6,R6,R5
		BRp	FLVAL;如果减去的棋子数目大于原本棋子数目,则发生错误
		ADD	R6,R5,R7;ASC码值转换为整数值
		NOT	R6,R6
		ADD	R6,R6,#1;转为负数让R1减去
		ADD	R1,R1,R6
		AND	R6,R6,#0
		ADD	R6,R6,#1;输入合法R6为1
		BRnzp	OUTP3
	
JUDGER5B	LD	R6,ZERO
		ADD	R6,R6,R5
		BRnz	FLVAL
		NOT	R6,R2
		ADD	R6,R6,#1;
		LD	R7,ZERO
		ADD	R6,R6,R7;因为输入的值为ASC码值,R6为R2的相反数,目的是判断棋子数目是否在范围内
		ADD	R6,R6,R5
		BRp	FLVAL;如果减去的棋子数目大于原本棋子数目,则发生错误
		ADD	R6,R5,R7;ASC码值转换为整数值
		NOT	R6,R6
		ADD	R6,R6,#1;转为负数让R1减去
		ADD	R2,R2,R6
		AND	R6,R6,#0
		ADD	R6,R6,#1
		BRnzp	OUTP3


JUDGER5C	LD	R6,ZERO
		ADD	R6,R6,R5
		BRnz	FLVAL
		NOT	R6,R3
		ADD	R6,R6,#1;
		LD	R7,ZERO
		ADD	R6,R6,R7;因为输入的值为ASC码值,R6为R1的相反数,目的是判断棋子数目是否在范围内
		ADD	R6,R6,R5
		BRp	FLVAL;如果减去的棋子数目大于原本棋子数目,则发生错误
		ADD	R6,R5,R7;ASC码值转换为整数值
		NOT	R6,R6
		ADD	R6,R6,#1;转为负数让R1减去
		ADD	R3,R3,R6
		AND	R6,R6,#0
		ADD	R6,R6,#1
		BRnzp	OUTP3

FLVAL	LEA	R0,FALSE
	TRAP	x22
	LD	R0,NEXTLINE3
	TRAP	x21
	AND	R6,R6,#0;输入不合法R6为0
OUTP3	LD	R7,P3STORER7
	RET		

;子程序P3数据区
P3STORER7	.FILL	0
A		.FILL	#-65;A的ASC码整数值
B		.FILL	#-66
C		.FILL	#-67
ZERO		.FILL	#-48
NEXTLINE3	.FILL	x000A
FALSE		.STRINGZ	"Invalid move. Try again."

;子程序SHOW代码:子程序SHOW的作用是输出游戏状态
SHOW	ST	R1,STORER1;把R1的值先存进内存
	ST	R2,STORER2;
	ST	R3,STORER3;
	ST	R7,STORER7;
;先输出ROWA
SHOWA	LEA	R0,ROWA
	TRAP	x22
JUDGER1	ADD	R1,R1,#0
	BRz	SHOWB
	LEA	R0,SHOWO
	TRAP	X22	
	ADD	R1,R1,#-1
	BRnzp	JUDGER1
;输出ROWB
SHOWB	LD	R0,NEXTLINE
	TRAP	x21
	LEA	R0,ROWB
	TRAP	x22
JUDGER2	ADD	R2,R2,#0
	BRz	SHOWC
	LEA	R0,SHOWO
	TRAP	x22
	ADD	R2,R2,#-1
	BRnzp	JUDGER2
;输出ROWC
SHOWC	LD	R0,NEXTLINE
	TRAP	x21
	LEA	R0,ROWC
	TRAP	x22
JUDGER3	ADD	R3,R3,#0
	BRz	SHOWOUT
	LEA	R0,SHOWO
	TRAP	x22
	ADD	R3,R3,-1
	BRnzp	JUDGER3
SHOWOUT	LD	R0,NEXTLINE
	TRAP	x21
	LD	R1,STORER1;还原R1的值
	LD	R2,STORER2
	LD	R3,STORER3
	LD	R7,STORER7
	RET


;子程序SHOW数据区
SHOWO		.STRINGZ	"o"
STORER1		.FILL	0
STORER2		.FILL	0
STORER3		.FILL	0
STORER7		.FILL	0
NEXTLINE	.FILL	x000A
ROWA		.STRINGZ	"ROW A: "
ROWB		.STRINGZ	"ROW B: "
ROWC		.STRINGZ	"ROW C: "
	
;
	.END

总结

通过本次实验,我掌握了子程序的编写方法,运用子程序可以使主程序更加简洁,也令调试更加方便。


版权声明:本文为weixin_52827539原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。