LC-3簡易四子棋(深大計系1實驗4) 思路+代碼+詳細註釋

明天做LC-3的四子棋實驗,但是我想睡懶覺就今天把他做了,這個實驗挺難的,要寫好久還容易出bug,我把自己的思路和代碼分享一下,讓大家少走彎路

前置知識

在做實驗前要掌握LC-3的一些僞指令和操作

標號

標號 = 內存地址 (可以這麼粗略的理解,編譯器建立了名字到內存的映射)
在這裏插入圖片描述

僞操作

特性:相當於庫函數了,調用這些僞操作,編譯器自動幫你做一些工作,標號以.開頭,下面給出標號的解釋表格

標號名 標號後跟的操作數 解釋
.ORIG 起始地址 這個彙編文件的起始地址
.END 程序在此結束
.FILL 數字n 將這個地方用n填充
.STRINGZ 字符串 將這個地方作爲字符串首地址,往後填充字符串,自動填充\0

用法:

.ORIG 0x3000	; 程序在0x3000地址開始
.END			; 編譯在此停止 但不是停止程序
.FILL #123		; 這個地址將被賦值 123 (十進制)
.STRINGZ "abc"	; 這個地址起始,往後四個地址是 a b c \0

TRAP僞指令

除了僞操作,還可以使用TRAP x__的語句,實現系統的調用

值得注意的是,輸入輸出都要用到R0寄存器,所以保存寄存器R0的值,再用R0輸出信息,是非常關鍵的,也是導致輸出錯誤的一大原因

指令號 解釋
TRAP x25 程序exit
TRAP x23 打印輸入提示信息並且接受用戶的一個輸入字符(ASCII碼形式 )到R0低8位
TRAP x21 將R0中低8位的值以ASCII碼形式打印到屏幕上
TRAP x20 不帶輸入提示信息的輸入讀取 和 TRAP x23 類似
TRAP x22 將R0中的值作爲字符串首地址 連續輸出字符串直到遇到0

代碼塊(函數)調用

