此博客用來記錄字符遊戲貪喫蛇設的設計過程(我踩過的那些坑)。。。。。
貪喫蛇,作爲一款經典的遊戲,網上有很多相關的框架,相關的算法也有很多。在該項目中,我採用自頂向下,逐步求精的思想設計,整體的設計框架的僞代碼如下:
輸出字符矩陣
WHILE not 遊戲結束 DO
wait(time)
ch=whereGoNext(Hx,Hy,Fx,Fy)
CASE ch DO
‘A’:左前進一步,break
‘D’:右前進一步,break
‘W’:上前進一步,break
‘S’:下前進一步,break
END CASE
輸出字符矩陣
END WHILE
輸出 Game Over!!!
有了整體的框架以後,最主要的就是算法了,網上有很多相關的算法,但是都偏複雜,理解起來比較有難度,在該遊戲中,我使用了走最短曼哈頓距離的算法(老師給的。。。),實現了一個還算聰明的蛇,僞代碼如下:
// Hx,Hy: 頭的位置
// Fx,Fy:食物的位置
function whereGoNext(Hx,Hy,Fx,Fy) {
// 用數組movable[3]={“a”,”d”,”w”,”s”} 記錄可走的方向
// 用數組distance[3]={0,0,0,0} 記錄離食物的距離
// 分別計算蛇頭周邊四個位置到食物的距離。H頭的位置,F食物位置
// 例如:假設輸入”a” 則distance[0] = |Fx – (Hx-1)| + |Fy – Hy|
// 如果 Hx-1,Hy 位置不是Blank,則 distance[0] = 9999
// 選擇distance中存最小距離的下標p,注意最小距離不能是9999
// 返回 movable[p]
}
下面是我踩過的坑!!!
坑一:VT100控制碼座標是從(1,1)開始!!!並且是(列數,行數)!!!
VT100控制碼的座標是從(1,1)開始的, 並且是(行數,列數)!!!
————————>X
I(1, 1) (1, 2) (1, 3)
I(2, 1) (2, 2) (2, 3)
I
I
Y
這完全就是不按常理出牌。。。從(1, 1)開始就算了。。關鍵座標還不是(列數,行數),而是(行數,列數)。。。是我太菜了。。。
也正是這個原因本程序中的曼哈頓距離是:fabs(snakeX[0]-foody)+fabs(snakeY[0]-foodx),而不是fabs(snakeX[0]-foodx)+fabs(snakeY[0]-foody)。。。
坑二:一定要刷新緩衝區!!!
這個一定要注意!!!每次輸出字符時一定要打印'\n'
或者用fflush(stdout)
來刷新緩衝區!!!
如果不相信,你可以試一試不刷新。。。
坑三:關於用c99進行編譯
當然,這不算坑,只是我在redhat 6(版本有點低,勿噴。。希望有高版本的能分享一下)用gcc編譯是,它說c99才支持for循環的括號裏面定義變量,可能我的gcc默認是c89吧。
解決這個問題也很簡單,在編譯時加上-std=c99
就行拉。
也就是gcc -std=c99 -o mytest mytest.c
詳細見下面的makefile文件:
.SUFFIXES: .c .o
CC=gcc
SRCS1=mysnake.c
OBJS1=$(SRCS1:.c=.o)
EXEC1=mysnake
all: $(OBJS1)
$(CC) -std=c99 -o $(EXEC1) $(OBJS1)
@echo '-------------ok--------------'
.c.o:
$(CC) -std=c99 -Wall -g -o $@ -c $<
clean:
rm -f $(OBJS1) $(EXEC1)
總結
雖然蛇不是很智能,但是在設計算法的過程中還是學到了很多。總之,整個過程很有意思,也希望將來能將這個遊戲進一步地優化。。
還有一點,居然還有VT100控制碼!!!老子之前都沒聽說過啊啊啊啊。。漲知識啦。。。。