【深圳大学计算机系统1】实验四 简易四子棋

一、实验目的

分析和理解指定的需解决问题。

利用LC-3的汇编代码设计实现相关程序。

通过LC-3仿真器调试和运行相关程序并得到正确的结果。

二、实验内容

用LC3汇编语言实现简易四子棋。

规则:

两位选手依次轮流落子;

选手不能悔棋;

有子的地方不能继续落子;

直到有一方的四个棋子能够连成一条水平线、垂直线或者是对角线;

如果棋盘已满,无人获胜,则平局。

游戏最初时打印空棋盘,用"-" (即ASCII 码 x002D)来表示该处为空,"O"(ASCII 码 x004F)表示第一位选手的棋子,"X" (ASCII 码 x0058)来表示第二位选手的棋子,为了让棋盘更易于观察,在各列间加一个空格,第6列之后不要添加,初始棋盘应该如下:

- - - - - -

- - - - - -

- - - - - -

- - - - - -

- - - - - -

- - - - - -

选手一始终先下第一步棋,然后两者轮流落子,在每次落子之后,应该打印该选手的信息,提示他落子,以选手一为例,应该打印信息如下:

Player 1, choose a column:

       为了明确选手的落子的位置,该选手应该输入数字1-6,然后回车,数字1-6指示在落子所在的列,从左到右,无需输入行号,程序应默认从行号6到行号1递减的顺序填入该棋子,若前后输入的列号相同,则行号减一。例如,如果选手第一次在左起第二列落子,应该输入2,然后回车,则该棋子落在行6列2处,当后面输入的列号再次为2时,则将棋子落子行5列2处,以此类推,详情见后续示例输出。程序应该确保选手输入的数字对应正确的列的范围,如果输入不合理,应该输出一条错误信息,提示该选手继续输入,例如,如果对于选手一:

       Player 1, choose a column: D

    Invalid move. Try again.

    Player 1, choose a column: 7

    Invalid move. Try again.

Player 1, choose a column:

       程序应该一直提示该选手,知道输入正确的数字,当用户输入完成,程序应通过显示回馈给选手,然后通过换行符(ASCII 码 x000A)换行。

       当选手输入成功后,程序应打印更新后的棋盘,并检查是否有人获胜,如果没人获胜,则轮到下一位输入。

       当其中一位获胜或平局时,游戏结束,程序显示最后的棋盘情况并终止(Halt)。例如,如果选手二有四子相连,应该输出:

Player 2 Wins.

如果平局,程序应该输出:

Tie Game.

三、实验步骤与结果

按如下架构编写代码

代码如下


.ORIG x3000

		BRnzp pre_main	; 从main函数开始

; ----------------------------------------------------

; print 函数 打印矩阵 矩阵首地址存在mat0x标号
; 标号解释:
; pr_l1	print loop 1	外循环
; pr_l2	print loop 2	内循环
; pr_c1	print case 1	情况1 这是玩家1的棋子
; pr_c2	print case 2	情况2这是玩家2的棋子
; pr_l2ed	loop 2 end	循环2结束

print	ST R0, save_R0	; 保存寄存器
		ST R1, save_R1
		ST R2, save_R2
		ST R3, save_R3
		ST R4, save_R4
		ST R5, save_R5
		ST R6, save_R6
		ST R7, save_R7
	
		AND R1, R1, #0	; R1=6
		ADD R1, R1, #6
		LEA R3, mat0x	; R3保存矩阵首地址

pr_l1	AND R2, R2, #0	; R2=6
		ADD R2, R2, #6
		
pr_l2	LDR R4, R3, #0	; R4=M[R3]取矩阵数据
		ADD R3, R3, #1	; R3+=1
		
		ADD R5, R4, #0	; 跳转判断
		BRz pr_c3
		ADD R5, R4, #-1	; mat=1表示玩家1棋子
		BRz pr_c1
		ADD R5, R4, #-2	; mat=2表示玩家2棋子
		BRz pr_c2

pr_c1	LD R0, p1		; 情况1玩家1棋子
		TRAP x21
		BRnzp pr_l2ed	
