题面
四子棋是个双人游戏,两人轮流下棋,棋盘由行和列组成的网格,每个选手每次下一个子直到两人中有一人的棋子连成一条水平线、垂直线或者是对角线。
本实验需要在LC-3中实现简易版四子棋的游戏,两位选手通过键盘和输出窗口轮流交互操作,棋盘由6 X 6的网格组成。
游戏规则如下:
两位选手依次轮流落子;
选手不能悔棋;
有子的地方不能继续落子;
直到有一方的四个棋子能够连成一条水平线、垂直线或者是对角线;
如果棋盘已满,无人获胜,则平局。
游戏最初时应该打印空的棋盘,可以用ASCII码"-" (即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.
分析
子程序针对多复用内容:保存和恢复还有验证子程序
验证思路:当前点拓展
代码
;
; Mario Chan 2022/5/20 SZU "hahahahaha"
; ::
; :;J7, :, ::;7:
; ,ivYi, , ;LLLFS:
; :iv7Yi :7ri;j5PL
; ,:ivYLvr ,ivrrirrY2X,
; :;r@Wwz.7r: :ivu@kexianli.
; :iL7::,:::iiirii:ii;::::,,irvF7rvvLujL7ur
; ri::,:,::i:iiiiiii:i:irrv177JX7rYXqZEkvv17
; ;i:, , ::::iirrririi:i:::iiir2XXvii;L8OGJr71i
; :,, ,,: ,::ir@mingyi.irii:i:::j1jri7ZBOS7ivv,
; ,::, ::rv77iiiriii:iii:i::,rvLq@huhao.Li
; ,, ,, ,:ir7ir::,:::i;ir:::i:i::rSGGYri712:
; ::: ,v7r:: ::rrv77:, ,, ,:i7rrii:::::, ir7ri7Lri
; , 2OBBOi,iiir;r:: ,irriiii::,, ,iv7Luur:
; ,, i78MBBi,:,:::,:, :7FSL: ,iriii:::i::,,:rLqXv::
; : iuMMP: :,:::,:ii;2GY7OBB0viiii:i:iii:i:::iJqL;::
; , ::::i ,,,,, ::LuBBu BBBBBErii:i:i:i:i:i:i:r77ii
; , : , ,,:::rruBZ1MBBqi, :,,,:::,::::::iiriri:
; , ,,,,::::i: @arqiao. ,:,, ,:::ii;i7:
; :, rjujLYLi ,,:::::,:::::::::,, ,:i,:,,,,,::i:iii
; :: BBBBBBBBB0, ,,::: , ,:::::: , ,,,, ,,:::::::
; i, , ,8BMMBBBBBBi ,,:,, ,,, , , , , , :,::ii::i::
; : iZMOMOMBBM2::::::::::,,,, ,,,,,,:,,,::::i:irr:i:::,
; i ,,:;u0MBMOG1L:::i:::::: ,,,::, ,,, ::::::i:i:iirii:i:i:
; : ,iuUuuXUkFu7i:iii:i:::, :,:,: ::::::::i:i:::::iirr7iiri::
; : :rk@Yizero.i:::::, ,:ii:::::::i:::::i::,::::iirrriiiri::,
; : 5BMBBBBBBSr:,::rv2kuii:::iii::,:i:,, , ,,:,:i@petermu.,
; , :r50EZ8MBBBBGOBBBZP7::::i::,:::::,: :,:,::i;rrririiii::
; :jujYY7LS0ujJL7r::,::i::,::::::::::::::iirirrrrrrr:ii:
; ,: :@kevensun.:,:,,,::::i:i:::::,,::::::iir;ii;7v77;ii;i,
; ,,, ,,:,::::::i:iiiii:i::::,, ::::iiiir@xingjief.r;7:i,
; , , ,,,:,,::::::::iiiiiiiiii:,:,:::::::::iiir;ri7vL77rrirri::
; :,, , ::::::::i:::i:::i:i::,,,,,:,::i:i:::iir;@Secbone.ii:::
.ORIG x3000
;=====设置棋盘=====
LEA R0, Array
LEA R1, First_Line
STR R1, R0, #0
LEA R1, Second_Line
STR R1, R0, #1
LEA R0, Array
LEA R1, Third_Line
STR R1, R0, #2
LEA R0, Array
LEA R1, Forth_Line
STR R1, R0, #3
LEA R0, Array
LEA R1, Fifth_Line
STR R1, R0, #4
LEA R0, Array
LEA R1, Sixth_Line
STR R1, R0, #5
;===========================================落棋区域,R6锁死==============================================
AND R6, R6, #0 ; R6表示当前是player1(z)还是2(n)
JSR Display; 输出
While ADD R6, R6, #0; 输入
BRn Player_2_Ask
LEA R0, Ask_column1
PUTS;
BRnzp Player_Ask_Finish
Player_2_Ask LEA R0, Ask_column2
PUTS;
Player_Ask_Finish IN ; 输入结果存在R0
LD R1, ASC_Number
NOT R1, R1
ADD R1, R1, #1
ADD R0, R0, R1
BRn Invalid; 判负
ADD R1, R0, #-6 ;判是否超过6
BRp Invalid
LEA R1, Have ;找到对应的列
ADD R0, R0, #-1
ADD R1, R1, R0
LDR R2, R1, #0
BRn Invalid; 已经填满,非法
BRnzp Valid
; --输出不合法
Invalid LEA R0, Invalid_move
PUTS
BRnzp Player_Ask_Finish
;--输入合法
Valid LEA R3, Array
ADD R3, R3, R2; R3此时是行首指针
LDR R3, R3, #0
ADD R3, R3, R0; 找到了改值地址
ADD R4, R6, #0
STR R4, R3, #0
;R2是行(已经-1),R0是列,R3为当前地址
ADD R2, R2, #-1
STR R2, R1, #0 ; 让该列-1
JSR Display; 输出
JSR Check_Line; 返回0表示未定胜局
LD R5, Return_value
BRz Check_Column
BRnzp PUTS_Winner
Check_Column JSR Check_column; 返回0表示未定胜局
LD R5, Return_value
BRz Check_Diagonal
BRnzp PUTS_Winner
Check_Diagonal JSR Check_diagonal; 返回0表示未定胜局
LD R5, Return_value
BRz Check_Fill
BRnzp PUTS_Winner
Check_Fill
LD R5, left_fill; 检查是否填完了
ADD R5, R5, #-1
BRz DONE
ST R5, left_fill
NOT R6, R6
BRnzp While
PUTS_Winner ADD R6, R6, #0
BRn Winner_is_2
LEA R0, Win_1
BRnzp PUT_Win
Winner_is_2 LEA R0, Win_2
PUT_Win PUTS
HALT
DONE LEA R0, Win_both; 平局
PUTS
HALT
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%数据以及子程序区域%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;--字符--
player_one .FILL x004F
player_two .FILL x0058
no_chess .FILL x002D
change_line .FILL x000A
Space .FILL x0020
ASC_Number .FILL x0030
Ask_column1 .STRINGZ "Player 1, choose a column: "
Ask_column2 .STRINGZ "Player 2, choose a column: "
Invalid_move .STRINGZ "Invalid move. Try again."
Win_1 .STRINGZ "Player 1 Wins."
Win_2 .STRINGZ "Player 2 Wins."
Win_both .STRINGZ "Tie Game."
;---保留字,注意R7---
Save0 .FILL x0000
Save1 .FILL x0000
Save2 .FILL x0000
Save3 .FILL x0000
Save4 .FILL x0000
Save5 .FILL x0000
Save6 .FILL x0000
Return_value .FILL x0000
left_fill .FILL x0024
;--棋盘--
Array .BLKW 6 #0
First_Line .BLKW 6 #1
Second_Line .BLKW 6 #1
Third_Line .BLKW 6 #1
Forth_Line .BLKW 6 #1
Fifth_Line .BLKW 6 #1
Sixth_Line .BLKW 6 #1
Have .BLKW 6 #5
;----保存和恢复除了R7的所有寄存器------
;调用前面加上ST R7,save7,后面加上LD R7,save7
SaveR ST R0,Save0
ST R1,Save1
ST R2,Save2
ST R3,Save3
ST R4,Save4
ST R5,Save5
ST R6,Save6
RET
RecoverR LD R0,Save0
LD R1,Save1
LD R2,Save2
LD R3,Save3
LD R4,Save4
LD R5,Save5
LD R6,Save6
RET
;---------------判断横向是否连成4个--------------------
Check_Line ST R7, Save7; 存值
JSR SaveR
LD R7, Save7
; R2行,R0列,R3为当前地址, R4为值
NOT R1, R4
ADD R1, R1, #1
AND R4, R4, #0; 计数器
ADD R4, R4, #1
ADD R5, R3, #1; 指针
LOOP1 ADD R6, R5, #-6
BRz LOOP1_DONE
LDR R2, R5, #0
ADD R6, R1, R2
BRnp LOOP1_DONE
ADD R4, R4, #1
ADD R5, R5, #1
BRnzp LOOP1
LOOP1_DONE
ADD R5, R3, #-1; 指针
LOOP2 ADD R5, R5, #0
BRn LOOP2_DONE
LDR R2, R5, #0
ADD R6, R1, R2
BRnp LOOP2_DONE
ADD R4, R4, #1
ADD R5, R5, #-1
BRnzp LOOP2
LOOP2_DONE
ADD R4, R4, #-4
BRzp SKIP1
AND R0, R0, #0
ST R0, Return_value
BRnzp SKIP2
SKIP1 AND R0, R0, #0
ADD R0, R0, #1
ST R0, Return_value
SKIP2
ST R7, Save7; 还原值
JSR RecoverR
LD R7, Save7
RET
;---------------判断纵向是否连成4个--------------------
Check_column ST R7, Save7; 存值
JSR SaveR
LD R7, Save7
; R2行(已经-1),R0列,R3为当前地址, R4为值
ADD R2, R2, #2
ADD R1, R0, #0 ; R1为列, R2为行
AND R5, R5, #0 ; 计数器
ADD R5, R5, #1
NOT R4, R4 ;值
ADD R4, R4, #1
LOOP3 ADD R0, R2, #-6
BRz LOOP3_DONE
LEA R0, Array
ADD R0, R0, R2
LDR R0, R0, #0
ADD R0, R0, R1 ; 找到地址
LDR R0, R0, #0
ADD R0, R0, R4
BRnp LOOP3_DONE
ADD R2, R2, #1
ADD R5, R5, #1
BRnzp LOOP3
LOOP3_DONE
ADD R5, R5, #-4
BRn SKIP3
AND R0, R0, #0
ADD R0, R0, #1
ST R0, Return_value
BRnzp SKIP4
SKIP3
AND R0, R0, #0
ST R0, Return_value
SKIP4
ST R7, Save7; 存值
JSR RecoverR
LD R7, Save7
RET
;-------------------判断斜线是否有4个----------------------
Check_diagonal ST R7, Save7; 存值
JSR SaveR
LD R7, Save7
; R2行(已经-1),R0列,R3为当前地址, R4为值
ADD R2, R2, #1
ADD R1, R0, #0 ; R1为列, R2为行
AND R5, R5, #0 ; R5计数器
ADD R5, R5, #1
NOT R6, R4 ; R6为值
ADD R6, R6, #1
ADD R3, R2, #1 ; R3表示行, R4表示列
ADD R4, R1, #1
LOOP5 ADD R0, R3, #-6
BRz LOOP5_DONE
ADD R0, R4, #-6
BRz LOOP5_DONE
LEA R0, Array
ADD R0, R0, R3
LDR R0, R0, #0
ADD R0, R0, R4
LDR R0, R0, #0
ADD R0, R0, R6
BRnp LOOP5_DONE
ADD R5, R5, #1
ADD R3, R3, #1
ADD R4, R4, #1
BRnzp LOOP5
LOOP5_DONE
ADD R3, R2, #-1
ADD R4, R1, #-1
LOOP6 ADD R3, R3, #0
BRn LOOP6_DONE
ADD R4, R4, #0
BRn LOOP6_DONE
LEA R0, Array
ADD R0, R0, R3
LDR R0, R0, #0
ADD R0, R0, R4
LDR R0, R0, #0
ADD R0, R0, R6
BRnp LOOP6_DONE
ADD R5, R5, #1
ADD R3, R3, #-1
ADD R4, R4, #-1
BRnzp LOOP6
LOOP6_DONE
ADD R5, R5, #-4
BRzp YES
AND R5, R5, #0
ADD R5, R5, #1
ADD R3, R2, #1
ADD R4, R1, #-1
LOOP7 ADD R0, R3, #-6
BRz LOOP7_DONE
ADD R4, R4, #0
BRn LOOP7_DONE
LEA R0, Array
ADD R0, R0, R3
LDR R0, R0, #0
ADD R0, R0, R4
LDR R0, R0, #0
ADD R0, R0, R6
BRnp LOOP7_DONE
ADD R5, R5, #1
ADD R3, R3, #1
ADD R4, R4, #-1
BRnzp LOOP7
LOOP7_DONE
ADD R3, R2, #-1
ADD R4, R4, #1
LOOP8 ADD R3, R3, #0
BRn LOOP8_DONE
ADD R0, R4, #-6
BRn LOOP8_DONE
LEA R0, Array
ADD R0, R0, R3
LDR R0, R0, #0
ADD R0, R0, R4
LDR R0, R0, #0
ADD R0, R0, R6
BRnp LOOP8_DONE
ADD R5, R5, #1
ADD R3, R3, #-1
ADD R4, R4, #1
BRnzp LOOP8
LOOP8_DONE
ADD R5, R5, #-4
BRzp YES
BRnzp REC
YES AND R0, R0, #0
ADD R0, R0, #1
ST R0, Return_value
BRnzp REC
AND R0, R0, #0
ST R0, Return_value
REC
ST R7, Save7; 还原值
JSR RecoverR
LD R7, Save7
RET
;----------------------输出子程序--------------------------
;字符常量复刻
player_one2 .FILL x004F
player_two2 .FILL x0058
change_line2 .FILL x000A
Space2 .FILL x0020
no_chess2 .FILL x002D
Output_R7 .FILL x0000
Save7 .FILL x0000
Display ST R7, Save7; 存值
JSR SaveR
LD R7, Save7
LEA R1, Array
LDR R2, R1, #0 ; 第一维指向第一行指针
AND R3, R3, #0; 第一维计数器
LOOP_Display1 ADD R5, R3, #-6
BRz Display_Done; 六行扫描完
AND R4, R4, #0; 第二维计数器
LOOP_Display2 LDR R0, R2, #0; 字符放在R0
BRz Player1
BRp NoPlayer
BRn Player2
Player1 LD R0, player_one2
BRnzp OUTPUT
Player2 LD R0, player_two2
BRnzp OUTPUT
NoPlayer LD R0, no_chess2
BRnzp OUTPUT
OUTPUT
ST R7, Output_R7
OUT
LD R7, Output_R7
ADD R2, R2, #1
ADD R4, R4, #1
ADD R5, R4, #-6
BRz Line_Finish; 如果最后一位,跳转
LD R0, Space2
ST R7, Output_R7
OUT
LD R7, Output_R7
BRnzp LOOP_Display2
Line_Finish
LD R0, change_line2
ST R7, Output_R7
OUT
LD R7, Output_R7
ADD R1, R1, #1
LDR R2, R1, #0
ADD R3, R3, #1
BRnzp LOOP_Display1
Display_Done ST R7, Save7; 还原值
JSR RecoverR
LD R7, Save7
RET
;------------------------------------------------------
.END
;*********************************************
; _ooOoo_
; o8888888o
; 88" . "88
; (| -_- |)
; O\ = /O
; ____/`---'\____
; .' \\| |// `.
; / \\||| : |||// \
; / _||||| -:- |||||- \
; | | \\\ - /// | |
; | \_| ''\---/'' | |
; \ .-\__ `-` ___/-. /
; ___`. .' /--.--\ `. . __
; ."" '< `.___\_<|>_/___.' >'"".
; | | : `- \`.;`\ _ /`;.`/ - ` : | |
; \ \ `-. \_ __\ /__ _/ .-` / /
;======`-.____`-.___\_____/___.-`____.-'======
; `=---='
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Buddha Bless, No Bug !