Shell 仿消灭星星游戏(2013-03-15)

1200阅读 0评论2014-12-12 embeddedlwp
分类:LINUX

前言
做一个小游戏练习 shell 脚本的语法什么的。入门一般都是俄罗斯方块,不过也都有了,推箱子有用C写过,很简单,网上也有了,就做一个网上还没有人用 shell 写过的吧。模拟 IPAD 上一个“消灭星星”的游戏吧,就是消去几个连在一起的方块得分的游戏,看上去很简单。

正文
就放一个截图吧:
    

代码
放主程序吧,其它的放附件,方便下载查看。block.zip
这个代码框怎么格式都没了啊,还是 CSDN 的代码框更好,能保留缩进啊。

点击(此处)折叠或打开

  1. #!/bin/bash
  2. # block.sh
  3. # 作者:亚丹
  4. # 时间:2012-03-16
  5. # http://seesea.blog.chinaunix.net
  6. # http://blog.csdn.net/nicenight
  7. # 功能:模拟 IPAD 的消灭星星游戏
  8. # 游戏规则:
  9. #   1. 有两个以上的同色方块就可以消去,同时消去的方块越多,得分越多
  10. #   2. 过关时,剩余的方块越少,奖励分数越多
  11. #   3. 当总分低于过关目标分数时,游戏结束
  12. #
  13. # 写着写着发现控制和逻辑越来越混了,也罢,就是练习一下语法嘛

  14. #-----------------------------------------------------------
  15. # 加载通用文件
  16. source colors.sh
  17. source array2d.sh
  18. source util.sh

  19. #-----------------------------------------------------------
  20. # 全局配置

  21. # 响应的信号
  22. declare -r SIG_UP=SIGRTMIN+1
  23. declare -r SIG_DOWN=SIGRTMIN+2
  24. declare -r SIG_LEFT=SIGRTMIN+3
  25. declare -r SIG_RIGHT=SIGRTMIN+4
  26. declare -r SIG_SHOOT=SIGRTMIN+5
  27. declare -r SIG_PAUSE=SIGRTMIN+6
  28. declare -r SIG_EXIT=SIGRTMIN+7

  29. # 响应的按键(注意:使用大写配置)
  30. declare -r KEY_UP="W"
  31. declare -r KEY_DOWN="S"
  32. declare -r KEY_LEFT="A"
  33. declare -r KEY_RIGHT="D"
  34. declare -r KEY_SHOOT="J"
  35. declare -r KEY_PAUSE="P"
  36. declare -r KEY_EXIT="Q"

  37. # 光标效果,设置光标所在方块的特殊显示效果,这里设置为白色背景显示
  38. declare -r EFFECT_CURSOR=${BWHT}

  39. # 当前位置同色的成片方块特殊效果,这里设置为亮黄色背景显示
  40. declare -r EFFECT_CONNECTION=${BYEL}

  41. # 游戏区域顶边界和左边界
  42. declare -r MAP_AREA_TOP=9
  43. declare -r MAP_AREA_LEFT=20

  44. # 游戏边界显示字符(分横向和纵向两种字符)
  45. declare -r MAP_BORDER_H="${BHIG} ${NOR}"
  46. declare -r MAP_BORDER_V="${BHIG} ${NOR}"

  47. # 游戏最高分存放文件
  48. declare -r FILE_TOP_SCORE=".block_top_score"

  49. #-----------------------------------------------------------
  50. # 常量
  51. declare -r BLOCK_WIDTH=3 # 一个元素显示的宽度
  52. declare -r BLOCK_HEIGHT=3 # 一个元素显示的高度

  53. declare -r BONUS_STAGE=1000 # 过关奖励
  54. declare -r BONUS_DECREASE=100 # 过关剩余方块扣分基数

  55. #-----------------------------------------------------------
  56. # 全局变量
  57. declare pid # 主线程pid
  58. declare sub_pid # 子线程pid
  59. declare sign # 信号
  60. declare stty_save # 保存stty配置

  61. declare score # 当前分数
  62. declare score_top # 最高分
  63. declare score_shoot # 当前区域消去可得分数
  64. declare score_goal # 当前关卡过关分数
  65. declare stage_round # 当前关卡数
  66. declare bonus_stage # 当前过关奖励分数

  67. declare width # 屏宽
  68. declare height # 屏高
  69. declare limit_cursor_row # 光标可移动范围的行数限制
  70. declare limit_cursor_col # 光标可移动范围的列数限制
  71. declare paused # 是否暂停状态标志
  72. declare exiting # 是否在退出状态
  73. declare repaint # 是否需要重绘

  74. declare map_area_width # 游戏区域宽
  75. declare map_area_height # 游戏区域高

  76. declare row_cur # 当前行
  77. declare col_cur # 当前列
  78. declare row_old # 旧行
  79. declare col_old # 旧列

  80. declare -a memory_page1 # 内存页一
  81. declare -a memory_page2 # 内存页二

  82. declare -a invalid_rect # 需要重绘的脏矩形,格式:row0 col0 row1 col1

  83. declare -a range_row_cur # 光标所示同色方块相连的所有方块 行 位置
  84. declare -a range_col_cur # 光标所示同色方块相连的所有方块 列 位置

  85. declare -a range_row_old # 光标所示同色方块相连的所有方块 行 位置备份
  86. declare -a range_col_old # 光标所示同色方块相连的所有方块 列 位置备份

  87. declare player_shoot=bc_click # 函数指针,玩家击键后,调用游戏逻辑的处理函数

  88. #-----------------------------------------------------------
  89. # 函数定义

  90. # 设备控制相关初始化
  91. function Init()
  92. {
  93. # ----------------------
  94. # 初始化游戏配置

  95. # 记录主线程pid
  96. pid=$$

  97. # 保存stty配置
  98. stty_save=$(stty -g)

  99. # 清屏
  100. clear

  101. # 获取显示信息
  102. width=$(tput cols)
  103. height=$(tput lines)

  104. # 关闭入出回显
  105. stty -echo

  106. # 关闭光标
  107. tput civis

  108. # 开启大小写case比较的开关
  109. shopt -s nocasematch
  110. }

  111. # 设置光标在地图中的相对位置
  112. # 参数一:相对行
  113. # 参数二:相对列
  114. function Put_cursor_in_map()
  115. {
  116. tput cup $(( MAP_AREA_TOP + $1 )) $(( MAP_AREA_LEFT + $2 ))
  117. }

  118. # 退出清理函数
  119. function Exit_clear()
  120. {
  121. # 清屏
  122. clear

  123. # 恢复输入回显
  124. # stty echo

  125. # 恢复大小写case比较的开关
  126. shopt -u nocasematch

  127. # 恢复stty配置
  128. stty $stty_save
  129. }

  130. # 帧函数
  131. function Frame()
  132. {
  133. :
  134. }

  135. # 刷新
  136. function Refresh()
  137. {
  138. # 显示提示信息
  139. Show_message

  140. # 刷新地图
  141. Refresh_map

  142. # 处理显示光标所在位置的连接在一起的同色区域
  143. Refresh_range

  144. # 显示光标
  145. Show_cursor

  146. # 处理光标所在块的显示
  147. # Show_cursor_block
  148. }

  149. # 刷新地图
  150. function Refresh_map()
  151. {
  152. local i
  153. local j
  154. local bit1
  155. local bit2

  156. # 得到最新显示页的数据
  157. memory_page1=( ${bc_map[@]} )

  158. # 关闭光标
  159. # tput civis

  160. # 逐位扫描
  161. for (( i = ${invalid_rect[0]}; i < ${invalid_rect[2]}; ++i ))
  162. do
  163. for (( j = ${invalid_rect[1]}; j < ${invalid_rect[3]}; ++j ))
  164. do
  165. bit1=$(array_get memory_page1 BC_COL $i $j)
  166. bit2=$(array_get memory_page2 BC_COL $i $j)

  167. # echo "refresh $i $j $bit1 $bit2" >> refresh.txt

  168. # 若两个位置数据一样,不需要更新显示
  169. if (( ! (bit1 ^ bit2) ))
  170. then
  171. continue
  172. fi

  173. # 根据位置更新该位的字符
  174. Print_block $i $j "${BC_IMAGE[$bit1]}"

  175. # echo "+ OK ${BC_IMAGE[$bit1]}" >> refresh.txt
  176. done
  177. done

  178. # 开启光标
  179. # tput cnorm

  180. # 将当前显示页数据备份到备份页
  181. memory_page2=( ${memory_page1[@]} )

  182. # 脏矩形置0
  183. invalid_rect=( 0 0 0 0 )
  184. }
  185. #------------------------------------------------------------------
  186. #------------------------------------------------------------------
  187. # 刷新
  188. # 尝试用内存图
  189. # declare -a memory_map
  190. # function Refresh2()
  191. # {
  192. # local i
  193. # local j
  194. # local bit1
  195. # local bit2
  196. #
  197. # # 显示提示信息
  198. # Show_message
  199. #
  200. # # 得到最新显示页的数据
  201. # memory_page1=( ${bc_map[@]} )
  202. #
  203. # # 关闭光标
  204. # # tput civis
  205. #
  206. # # 逐位扫描
  207. # for (( i = ${invalid_rect[0]}; i < ${invalid_rect[2]}; ++i ))
  208. # do
  209. # for (( j = ${invalid_rect[1]}; j < ${invalid_rect[3]}; ++j ))
  210. # do
  211. # bit1=$(array_get memory_page1 BC_COL $i $j)
  212. # bit2=$(array_get memory_page2 BC_COL $i $j)
  213. #
  214. # # 若两个位置数据一样,不需要更新显示
  215. # if (( ! (bit1 ^ bit2) ))
  216. # then
  217. # continue
  218. # fi
  219. #
  220. # # 根据位置更新该位的字符
  221. # Print_block_memory $i $j "\${BC_IMAGE[$bit1]}"
  222. # done
  223. #
  224. # Print_line $i "$(array_get_row memory_map BC_COL $i)"
  225. # done
  226. #
  227. # # 开启光标
  228. # # tput cnorm
  229. #
  230. # # 将当前显示页数据备份到备份页
  231. # memory_page2=( ${memory_page1[@]} )
  232. #
  233. # # 脏矩形置0
  234. # invalid_rect=( 0 0 0 0 )
  235. #
  236. # # 处理显示光标所在位置的连接在一起的同色区域
  237. # Show_range
  238. #
  239. # # 恢复坐标
  240. # Show_cursor
  241. #
  242. # # 处理光标所在块的显示
  243. # Show_cursor_block
  244. # }
  245. #
  246. # # 在内存图上打印
  247. # function Print_block_memory()
  248. # {
  249. # local i
  250. # local j
  251. # local x
  252. # local y
  253. #
  254. # x=$(( BLOCK_HEIGHT * $1 ))
  255. # y=$(( BLOCK_WIDTH * $2 ))
  256. #
  257. # for (( i = 0; i < BLOCK_HEIGHT; ++i ))
  258. # do
  259. # for (( j = 0; j < BLOCK_WIDTH; ++j ))
  260. # do
  261. # array_set memory_map BC_COL $(( y + $i )) $(( x + $j )) "$3"
  262. # done
  263. # done
  264. #
  265. # # echo ${memory_map[@]} >> xx.txt
  266. # }
  267. #
  268. # function Print_line()
  269. # {
  270. # local i
  271. # local x
  272. #
  273. # x=$(( BLOCK_HEIGHT * $1 ))
  274. #
  275. # for (( i = 0; i < BLOCK_HEIGHT; ++i ))
  276. # do
  277. # Put_cursor_in_map $(( x + i )) 0
  278. # echo -ne "${2}"
  279. # done
  280. # }

  281. #------------------------------------------------------------------
  282. #------------------------------------------------------------------

  283. # 显示提示信息
  284. function Show_title()
  285. {
  286. local title_left
  287. local title_top

  288. title_top=1
  289. title_left=$(( MAP_AREA_LEFT - 5 ))

  290. tput cup $(( title_top++ )) $title_left
  291. echo -ne '_|_|_| _| _|_| _|_|_| _| _| _|_|_|'
  292. tput cup $(( title_top++ )) $title_left
  293. echo -ne '_| _| _| _| _| _| _| _| _| '
  294. tput cup $(( title_top++ )) $title_left
  295. echo -ne '_|_|_| _| _| _| _| _|_| _|_| '
  296. tput cup $(( title_top++ )) $title_left
  297. echo -ne '_| _| _| _| _| _| _| _| _|'
  298. tput cup $(( title_top++ )) $title_left
  299. echo -ne '_|_|_| _|_|_|_| _|_| _|_|_| _| _| _|_|_| '


  300. # tput cup $(( title_top++ )) $title_left
  301. # echo -ne '@@@@@@@ @@@ @@@@@@ @@@@@@@ @@@ @@@ @@@@@@ '
  302. # tput cup $(( title_top++ )) $title_left
  303. # echo -ne '@@@@@@@@ @@@ @@@@@@@@ @@@@@@@@ @@@ @@@ @@@@@@@ '
  304. # tput cup $(( title_top++ )) $title_left
  305. # echo -ne '@@! @@@ @@! @@! @@@ !@@ @@! !@@ !@@ '
  306. # tput cup $(( title_top++ )) $title_left
  307. # echo -ne '!@ @!@ !@! !@! @!@ !@! !@! @!! !@! '
  308. # tput cup $(( title_top++ )) $title_left
  309. # echo -ne '@!@!@!@ @!! @!@ !@! !@! @!@@!@! !!@@!! '
  310. # tput cup $(( title_top++ )) $title_left
  311. # echo -ne '!!!@!!!! !!! !@! !!! !!! !!@!!! !!@!!! '
  312. # tput cup $(( title_top++ )) $title_left
  313. # echo -ne '!!: !!! !!: !!: !!! :!! !!: :!! !:!'
  314. # tput cup $(( title_top++ )) $title_left
  315. # echo -ne ':!: !:! :!: :!: !:! :!: :!: !:! !:! '
  316. # tput cup $(( title_top++ )) $title_left
  317. # echo -ne ' :: :::: :: :::: ::::: :: ::: ::: :: ::: :::: :: '
  318. # tput cup $(( title_top++ )) $title_left
  319. # echo -ne ':: : :: : :: : : : : : :: :: : : ::: :: : : '
  320. }

  321. # 显示提示信息
  322. function Show_message()
  323. {
  324. local msg_left
  325. local msg_top

  326. msg_left=$(( MAP_AREA_LEFT + BLOCK_WIDTH * BC_COL + 5 ))
  327. msg_top=$((MAP_AREA_TOP - 1 ))

  328. # tput civis
  329. tput cup $(( msg_top++ )) $msg_left
  330. echo -n "Score : $score "
  331. tput cup $(( msg_top++ )) $msg_left
  332. echo -n "Top Score : $score_top "
  333. tput cup $(( msg_top++ )) $msg_left
  334. echo -n "Preview : $score_shoot "

  335. (( msg_top++ ))
  336. tput cup $(( msg_top++ )) $msg_left
  337. echo -n "Stage : $stage_round "
  338. tput cup $(( msg_top++ )) $msg_left
  339. echo -n "Stage bonus : $bonus_stage "
  340. tput cup $(( msg_top++ )) $msg_left
  341. echo -n "Stage goal : $score_goal "

  342. (( msg_top++ ))
  343. tput cup $(( msg_top++ )) $msg_left
  344. echo -n "Operation"
  345. tput cup $(( msg_top++ )) $msg_left
  346. echo -n "Up : $KEY_UP"
  347. tput cup $(( msg_top++ )) $msg_left
  348. echo -n "Down : $KEY_DOWN"
  349. tput cup $(( msg_top++ )) $msg_left
  350. echo -n "Left : $KEY_LEFT"
  351. tput cup $(( msg_top++ )) $msg_left
  352. echo -n "Right : $KEY_RIGHT"
  353. tput cup $(( msg_top++ )) $msg_left
  354. echo -n "Shoot : $KEY_SHOOT"
  355. tput cup $(( msg_top++ )) $msg_left
  356. echo -n "Quit : $KEY_EXIT"

  357. # tput cnorm
  358. }

  359. # 绘制边界
  360. function Show_border()
  361. {
  362. local i
  363. local border_h
  364. local border_v
  365. local r
  366. local c
  367. local c2

  368. # Put_cursor_in_map $i -1
  369. border_h=""
  370. for (( i = 0; i < map_area_width + 2; ++i ))
  371. do
  372. border_h="$border_h$MAP_BORDER_H"
  373. done

  374. r=$(( MAP_AREA_TOP ))
  375. c=$(( MAP_AREA_LEFT ))
  376. echo -ne "${ESC}[${r};${c}H${border_h}"

  377. r=$(( MAP_AREA_TOP + map_area_height + 1 ))
  378. echo -ne "${ESC}[${r};${c}H${border_h}"

  379. c2=$(( MAP_AREA_LEFT + map_area_width + 1 ))
  380. for (( r = MAP_AREA_TOP + 1; r < MAP_AREA_TOP + map_area_height + 1; ++r ))
  381. do
  382. echo -ne "${ESC}[${r};${c}H${MAP_BORDER_V}${ESC}[${r};${c2}H${MAP_BORDER_V}"
  383. done
  384. }

  385. # 方块消失动画
  386. # 参数一:方块行
  387. # 参数二:方块列
  388. # 拟按顺时针方向一块一块地消失
  389. function Animation_block_disappear()
  390. {
  391. local block_row # 当前块所在的初始行(block_top)
  392. local block_col # 当前块所在的初始列(block_left)
  393. local char
  394. local i
  395. local r # 当前处理行
  396. local c # 当前处理列
  397. local top # 旋转后的厚度:顶
  398. local bottom # 旋转后的厚度:底
  399. local left # 旋转后的厚度:左边界
  400. local right # 旋转后的厚度:右边界
  401. local dir # 方向:0 1 2 3 -> 右 下 左 上(顺时针)

  402. block_row=$(( BLOCK_HEIGHT * $1 ))
  403. block_col=$(( BLOCK_WIDTH * $2 ))
  404. char="${BC_IMAGE[0]}"

  405. dir=0
  406. top=0
  407. bottom=0
  408. left=0
  409. right=0
  410. c=0
  411. r=0
  412. i=$(( BLOCK_HEIGHT * BLOCK_WIDTH ))

  413. while true
  414. do
  415. echo "$i $dir $r $c $top $bottom $right $left" >> dir.txt
  416. Put_cursor_in_map $(( block_row + r )) $(( block_col + c ))
  417. echo -ne "$char"

  418. # 若所有块处理完毕,就结束循环
  419. if (( i <= 1 ))
  420. then
  421. break
  422. fi

  423. case $dir in
  424. 0) # 右行
  425. if (( c >= (BLOCK_WIDTH - right - 1) ))
  426. then
  427. (( dir = (dir + 1) % 4 ))
  428. (( ++top ))
  429. continue
  430. fi

  431. (( ++c ))
  432. ;;

  433. 1) # 下行
  434. if (( r >= (BLOCK_HEIGHT - bottom - 1) ))
  435. then
  436. (( dir = (dir + 1) % 4 ))
  437. (( ++right ))
  438. continue
  439. fi

  440. (( ++r ))
  441. ;;
  442. 2) # 左行
  443. if (( c <= left ))
  444. then
  445. (( dir = (dir + 1) % 4 ))
  446. (( ++bottom ))
  447. continue
  448. fi

  449. (( --c ))
  450. ;;

  451. 3) # 上行
  452. if (( r <= top ))
  453. then
  454. (( dir = (dir + 1) % 4 ))
  455. (( ++left ))
  456. continue
  457. fi

  458. (( --r ))
  459. ;;
  460. esac

  461. (( --i ))

  462. # 动画延时
  463. sleep 0.01
  464. done
  465. }

  466. # 旧区域消失动画
  467. function Animation_old_range_disappear()
  468. {
  469. local i

  470. # 除最后一个块外,以后台形式播放消失动画

  471. for (( i = 0; i < ${#range_row_old[@]}; ++i ))
  472. do
  473. Animation_block_disappear ${range_row_old[$i]} ${range_col_old[$i]}
  474. done

  475. # Animation_block_disappear ${range_row_old[$i]} ${range_col_old[$i]}
  476. }

  477. # 显示指定位置的一个方块
  478. # 参数一:方块 行 位置
  479. # 参数二:方块 列 位置
  480. # 参数三:方块填充字符
  481. function Print_block()
  482. {
  483. local i
  484. local block_row
  485. local block_col
  486. local block_line=""

  487. block_row=$(( BLOCK_HEIGHT * $1 ))
  488. block_col=$(( BLOCK_WIDTH * $2 ))

  489. for (( i = 0; i < BLOCK_WIDTH; ++i ))
  490. do
  491. block_line="$block_line$3"
  492. done

  493. for (( i = 0; i < BLOCK_HEIGHT; ++i ))
  494. do
  495. Put_cursor_in_map $(( block_row + i )) $block_col
  496. echo -ne "$block_line"
  497. done
  498. }

  499. # 将光标所在位置的方块特殊显示
  500. function Show_cursor_block()
  501. {
  502. local char

  503. # 恢复旧位置
  504. char="${BC_IMAGE[$(array_get memory_page1 BC_COL $row_old $col_old)]}"
  505. Print_block $row_old $col_old "$char"

  506. # 显示新位置
  507. char="${EFFECT_CURSOR}${BC_IMAGE[$(array_get memory_page1 BC_COL $row_cur $col_cur)]}"
  508. Print_block $row_cur $col_cur "$char"

  509. # 记录新位置为旧位置
  510. # row_old=$row_cur
  511. # col_old=$col_cur
  512. }

  513. # 判断光标是否在旧的特殊显示区域中
  514. # 只需要判断前后两个位置的值是不是一样即可
  515. # 是则返回 0
  516. # 否则返回 1
  517. function Is_cursor_in_old_range()
  518. {
  519. local i
  520. local old_val
  521. local new_val

  522. new_val=$(array_get memory_page1 BC_COL $row_cur $col_cur)
  523. if [ $new_val -eq 0 ]
  524. then
  525. return 1
  526. fi

  527. old_val=$(array_get memory_page1 BC_COL $row_old $col_old)
  528. if [ $new_val -ne $old_val ]
  529. then
  530. return 1
  531. fi

  532. return 0

  533. # 原函数
  534. # if [ ${#range_row_old[@]} -eq 0 ]
  535. # then
  536. # return 1
  537. # fi
  538. #
  539. # if [ $(array_get memory_page1 BC_COL $row_cur $col_cur) -eq 0 ]
  540. # then
  541. # return 1
  542. # fi
  543. #
  544. # for ((i = 0; i < ${#range_row_old[@]}; ++i ))
  545. # do
  546. # if [ $row_cur -eq ${range_row_old[$i]} -a $col_cur -eq ${range_col_old[i]} ]
  547. # then
  548. # return 0
  549. # fi
  550. # done
  551. #
  552. # return 1
  553. }

  554. # 判断光标是否在特殊显示区域中
  555. # 是则返回 0
  556. # 否则返回 1
  557. # function Is_cursor_in_range()
  558. # {
  559. # local i
  560. #
  561. # if [ ${#range_row_cur[@]} -eq 0 ]
  562. # then
  563. # return 1
  564. # fi
  565. #
  566. # if [ $(array_get memory_page1 BC_COL $row_cur $col_cur) -eq 0 ]
  567. # then
  568. # return 1
  569. # fi
  570. #
  571. # for ((i = 0; i < ${#range_row_cur[@]}; ++i ))
  572. # do
  573. # if [ $row_cur -eq ${range_row_cur[$i]} -a $col_cur -eq ${range_col_cur[i]} ]
  574. # then
  575. # return 0
  576. # fi
  577. # done
  578. #
  579. # return 1
  580. # }

  581. # 更新区域信息
  582. function Refresh_range_info()
  583. {
  584. # 重新计算
  585. bc_calcualate_range $row_cur $col_cur

  586. range_row_old=( ${range_row_cur[@]} )
  587. range_col_old=( ${range_col_cur[@]} )
  588. range_row_cur=( ${bc_range_row[@]} )
  589. range_col_cur=( ${bc_range_col[@]} )
  590. }

  591. # 清除特殊显示光标所示方块相连的同色方块
  592. function Clear_range()
  593. {
  594. local char
  595. local i

  596. # 若区域数据为空,则不需要处理
  597. if [ ${#range_row_old[@]} -le 0 ]
  598. then
  599. return
  600. fi

  601. # 恢复旧块
  602. for (( i = 0; i < ${#range_row_old[@]}; ++i ))
  603. do
  604. char="${BC_IMAGE[$(array_get memory_page1 BC_COL ${range_row_old[$i]} ${range_col_old[$i]})]}"
  605. Print_block ${range_row_old[$i]} ${range_col_old[$i]} "$char"
  606. done
  607. }

  608. # 特殊显示光标所示方块相连的同色方块
  609. function Show_range()
  610. {
  611. local char
  612. local i

  613. # 显示新块
  614. char="${EFFECT_CONNECTION}${BC_IMAGE[$(array_get memory_page1 BC_COL $row_cur $col_cur)]}"
  615. for (( i = 0; i < ${#range_row_cur[@]}; ++i ))
  616. do
  617. Print_block ${range_row_cur[$i]} ${range_col_cur[$i]} "$char"
  618. done
  619. }

  620. # 更新相连区域的显示
  621. # 参数一:是否强制刷新
  622. # 1: 强制刷新,不判断光标位置
  623. # 0: 判断光标位置变动情况来刷新
  624. function Refresh_range()
  625. {
  626. local force=1

  627. # 不传入参数,默认为 false
  628. if [ -z "$1" ] || [ $1 -eq 0 ]
  629. then
  630. force=0
  631. fi

  632. # 若当前光标移动后还在本区域内
  633. # 则不需要擦除旧块
  634. if [ $force -eq 1 ] || ! Is_cursor_in_old_range
  635. then
  636. Clear_range
  637. fi

  638. # 显示
  639. Show_range
  640. }

  641. # 键盘输入响应函数
  642. function Input()
  643. {
  644. while true
  645. do
  646. read -s -n 1 key

  647. case $key in
  648. $KEY_UP) Player_up ;;
  649. $KEY_DOWN) Player_down ;;
  650. $KEY_LEFT) Player_left ;;
  651. $KEY_RIGHT) Player_right ;;
  652. $KEY_SHOOT) Player_shoot ;;
  653. $KEY_PAUSE) Game_pause_switch ;;
  654. $KEY_EXIT) Game_exit ;;
  655. esac

  656. if (( exiting == 1 ))
  657. then
  658. break
  659. fi
  660. done
  661. }

  662. # 游戏坐标:
  663. # +-----> x
  664. # |
  665. # |
  666. # |
  667. # v
  668. # y

  669. # 玩家上移
  670. function Player_up()
  671. {
  672. if (( paused == 1 ))
  673. then
  674. return
  675. fi

  676. if (( row_cur <= 0 ))
  677. then
  678. return
  679. fi

  680. row_old=$row_cur
  681. col_old=$col_cur
  682. (( --row_cur ))
  683. Move_cursor
  684. }

  685. # 玩家下移
  686. function Player_down()
  687. {
  688. if (( paused == 1 ))
  689. then
  690. return
  691. fi

  692. if (( row_cur >= limit_cursor_row ))
  693. then
  694. return
  695. fi

  696. row_old=$row_cur
  697. col_old=$col_cur
  698. (( ++row_cur ))
  699. Move_cursor
  700. }

  701. # 玩家左移
  702. function Player_left()
  703. {
  704. if (( paused == 1 ))
  705. then
  706. return
  707. fi

  708. if (( col_cur <= 0 ))
  709. then
  710. return
  711. fi

  712. row_old=$row_cur
  713. col_old=$col_cur
  714. (( --col_cur ))
  715. Move_cursor
  716. }

  717. # 玩家右移
  718. function Player_right()
  719. {
  720. if (( paused == 1 ))
  721. then
  722. return
  723. fi

  724. if (( col_cur >= limit_cursor_col ))
  725. then
  726. return
  727. fi

  728. row_old=$row_cur
  729. col_old=$col_cur
  730. (( ++col_cur ))
  731. Move_cursor
  732. }

  733. # 光标显示函数
  734. function Show_cursor()
  735. {
  736. # tput cup $(( row_cur * BLOCK_WIDTH )) $(( col_cur * BLOCK_HEIGHT ))

  737. local char

  738. # 显示新位置
  739. char="${EFFECT_CURSOR}${BC_IMAGE[$(array_get memory_page1 BC_COL $row_cur $col_cur)]}"
  740. Print_block $row_cur $col_cur "$char"
  741. }

  742. # 光标移除函数
  743. function Clear_cursor()
  744. {
  745. local char

  746. # 恢复旧位置
  747. char="${BC_IMAGE[$(array_get memory_page1 BC_COL $row_old $col_old)]}"
  748. Print_block $row_old $col_old "$char"
  749. }

  750. # 移动光标操作处理函数
  751. function Move_cursor()
  752. {
  753. # 若光标不在新生成的区域内则需要刷新获得信息
  754. if ! Is_cursor_in_old_range
  755. then
  756. Refresh_range_info
  757. fi

  758. Clear_cursor
  759. Refresh_range
  760. Show_cursor

  761. Refresh_shoot_score
  762. }

  763. # 玩家开火
  764. function Player_shoot()
  765. {
  766. # 若当前区域只有一个方块,不允许消除
  767. if [ ${#range_row_cur[@]} -le 1 ]
  768. then
  769. return
  770. fi

  771. # 调用游戏逻辑处理
  772. $player_shoot $row_cur $col_cur

  773. # 增加分数
  774. Increase_score

  775. # # 需要重绘的区域为 顶行,最小列,最大行,最大列
  776. # # 判断作为容错处理(本不应该出现的情况,但可能脚本运行速度慢,并发的情况下出现)
  777. # # echo "range_row_cur: ${range_row_cur[@]}" >> debug.txt
  778. # # echo "range_col_cur: ${range_col_cur[@]}" >> debug.txt
  779. # if [ -z "${range_row_cur[@]}" ] || [ -z "${range_col_cur[@]}" ]
  780. # then
  781. # invalid_rect=( 0 0 $BC_ROW $BC_COL )
  782. # else
  783. # invalid_rect=( 0 $(min ${range_col_cur[@]}) $(( $(max ${range_row_cur[@]}) + 1 )) $(( $(max ${range_col_cur[@]}) + 1 )) )
  784. # fi

  785. # 在有空列需要移动的时候,需要重绘的区域为
  786. # 顶行,最小列,地图最大行,地图最大列
  787. invalid_rect=( 0 $(min ${range_col_cur[@]}) $BC_ROW $BC_COL )
  788. # invalid_rect=( 0 0 $BC_ROW $BC_COL )

  789. # 刷新区域信息
  790. Refresh_range_info

  791. # 插入旧区域消失动画
  792. Animation_old_range_disappear

  793. Refresh

  794. Refresh_shoot_score

  795. # 检测是否结束当前关卡
  796. if ! Is_stage_over
  797. then
  798. return
  799. fi

  800. # 清算关卡
  801. Clear_stage

  802. # 在结束当前关卡的情况下,检测是否游戏结束
  803. # 若未结束,则开启新关卡
  804. # 否则,结束游戏
  805. if ! Is_game_over
  806. then
  807. # 新关卡
  808. New_stage
  809. else
  810. # 结束游戏
  811. Game_over
  812. fi
  813. }

  814. # 计算当前消除方块能得到的分数
  815. function Calcualate_score_shoot()
  816. {
  817. local block_number

  818. block_number=${#range_row_cur[@]}

  819. case $block_number in
  820. 1) score_shoot=0 ;;
  821. [2-4]) score_shoot=$(( block_number * 20 )) ;;
  822. *) score_shoot=$(( (block_number - 4 ) * 25 + 4 * 20 )) ;;
  823. esac
  824. }

  825. # 刷新预览分数
  826. function Refresh_shoot_score()
  827. {
  828. Calcualate_score_shoot
  829. Show_message
  830. }

  831. # 刷新分数,并根据当前分数来确认是否更新最高分
  832. function Increase_score()
  833. {
  834. (( score += score_shoot ))

  835. if (( score > score_top ))
  836. then
  837. score_top=$score
  838. Save_top_score
  839. fi
  840. }

  841. # 测试当前轮次是否结束
  842. function Is_stage_over()
  843. {
  844. bc_check_stage_over

  845. return $?
  846. }

  847. # 测试游戏是否结束
  848. # 是则返回 0
  849. # 否则返回 1
  850. function Is_game_over()
  851. {
  852. if (( score < score_goal ))
  853. then
  854. return 0
  855. fi

  856. return 1
  857. }

  858. # 计算过关分数
  859. function Calcualate_score_goal()
  860. {
  861. # 这个过关分数需要委认真地计算呀,这里就只是简单做着玩,就不那么认真了

  862. # 计算规则:按一个方块 20 分计算,一局可得 20 * BC_ROW * BC_COL 分
  863. # 目标就是总分的 1/4
  864. (( score_goal = stage_round * BC_ROW * BC_COL * 20 / 4 ))
  865. }

  866. # 开启新关卡
  867. function New_stage()
  868. {
  869. while true
  870. do
  871. bc_init

  872. # 万一初始化后就是无法操作的地图,得重新生成
  873. # 否则就可以继续后续操作了
  874. if ! Is_stage_over
  875. then
  876. break
  877. fi
  878. done

  879. memory_page1=( ${bc_map[@]} )
  880. memory_page2=( ${bc_map[@]/*/0} )

  881. Refresh_range_info

  882. (( ++stage_round ))
  883. Calcualate_score_goal
  884. Calcualate_score_shoot

  885. bonus_stage=$BONUS_STAGE

  886. invalid_rect=( 0 0 $BC_ROW $BC_COL )
  887. Refresh
  888. }

  889. # 清算关卡
  890. # 过关奖励 1000 分
  891. # 剩余一个方块扣除 10 分,直至 0 分
  892. function Clear_stage()
  893. {
  894. local r
  895. local c

  896. # 从上到下,从右到左地进行清算
  897. for (( c = BC_ROW - 1; --c; c >= 0 ))
  898. do
  899. for (( r = BC_COL - 1; --r; r >= 0 ))
  900. do
  901. # echo "---> array_get memory_page1 BC_COL $r $c)"
  902. if [ $(array_get memory_page1 BC_COL $r $c) -eq 0 ]
  903. then
  904. continue
  905. fi

  906. Animation_block_disappear $r $c
  907. (( bonus_stage -= BONUS_DECREASE ))
  908. (( bonus_stage = (bonus_stage < 0) ? 0 : bonus_stage ))

  909. Show_message
  910. sleep 0.1
  911. done
  912. done
  913. }

  914. # 读取最高分数
  915. function Read_top_score()
  916. {
  917. # 若没有最高分数记录则最高分为0
  918. if [ ! -f "$FILE_TOP_SCORE" ]
  919. then
  920. score_top=0
  921. return
  922. fi

  923. # 读取文件内容,若不是有效数字则设置最高分为0
  924. score_top=$(cat "$FILE_TOP_SCORE")
  925. if [ "${score_top//[[:digit:]]}" != "" ]
  926. then
  927. score_top=0
  928. fi
  929. }

  930. # 保存最高分数
  931. function Save_top_score()
  932. {
  933. echo $score_top > "$FILE_TOP_SCORE"
  934. }

  935. # 获取整个游戏宽度(游戏区+信息区)
  936. function Game_width()
  937. {
  938. # 估计信息区最长信息长度
  939. local estimate=0

  940. echo $(( MAP_AREA_LEFT + BLOCK_WIDTH * BC_COL + 5 + estimate ))
  941. }

  942. # 获取整个游戏高度(游戏区+信息区)
  943. function Game_height()
  944. {
  945. # 认为信息区高度不超过游戏区高度
  946. echo $(( MAP_AREA_TOP + BLOCK_HEIGHT * BC_ROW ))
  947. }

  948. # 于游戏区中央显示信息
  949. # 参数一:信息内容
  950. function Game_tip()
  951. {
  952. local msg=$1
  953. # local len=${#msg}
  954. local top
  955. local left
  956. local h_border

  957. hborder="+--$(echo $msg | sed 's/./-/g')--+"
  958. msg="| $msg |"

  959. top=$(( $(Game_height) / 2 + 2 ))
  960. left=$(( $(Game_width) / 2 ))

  961. tput cup $(( top++ )) $left
  962. echo -ne "$hborder"
  963. tput cup $(( top++ )) $left
  964. echo -ne "$msg"
  965. tput cup $(( top++ )) $left
  966. echo -ne "$hborder"
  967. }

  968. # 切换游戏暂停状态
  969. function Game_pause_switch()
  970. {
  971. # 不过这个游戏不需要暂停,所以不允许用户操作
  972. return

  973. (( paused = paused == 1 ? 0 : 1 ))
  974. }

  975. # 开始游戏
  976. function Game_start()
  977. {
  978. Game_init
  979. sub_pid=$!
  980. }

  981. # 游戏结束
  982. function Game_over()
  983. {
  984. # 停止响应用户的游戏输入
  985. paused=1

  986. # 于游戏区中央显示游戏结束,按退出键返回
  987. Game_tip "Game Over! Press '$KEY_EXIT' to quit."
  988. }

  989. # 退出游戏
  990. function Game_exit()
  991. {
  992. exiting=1
  993. }

  994. # 游戏初始化
  995. function Game_init()
  996. {
  997. row_cur=0 # 当前行
  998. col_cur=0 # 当前列
  999. row_old=0 # 旧行
  1000. col_old=0 # 旧列

  1001. paused=0 # 设置非暂停状态
  1002. exiting=0 # 设置非退出状态

  1003. stage_round=0 # 关卡数初始化

  1004. score=0 # 当前游戏分数
  1005. Read_top_score # 读取最高分

  1006. limit_cursor_row=$(( BC_ROW - 1 )) # 光标最大限制行数
  1007. limit_cursor_col=$(( BC_COL - 1 )) # 光标最大限制列数

  1008. map_area_width=$(( BLOCK_WIDTH * BC_COL )) # 游戏区域宽
  1009. map_area_height=$(( BLOCK_HEIGHT * BC_ROW )) # 游戏区域高

  1010. # 如果屏幕大小不够,则提示退出(不考虑信息显示区,因为没有信息提示也一样可以玩)
  1011. if [ $width -lt $(( MAP_AREA_LEFT + map_area_width )) -o $height -lt $(( MAP_AREA_TOP + map_area_height )) ]
  1012. then
  1013. # 停止响应用户的游戏输入
  1014. paused=1

  1015. # 提示错误信息,按退出键返回
  1016. echo "Screen size too small! Press '$KEY_EXIT' to quit."

  1017. return
  1018. fi

  1019. Show_title # 显示游戏标题
  1020. Show_border # 显示边框
  1021. New_stage # 开启新关卡
  1022. }

  1023. # 主函数
  1024. function Main()
  1025. {
  1026. Init
  1027. Game_start
  1028. Input
  1029. Exit_clear
  1030. }

  1031. #-----------------------------------------------------------
  1032. # 游戏逻辑部分
  1033. # 游戏名:block_clear(消方块)
  1034. # 游戏逻辑函数、变量均以 bc 为前缀

  1035. # 游戏 map,拟二维数组
  1036. declare -a bc_map

  1037. # map 的行列
  1038. declare -r BC_ROW=8
  1039. declare -r BC_COL=8

  1040. # map 中的方块类型种类数量,及数字对应的显示字符
  1041. declare -r BC_TYPE_NUM=6
  1042. declare -ar BC_IMAGE=(" ${NOR}" "${HIG}O${NOR}" "${HIY}#${NOR}" "${HIR}H${NOR}" "${HIM}M${NOR}" "${HIC}@${NOR}" "${HIW}X${NOR}")
  1043. # declare -ar BC_IMAGE=(" ${NOR}" "${BHG} ${NOR}" "${BHIY} ${NOR}" "${BHIR} ${NOR}" "${BHIM} ${NOR}" "${BHIC} ${NOR}" "${BHIW}.${NOR}")
  1044. # 测试用的显示字符declare -ar BC_IMAGE=(" ${NOR}" "${HIG}1${NOR}" "${HIY}2${NOR}" "${HIR}3${NOR}" "${HIM}4${NOR}" "${HIC}5${NOR}" "${HIW}6${NOR}")

  1045. # 用于存放相连方块的坐标数组
  1046. declare -a bc_range_row
  1047. declare -a bc_range_col

  1048. # bc 初始化
  1049. function bc_init()
  1050. {
  1051. local i
  1052. local j

  1053. array_init bc_map $BC_ROW $BC_COL
  1054. for (( i = 0; i < BC_ROW; ++i ))
  1055. do
  1056. for (( j = 0; j < BC_COL; ++j ))
  1057. do
  1058. array_set bc_map BC_COL $i $j $(( $(random $BC_TYPE_NUM) + 1 ))
  1059. done
  1060. done
  1061. }

  1062. # bc 帧逻辑
  1063. function bc_frame()
  1064. {
  1065. :
  1066. }

  1067. # bc 数字地图输出
  1068. function bc_show_map()
  1069. {
  1070. local map=""
  1071. local i

  1072. for (( i = 0; i < BC_ROW; ++i ))
  1073. do
  1074. map="$map\n$(array_get_row bc_map $BC_COL $i)"
  1075. done

  1076. # map=$(echo "$map" | tr $(seq -s "" 0 $BC_TYPE_NUM) "$BC_IMAGE")
  1077. echo "${map}"
  1078. }

  1079. # 将 bc 数字图渲染为文字图
  1080. function bc_rander_map()
  1081. {
  1082. local map=""
  1083. local i

  1084. for (( i = 0; i < BC_ROW; ++i ))
  1085. do
  1086. map="$map\n$(array_get_row bc_map $BC_COL $i)"
  1087. done

  1088. # xxx map=$(echo "$map" | tr $(seq -s "" 0 $BC_TYPE_NUM) "${BC_IMAGE[@]}")
  1089. echo "${map}"
  1090. }

  1091. # 点击事件响应函数
  1092. # 参数一:行
  1093. # 参数二:列
  1094. function bc_click()
  1095. {
  1096. local i
  1097. local xxstr
  1098. # array_set bc_map $BC_COL $1 $2 0

  1099. for (( i = 0; i < ${#bc_range_row[@]}; ++i ))
  1100. do
  1101. array_set bc_map $BC_COL ${bc_range_row[$i]} ${bc_range_col[$i]} 0
  1102. done

  1103. # 调整地图
  1104. bc_adjust_map

  1105. # 重新计算区域
  1106. # bc_calcualate_range $1 $2
  1107. }

  1108. # 调整地图
  1109. # 空格上方的方块下落
  1110. # 空列右方的方块左移
  1111. # 需要调整的区域为根据当前区域计算的 顶行,最小列,顶行,最大列
  1112. function bc_adjust_map()
  1113. {
  1114. local i
  1115. local j
  1116. local k
  1117. local value
  1118. local bottom_zero_row
  1119. local empty_cols
  1120. local flag_moved

  1121. # echo "bc_range_col: ${bc_range_col[@]}" >> debug.txt
  1122. # 容错判断(本不应该出现的情况,但可能脚本运行速度慢,并发的情况下出现)
  1123. # if [ -z "${bc_range_col[*]}" ]
  1124. # then
  1125. # return
  1126. # fi

  1127. # 对每一列处理下落
  1128. for (( j = $(min ${bc_range_col[@]}); j <= $(max ${bc_range_col[@]}); ++j ))
  1129. do
  1130. # 从底层往上走,并记录最下一个 0 元素的位置
  1131. # 若发现非 0 元素,则移动到最下一个 0 位置上,并更新最下一个 0 位置的指针
  1132. bottom_zero_row=$(( BC_ROW - 1 ))
  1133. for (( i = $bottom_zero_row; i >= 0; --i ))
  1134. do
  1135. value=$(array_get bc_map BC_COL $i $j)

  1136. # 若此位置为 0,则不处理
  1137. if [ $value -eq 0 ]
  1138. then
  1139. continue
  1140. fi

  1141. # 非 0 元素
  1142. # 判断下方是否有空位置
  1143. # 若无则调整最下非 0 位置指针
  1144. if [ $bottom_zero_row -eq $i ]
  1145. then
  1146. (( --bottom_zero_row ))
  1147. continue
  1148. fi

  1149. # 非 0 元素需要下移
  1150. array_set bc_map BC_COL $bottom_zero_row $j $value
  1151. array_set bc_map BC_COL $i $j 0

  1152. # 非 0 元素
  1153. (( --bottom_zero_row ))
  1154. done
  1155. done

  1156. # 测试是否有空列,若无则返回
  1157. empty_cols=( $(bc_get_empty_col) )
  1158. if [ ${#empty_cols[@]} -eq 0 ]
  1159. then
  1160. return
  1161. fi

  1162. # 有空列,需要移动

  1163. # 空列最后一个元素设置为最大列,用于简化控制循环
  1164. empty_cols=( ${empty_cols[@]} $BC_COL )

  1165. # 得到当前空列
  1166. k=0
  1167. cur_zero_col=${empty_cols[$k]}
  1168. (( ++k ))

  1169. flag_moved=0

  1170. # 处理每一列
  1171. for (( j = cur_zero_col + 1; j < BC_COL; ++j ))
  1172. do
  1173. # 若 j 大于行于下一个 0 列,说明当前处理的列也是空列
  1174. # 则移动 k,跳过当前列处理
  1175. # 上面给 empty_cols 加上最后一个元素就用于这里简化控制,不需要判断 k 是否到达末尾了
  1176. if [ $j -ge ${empty_cols[$k]} ]
  1177. then
  1178. (( ++k ))
  1179. continue
  1180. fi

  1181. # 处理每一行,进行移动
  1182. # 由下自上倒着处理,当遇到 0 时,这一列可以提前结束处理
  1183. for (( i = BC_ROW - 1; i >= 0; --i ))
  1184. do
  1185. # 得到需要移动的数据,若为0,则提前结束
  1186. value=$(array_get bc_map BC_COL $i $j)
  1187. if [ $value -eq 0 ]
  1188. then
  1189. break
  1190. fi

  1191. # 移动
  1192. array_set bc_map BC_COL $i $cur_zero_col $value

  1193. # 当前处理列本来需要设置为 0 的,在最后的统一处理,这里略过
  1194. done

  1195. # 此列处理完后,下一列就做为当前 0 列
  1196. (( ++ cur_zero_col ))

  1197. # 标记有移动过
  1198. flag_moved=1
  1199. done

  1200. # 若没有移动过,则不需要做置 0 处理
  1201. if [ $flag_moved -ne 1 ]
  1202. then
  1203. return
  1204. fi

  1205. # 对当前 0 列之后的列做置 0 处理
  1206. for (( j = cur_zero_col; j < BC_COL; ++j ))
  1207. do
  1208. # 处理每一行
  1209. # 由下自上倒着处理,当遇到 0 时,这一列可以提前结束处理
  1210. for (( i = BC_ROW - 1; i >= 0; --i ))
  1211. do
  1212. # 得到需要移动的数据,若为0,则提前结束
  1213. value=$(array_get bc_map BC_COL $i $j)
  1214. if [ $value -eq 0 ]
  1215. then
  1216. break
  1217. fi

  1218. # 移动
  1219. array_set bc_map BC_COL $i $j 0
  1220. done
  1221. done
  1222. }

  1223. # 测试是否需要移动操作
  1224. # 返回所有的空列的列号组成的字串,以空格分隔,可以使用 var=( $(function) ) 方式得到结果
  1225. # 判断结果长度来确定是否有空列及是否需要移动
  1226. function bc_get_empty_col()
  1227. {
  1228. # 在此,只需要判断最底列是否有 0 值即可,并不需要真的判断空列

  1229. local bottom_row
  1230. local j
  1231. local ret

  1232. ret=""
  1233. (( bottom_row = BC_ROW - 1 ))
  1234. for (( j = 0; j < BC_COL; ++j ))
  1235. do
  1236. if [ $(array_get bc_map BC_COL $bottom_row $j) -ne 0 ]
  1237. then
  1238. continue
  1239. fi

  1240. ret="$ret $j"
  1241. done

  1242. echo "$ret"
  1243. }

  1244. # 计算输入位置所示广场相连的方块坐标,结果保存于数组中备用
  1245. # 参数一:当前行
  1246. # 参数二:当前列
  1247. # local_map_temp 为本函数内部临时使用的一个数组
  1248. declare -a local_map_temp
  1249. function bc_calcualate_range()
  1250. {
  1251. local cur_row=$1
  1252. local cur_col=$2
  1253. local queue_tail
  1254. local queue_head
  1255. local i
  1256. local j
  1257. local value=$(array_get bc_map BC_COL $cur_row $cur_col)

  1258. # bc_range_row=( )
  1259. # bc_range_col=( )
  1260. #
  1261. # bc_range_row[0]=$cur_row
  1262. # bc_range_col[0]=$cur_col
  1263. # 换成这样
  1264. bc_range_row=( $cur_row )
  1265. bc_range_col=( $cur_col )
  1266. queue_tail=0
  1267. queue_head=0

  1268. if [ $value -eq 0 ]
  1269. then
  1270. return
  1271. fi

  1272. local_map_temp=( ${bc_map[@]} )
  1273. array_set local_map_temp BC_COL $cur_row $cur_col 0

  1274. while true
  1275. do
  1276. if [ $queue_head -gt $queue_tail ]
  1277. then
  1278. break
  1279. fi

  1280. cur_row=${bc_range_row[$queue_head]}
  1281. cur_col=${bc_range_col[$queue_head]}
  1282. # array_set local_map_temp BC_COL $cur_row $cur_col $(( BC_TYPE_NUM + 1 ))
  1283. # array_set local_map_temp BC_COL $cur_row $cur_col 0
  1284. (( ++queue_head ))

  1285. # 朝上找
  1286. if [ $(( cur_row - 1 )) -ge 0 ] && [ $value -eq $(array_get local_map_temp BC_COL $(( cur_row - 1 )) $cur_col) ]
  1287. then
  1288. (( ++queue_tail ))
  1289. bc_range_row[queue_tail]=$(( cur_row - 1 ))
  1290. bc_range_col[queue_tail]=$cur_col

  1291. # 标记访问过
  1292. array_set local_map_temp BC_COL ${bc_range_row[queue_tail]} ${bc_range_col[queue_tail]} 0
  1293. fi

  1294. # 朝下找
  1295. if [ $(( cur_row + 1 )) -lt $BC_ROW ] && [ $value -eq $(array_get local_map_temp BC_COL $(( cur_row + 1 )) $cur_col) ]
  1296. then
  1297. (( ++queue_tail ))
  1298. bc_range_row[queue_tail]=$(( cur_row + 1 ))
  1299. bc_range_col[queue_tail]=$cur_col

  1300. # 标记访问过
  1301. array_set local_map_temp BC_COL ${bc_range_row[queue_tail]} ${bc_range_col[queue_tail]} 0
  1302. fi

  1303. # 朝左找
  1304. if [ $(( cur_col - 1 )) -ge 0 ] && [ $value -eq $(array_get local_map_temp BC_COL $cur_row $(( cur_col - 1 )) ) ]
  1305. then
  1306. (( ++queue_tail ))
  1307. bc_range_row[queue_tail]=$cur_row
  1308. bc_range_col[queue_tail]=$(( cur_col - 1 ))

  1309. # 标记访问过
  1310. array_set local_map_temp BC_COL ${bc_range_row[queue_tail]} ${bc_range_col[queue_tail]} 0
  1311. fi

  1312. # 朝右找
  1313. if [ $(( cur_col + 1 )) -lt $BC_COL ] && [ $value -eq $(array_get local_map_temp BC_COL $cur_row $(( cur_col + 1 )) ) ]
  1314. then
  1315. (( ++queue_tail ))
  1316. bc_range_row[queue_tail]=$cur_row
  1317. bc_range_col[queue_tail]=$(( cur_col + 1 ))

  1318. # 标记访问过
  1319. array_set local_map_temp BC_COL ${bc_range_row[queue_tail]} ${bc_range_col[queue_tail]} 0
  1320. fi
  1321. done
  1322. }

  1323. # 判断是否结束一轮
  1324. # 返回 0 说明已结束 (true)
  1325. # 返回 1 说明还未结束 (false)
  1326. function bc_check_stage_over()
  1327. {
  1328. local i
  1329. local j
  1330. local range_row_bak
  1331. local range_col_bak

  1332. # 备份以备后续恢复
  1333. range_row_bak=( ${bc_range_row[@]} )
  1334. range_col_bak=( ${bc_range_col[@]} )

  1335. for (( i = 0; i < BC_ROW; ++i ))
  1336. do
  1337. for (( j = 0; j < BC_COL; ++j ))
  1338. do
  1339. bc_calcualate_range $i $j

  1340. # 若某一个块的连接区域大于等于 2 块,说明还可以进行游戏
  1341. if [ ${#bc_range_row[@]} -ge 2 ]
  1342. then
  1343. bc_range_row=( ${range_row_bak[@]} )
  1344. bc_range_col=( ${range_col_bak[@]} )

  1345. return 1
  1346. fi
  1347. done
  1348. done

  1349. bc_range_row=( ${range_row_bak[@]} )
  1350. bc_range_col=( ${range_col_bak[@]} )

  1351. return 0
  1352. }

  1353. #-----------------------------------------------------------
  1354. # 执行

  1355. # Main 2>> err.txt
  1356. Main
    


上一篇:通过ramdisk内核模块研究Linux文件系统
下一篇:Shell 飞机游戏(2013-03-15)