pr_c2	LD R0, p2		; 情况2玩家2棋子
		TRAP x21
		BRnzp pr_l2ed	
pr_c3	LD R0, no_p		; 情况3无棋子
		TRAP x21	

pr_l2ed	LD R0, space	; 打印空格
		TRAP x21
		ADD R2, R2, #-1	
		BRp pr_l2		; 循环2到此结束

		LD R0, nextLi	; 打印回车
		TRAP x21
		ADD R1, R1, #-1
		BRp pr_l1		; 循环1到此结束
	
		LD R0, save_R0	; 恢复寄存器
		LD R1, save_R1
		LD R2, save_R2
		LD R3, save_R3
		LD R4, save_R4
		LD R5, save_R5
		LD R6, save_R6
		LD R7, save_R7	
		RET

; ----------------------------------------------------

; judge1 函数 判断纵向四连 | 的情况
; 标号解释:
; j1_l1	judge 1 loop 1	外循环
; j1_l2	judge 1 loop 2	内循环
; j1_ad1	judge 1 add 1	下一个行指针+1处
; j1_ad2 , j1_ad3, j1_ad4 同上(if跳转用)

judge1	ST R0, save_R0	; 保存寄存器
		ST R1, save_R1
		ST R2, save_R2
		ST R3, save_R3
		ST R4, save_R4
		ST R5, save_R5
		ST R6, save_R6
		ST R7, save_R7

; 判断|
		AND R1, R1, #0
		ADD R1, R1, #3	; R1=3外循环迭代器
		LEA R3, mat0x	; R3首行地址

j1_l1	AND R2, R2, #0
		ADD R2, R2, #6	; R2=6内循环迭代器

j1_l2	ADD R4, R3, #-1	; 获取当前行地址(偏移-1从0开始)
		ADD R4, R4, R2	; R4计算列偏移地址
		AND R5, R5, #0	; R5记录玩家1棋子数目

		LDR R0, R4, #0	
		BRz j1_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j1_ad1 
		ADD R5, R5, #1
j1_ad1	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #0	
		BRz j1_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j1_ad2 
		ADD R5, R5, #1
j1_ad2	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #0	
		BRz j1_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j1_ad3 
		ADD R5, R5, #1
j1_ad3	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #0	
		BRz j1_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j1_ad4 
		ADD R5, R5, #1
j1_ad4	ADD R6, R5, #-4	; 只要能走到这里必定为4个1或2
		BRz winc1_pre	; 如果p1计数器为4则p1赢
		ADD R5, R5, #0
		BRz winc2_pre	; 如果p1计数器为0则p2赢

j1_l2ed	ADD R2, R2, #-1
		BRp j1_l2		; 内循环到此结束
	
		ADD R3, R3, #6	; R3指向下一行
		ADD R1, R1, #-1
		BRp j1_l1		; 外循环到此结束
; 判断|结束
	
		LD R0, save_R0	; 恢复寄存器
		LD R1, save_R1
		LD R2, save_R2
		LD R3, save_R3
		LD R4, save_R4
		LD R5, save_R5
		LD R6, save_R6
		LD R7, save_R7	
		RET

; ----------------------------------------------------

; judge2 函数 判断斜向四连 \ 的情况
; 标号解释:同judge1

judge2	ST R0, save_R0	; 保存寄存器
		ST R1, save_R1
		ST R2, save_R2
		ST R3, save_R3
		ST R4, save_R4
		ST R5, save_R5
		ST R6, save_R6
		ST R7, save_R7

; 判断\
		AND R1, R1, #0
		ADD R1, R1, #3	; R1=3外循环迭代器
		LEA R3, mat0x	; R3首行地址

j2_l1	AND R2, R2, #0
		ADD R2, R2, #3	; R2=3内循环迭代器

j2_l2	ADD R4, R3, #-1	; 获取当前行地址(偏移-1从0开始)
		ADD R4, R4, R2	; R4计算列偏移地址
		AND R5, R5, #0	; R5记录玩家1棋子数目
	
		LDR R0, R4, #0	
		BRz j2_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j2_ad1 
		ADD R5, R5, #1