LC-3提供非常簡陋的方式調用代碼塊(尚不能稱之爲函數。。。

因爲所有代碼共享8個寄存器,所以調用代碼塊之前記得保存寄存器的值

不要試圖在一個 帶RET的 函數中調用另外的函數,可能會引發意想不到的bug,比如死機(是的我死機過

func	ADD R0, R0, #1	; 這個函數叫func 功能是R0++
		RET
		
		...... 其他代碼 ......
		
		JSR	func		; JSR + 標號即可調用(跳轉到標號然後再跳轉回來)

題目描述

四子棋是一款普遍流行的簡易型桌面遊戲,據說,虎克船長曾因專注於此遊戲而長期隱身在住所,當船員們發現船長的這一專長之後,他們稱這個遊戲爲“船長的情婦”。

四子棋是個雙人遊戲,兩人輪流下棋,棋盤由行和列組成的網格,每個選手每次下一個子直到兩人中有一人的棋子連成一條水平線、垂直線或者是對角線。

本實驗需要在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. 

示例輸出

- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
Player 1, choose a column: 1
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
O - - - - - 
Player 2, choose a column: 2
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
O X - - - - 
Player 1, choose a column: 2
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
- O - - - - 
O X - - - - 
Player 2, choose a column: 3
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
- O - - - - 
O X X - - - 
Player 1, choose a column: 3
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
- O O - - - 
O X X - - - 
Player 2, choose a column: 1
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
X O O - - - 
O X X - - - 
Player 1, choose a column: 4
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
X O O - - - 
O X X O - - 
Player 2, choose a column: 4
- - - - - - 
- - - - - - 
- - - - - - 
- - - - - - 
X O O X - - 
O X X O - - 
Player 1, choose a column: 3
- - - - - - 
- - - - - - 
- - - - - - 
- - O - - - 
X O O X - - 
O X X O - - 
Player 2, choose a column: 4
- - - - - - 
- - - - - - 
- - - - - - 
- - O X - - 
X O O X - - 
O X X O - - 
Player 1, choose a column: 4
- - - - - - 
- - - - - - 
- - - O - - 
- - O X - - 
X O O X - - 
O X X O - - 
Player 1 Wins.
----- Halting the processor ----- 

提示:

  • 參考程序在內存中分配36個空間來表示棋盤的每個位置
  • 最簡單的遍歷棋盤的方法爲:如果該位置爲空,則存放0,如果該位置爲選手一的棋子,則存放1,如果爲選手二的棋子,則存放-1,這樣可以最大程度的使用狀態碼。

在下面文章的代碼中,我沒有聽取上述這個建議,我是用1和2來表示的,所以判斷時遇到不少麻煩。。。

  • 記得所有的輸入和輸出使用ASCII字符,必要時自己轉換。
  • 從鍵盤接收輸入時使用TRAP x20 (GETC),顯示字符時使用TRAP x20 和TRAP x21
    (OUT),合適的地方使用子例程,每次子例程都應暫存和恢復要使用的寄存器,這樣有利於調試程序。
  • 程序首行指定第一條指令的地址,即.ORIG x3000。
  • 最後提交的文件爲connect4.asm,根據提交的說明上傳程序以便打分。

實現思路

流程

代碼首先讀取玩家1的輸入,判斷並輸出非法信息直到玩家輸入合法爲止,然後改變棋盤矩陣的值,接着輸出更新後的棋盤,然後判斷輸贏,如果未分出勝負,則繼續讀取玩家2的輸入,然後做同樣的操作,仍然未分出勝負則查看是否棋盤已滿,如果未滿則繼續,已滿則平局
在這裏插入圖片描述

判斷勝利思路

這裏我用1來表示玩家1的棋子,用2來表示玩家2的棋子,我們需要判斷4種情況:分別是橫向四連“”,縱向四連“|”,斜向四連“\”和”/

如圖:

  1. 枚舉起點(兩重循環),然後向下(或者是右方,斜下方)找4個格子
  2. 統計4個格子中,1出現的個數
  3. 如果1出現個數爲4,則玩家1獲勝
  4. 如果1出現次數爲0則玩家2獲勝
  5. 否則難分勝負,不做操作

枚舉起點的時候注意下標不要越界即可。斜着找的話,LDR指令不是有offset嘛,直接設置就行了,偏移量分別爲0,1,2,3 ,或者是 0,-1,-2,-3
在這裏插入圖片描述
判斷的循環:外循環(行)6次 內循環(列)3次
\ 判斷的循環:外循環(行)3次 內循環(列)3次
/ 判斷的循環:外循環(行)3次 內循環(列)3次
| 判斷的循環:外循環(行)3次 內循環(列)6次

如圖:枚舉起點的定義
在這裏插入圖片描述

矩陣存放與填寫

在內存中連續的方式存放矩陣,即開36個空間,然後0-6是第一行,依次類推

題目的輸入要求非常怪,是像俄羅斯方塊一樣,下落式的,指定列數,然後從下往上填對應的行數,所以我們填寫的思路也很怪

矩陣填寫思路:使用指針的思想

  1. 用一個數組存儲指向矩陣最後一行各個列的指針

  2. 然後通過輸入的數字作爲數組偏移,找到列指針

  3. 將列指針指向的內存改寫爲玩家標誌(1或者2)

  4. 將該指針指向上一行(指針-6即可,指向下一次輸入的位置)

重點就是輸入的列數作爲指針數組的偏移,找到對應列的指針,以及找到之後,指針要指向上一行(即指向下一次輸入的位置)

在這裏插入圖片描述

測試結果

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

代碼

; @program		: 簡易四子棋遊戲LC-3
; @author		: 李若龍 2018171028
; @last modify	: 2020/5/26 18:44
; @explain		: 用分割線----劃分不同代碼塊

.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	; 獲取當前行地址(偏移-10開始)
		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	; 只要能走到這裏必定爲412
		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	; 獲取當前行地址(偏移-10開始)
		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	; 只要能走到這裏必定爲412
		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	; 獲取當前行地址(偏移-10開始)
		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	; 只要能走到這裏必定爲412
		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	; 獲取當前行地址(偏移-10開始)
		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	; 只要能走到這裏必定爲412
		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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章