j2_ad1	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #1	
		BRz j2_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j2_ad2 
		ADD R5, R5, #1
j2_ad2	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #2	
		BRz j2_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j2_ad3 
		ADD R5, R5, #1
j2_ad3	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #3	
		BRz j2_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j2_ad4 
		ADD R5, R5, #1
j2_ad4	ADD R6, R5, #-4	; 只要能走到这里必定为4个1或2
		BRz winc1_pre	; 如果p1计数器为4则p1赢
		ADD R5, R5, #0
		BRz winc2_pre	; 如果p1计数器为0则p2赢

j2_l2ed	ADD R2, R2, #-1
		BRp j2_l2		; 内循环到此结束
	
		ADD R3, R3, #6	; R3指向下一行
		ADD R1, R1, #-1
		BRp j2_l1		; 外循环到此结束
; 判断\结束
	
		LD R0, save_R0	; 恢复寄存器
		LD R1, save_R1
		LD R2, save_R2
		LD R3, save_R3
		LD R4, save_R4
		LD R5, save_R5
		LD R6, save_R6
		LD R7, save_R7	
		RET

; ----------------------------------------------------

pre_main BRnzp p_main	; main函数过于远 中转

; ----------------------------------------------------

; 字符存放
space	.FILL 0x20
no_p	.FILL 0x2D
p1		.FILL 0x4F
p2		.FILL 0x58
nextLi	.FILL 0x0D

; 矩阵存放
mat0x	.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
mat1x	.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
mat2x	.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
mat3x	.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
mat4x	.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
		.FILL #0
mat50	.FILL #0
mat51	.FILL #0
mat52	.FILL #0
mat53	.FILL #0
mat54	.FILL #0
mat55	.FILL #0

; 寄存器存放
save_R0	.FILL #0
save_R1	.FILL #0
save_R2	.FILL #0
save_R3	.FILL #0
save_R4	.FILL #0
save_R5	.FILL #0
save_R6	.FILL #0
save_R7	.FILL #0

; ----------------------------------------------------

p_main BRnzp main	; main函数过于远 中转
winc1_pre BRnzp winc1	; 中转
winc2_pre BRnzp winc2

; ----------------------------------------------------

; judge3 判断斜向四连 / 的情况
; 标号解释:同judge1

judge3	ST R0, save_R0	; 保存寄存器
		ST R1, save_R1
		ST R2, save_R2
		ST R3, save_R3
		ST R4, save_R4
		ST R5, save_R5
		ST R6, save_R6
		ST R7, save_R7

; 判断/
		AND R1, R1, #0
		ADD R1, R1, #3	; R1=3外循环迭代器
		LEA R3, mat0x	; R3首行地址

j3_l1	AND R2, R2, #0
		ADD R2, R2, #3	; R2=3内循环迭代器

j3_l2	ADD R4, R3, #-1	; 获取当前行地址(偏移-1从0开始)
		ADD R4, R4, R2	; R4计算列偏移地址
		ADD R4, R4, #3
		AND R5, R5, #0	; R5记录玩家1棋子数目

		LDR R0, R4, #0	
		BRz j3_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j3_ad1 
		ADD R5, R5, #1
j3_ad1	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #-1	
		BRz j3_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j3_ad2 
		ADD R5, R5, #1
j3_ad2	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #-2	
		BRz j3_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j3_ad3 
		ADD R5, R5, #1
j3_ad3	ADD R4, R4, #6	; R4指向下一行
		LDR R0, R4, #-3	
		BRz j3_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j3_ad4 
		ADD R5, R5, #1
j3_ad4	ADD R6, R5, #-4	; 只要能走到这里必定为4个1或2
		BRz winc1_pre	; 如果p1计数器为4则p1赢
		ADD R5, R5, #0
		BRz winc2_pre	; 如果p1计数器为0则p2赢

j3_l2ed	ADD R2, R2, #-1
		BRp j3_l2		; 内循环到此结束
	
		ADD R3, R3, #6	; R3指向下一行
		ADD R1, R1, #-1
		BRp j3_l1		; 外循环到此结束
; 判断/结束
		
		LD R0, save_R0	; 恢复寄存器
		LD R1, save_R1
		LD R2, save_R2
		LD R3, save_R3
		LD R4, save_R4
		LD R5, save_R5
		LD R6, save_R6
		LD R7, save_R7	
		RET

; ----------------------------------------------------

; judge4 判断横向四连 即 - 的情况
; 标号解释:同judge1

judge4	ST R0, save_R0	; 保存寄存器
		ST R1, save_R1
		ST R2, save_R2
		ST R3, save_R3
		ST R4, save_R4
		ST R5, save_R5
		ST R6, save_R6
		ST R7, save_R7

; 判断-
		AND R1, R1, #0
		ADD R1, R1, #6	; R1=6外循环迭代器
		LEA R3, mat0x	; R3首行地址

j4_l1	AND R2, R2, #0
		ADD R2, R2, #3	; R2=3内循环迭代器

j4_l2	ADD R4, R3, #-1	; 获取当前行地址(偏移-1从0开始)
		ADD R4, R4, R2	; R4计算列偏移地址
		AND R5, R5, #0	; R5记录玩家1棋子数目

		LDR R0, R4, #0	
		BRz j4_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j4_ad1 
		ADD R5, R5, #1
j4_ad1	LDR R0, R4, #1	
		BRz j4_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j4_ad2 
		ADD R5, R5, #1
j4_ad2	LDR R0, R4, #2	
		BRz j4_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j4_ad3 
		ADD R5, R5, #1
j4_ad3	LDR R0, R4, #3	
		BRz j4_l2ed		; 如果遇到0直接break
		ADD R0, R0, #-1
		BRnp j4_ad4 
		ADD R5, R5, #1
j4_ad4	ADD R6, R5, #-4	; 只要能走到这里必定为4个1或2
		BRz winc1_pre	; 如果p1计数器为4则p1赢
		ADD R5, R5, #0
		BRz winc2_pre	; 如果p1计数器为0则p2赢

j4_l2ed	ADD R2, R2, #-1
		BRp j4_l2		; 内循环到此结束
	
		ADD R3, R3, #6	; R3指向下一行
		ADD R1, R1, #-1
		BRp j4_l1		; 外循环到此结束
; 判断-结束
	
		LD R0, save_R0	; 恢复寄存器
		LD R1, save_R1
		LD R2, save_R2
		LD R3, save_R3
		LD R4, save_R4
		LD R5, save_R5
		LD R6, save_R6
		LD R7, save_R7	
		RET

; ----------------------------------------------------

; 列指针存放
ptr0	.FILL #0
ptr1	.FILL #0
ptr2	.FILL #0
ptr3	.FILL #0
ptr4	.FILL #0
ptr5	.FILL #0

; ----------------------------------------------------

; main 函数 ,程序从这里开始执行
; 标号解释:
; ma_lp1	main loop 1	主函数循环1
; in1	main input 1	玩家1输入
; in2 	main input 2	玩家2输入
; i1t2	input 1 test 2	玩家1输入合法测试2
; i1ed	input 1 end	输入1测试结束
; 其他同理
; winc1	win case 1	玩家1获胜
; winc2	win case 2	玩家2获胜
; EOM	End Of Main	main函数结束

main	AND R1, R1, #0		; R1=18 迭代变量
		ADD R1, R1, #15
		ADD R1, R1, #3
	
		JSR print
	
		LEA R0, mat50		; 列指针赋值	
		ST R0, ptr0
		LEA R0, mat51		
		ST R0, ptr1
		LEA R0, mat52		
		ST R0, ptr2
		LEA R0, mat53		
		ST R0, ptr3
		LEA R0, mat54		
		ST R0, ptr4
		LEA R0, mat55		
		ST R0, ptr5

ma_lp1	ADD R0, R0, #0
in1		LEA R0, p1inp 		; 打印输入
		TRAP x22
		TRAP x20			; 玩家1输入
		TRAP x21			; 回显
		ADD R0, R0, #-16
		ADD R0, R0, #-16
		ADD R0, R0, #-16 	; 输入-48 ascii转数字
	
		ADD R2, R0, #0		; 输出回车
		LD R0, nextLi_
		TRAP x21
		ADD R0, R2, #0
	
		BRp i1t2			; 判断输入是否>'0'
		LEA R0, err			; 输出错误提示
		TRAP x22
		BRnzp in1
i1t2	ADD R2, R0, #-7 	; R2=输入-'7'
		BRn i1ed			; 判断输入是否<'7'
		LEA R0, err			
		TRAP x22
		BRnzp in1
	
i1ed	AND R2, R2, #0
		ADD R2, R2, #1		; 玩家1填数字1
		LEA R3, ptr0		; R3取列指针地址
		ADD R3, R3, R0		; R3列指针按照输入偏移
		LDR R4, R3, #-1		; 读取指针数据
		STR R2, R4, #0		; 将数据写入R3指向的地址
		ADD R4, R4, #-6		; 指针--
		STR R4, R3, #-1		; 将偏移后的值存回去
		
		JSR print
		JSR judge1			; 判断 | 输赢
		JSR judge2			; 判断 \ 输赢
		JSR judge3			; 判断 / 输赢
		JSR judge4			; 判断 - 输赢

in2		LEA R0, p2inp 		; 打印:请玩家2输入
		TRAP x22
		TRAP x20			; 玩家2输入
		TRAP x21
		ADD R0, R0, #-16
		ADD R0, R0, #-16
		ADD R0, R0, #-16 	; 输入-48 ascii转数字
	
		ADD R2, R0, #0		; 输出回车
		LD R0, nextLi_
		TRAP x21
		ADD R0, R2, #0
	
		BRp i2t2			; 判断输入是否>'0'
		LEA R0, err			; 输出错误提示
		TRAP x22
		BRnzp in2
i2t2	ADD R2, R0, #-7 	; R2=输入-'7'
		BRn i2ed			; 判断输入是否<'7'
		LEA R0, err		
		TRAP x22
		BRnzp in2
		
i2ed	AND R2, R2, #0
		ADD R2, R2, #2		; 玩家2填数字2
		LEA R3, ptr0		; R3取列指针地址
		ADD R3, R3, R0		; R3列指针按照输入偏移
		LDR R4, R3, #-1		; 读取指针数据
		STR R2, R4, #0		; 将数据写入R3指向的地址
		ADD R4, R4, #-6		; 指针--
		STR R4, R3, #-1		; 将偏移后的值存回去
		
		JSR print
		JSR judge1			; 判断 | 输赢
		JSR judge2			; 判断 \ 输赢
		JSR judge3			; 判断 / 输赢
		JSR judge4			; 判断 - 输赢
	
		ADD R1, R1, #-1	
		BRp ma_lp1			; 循环到此结束
	
		LEA R0, draw		; 平局
		TRAP x22
		BRnzp EOM

winc1	LEA R0, p1win		; p1赢了
		TRAP x22
		BRnzp EOM

winc2	LEA R0, p2win		; p2赢了
		TRAP x22
		BRnzp EOM

EOM	AND R0, R0, #0			; main函数结束

; ----------------------------------------------------

; 字符存放
nextLi_	.FILL 0x0D
; 字符串存放
p1inp	.STRINGZ "player1 choose a cloumn:"
p2inp	.STRINGZ "player2 choose a cloumn:"
draw	.STRINGZ "Tie Game\n"
err		.STRINGZ "Invalid move. Try again.\n"
p1win	.STRINGZ "player1 win\n"
p2win	.STRINGZ "player2 win\n"

.END

四、实验结论

利用LC3汇编语言可以编写简易的小程序;

通过此次实验,加深了对LC3汇编语言的掌握程度;

编写代码时,要注意跳转指令的范围只有256,超出范围需要进行中转;

(by 子忆)

  • 23
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

归忆_AC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值