waterlubber

Bash 2048

Oct 4th, 2014
367
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.70 KB | None | 0 0
  1. #!/usr/bin/env bash
  2. #important variables
  3. declare -ia board # array that keeps track of game status
  4. declare -i pieces # number of pieces present on board
  5. declare -i score=0 # score variable
  6. declare -i flag_skip # flag that prevents doing more than one operation on
  7. # single field in one step
  8. declare -i moves # stores number of possible moves to determine if player lost
  9. # the game
  10. declare ESC=$'\e' # escape byte
  11. declare header="Bash 2048 v1.1 (https://github.com/mydzor/bash2048)"
  12. #default config
  13. declare -i board_size=4
  14. declare -i target=2048
  15. #for colorizing numbers
  16. declare -a colors
  17. colors[2]=33 # yellow text
  18. colors[4]=32 # green text
  19. colors[8]=34 # blue text
  20. colors[16]=36 # cyan text
  21. colors[32]=35 # purple text
  22. colors[64]="33m\033[7" # yellow background
  23. colors[128]="32m\033[7" # green background
  24. colors[256]="34m\033[7" # blue background
  25. colors[512]="36m\033[7" # cyan background
  26. colors[1024]="35m\033[7" # purple background
  27. colors[2048]="31m\033[7" # red background (won with default target)
  28. exec 3>/dev/null # no logging by default
  29. trap "end_game 0" INT #handle INT signal
  30. #simplified replacement of seq command
  31. function _seq {
  32. local cur=1
  33. local max
  34. local inc=1
  35. case $# in
  36. 1) let max=$1;;
  37. 2) let cur=$1
  38. let max=$2;;
  39. 3) let cur=$1
  40. let inc=$2
  41. let max=$3;;
  42. esac
  43. while test $max -ge $cur; do
  44. printf "$cur "
  45. let cur+=inc
  46. done
  47. }
  48. # print currect status of the game, last added pieces are marked red
  49. function print_board {
  50. clear
  51. printf "$header pieces=$pieces target=$target score=$score\n"
  52. printf "Board status:\n" >&3
  53. printf "\n"
  54. printf '/------'
  55. for l in $(_seq 1 $index_max); do
  56. printf '|------'
  57. done
  58. printf '\\\n'
  59. for l in $(_seq 0 $index_max); do
  60. printf '|'
  61. for m in $(_seq 0 $index_max); do
  62. if let ${board[l*$board_size+m]}; then
  63. if let '(last_added==(l*board_size+m))|(first_round==(l*board_size+m))'; then
  64. printf '\033[1m\033[31m %4d \033[0m|' ${board[l*$board_size+m]}
  65. else
  66. printf "\033[1m\033[${colors[${board[l*$board_size+m]}]}m %4d\033[0m |" ${board[l*$board_size+m]}
  67. fi
  68. printf " %4d |" ${board[l*$board_size+m]} >&3
  69. else
  70. printf ' |'
  71. printf ' |' >&3
  72. fi
  73. done
  74. let l==$index_max || {
  75. printf '\n|------'
  76. for l in $(_seq 1 $index_max); do
  77. printf '|------'
  78. done
  79. printf '|\n'
  80. printf '\n' >&3
  81. }
  82. done
  83. printf '\n\\------'
  84. for l in $(_seq 1 $index_max); do
  85. printf '|------'
  86. done
  87. printf '/\n'
  88. }
  89. # Generate new piece on the board
  90. # inputs:
  91. # $board - original state of the game board
  92. # $pieces - original number of pieces
  93. # outputs:
  94. # $board - new state of the game board
  95. # $pieces - new number of pieces
  96. function generate_piece {
  97. while true; do
  98. let pos=RANDOM%fields_total
  99. let board[$pos] || {
  100. let value=RANDOM%10?2:4
  101. board[$pos]=$value
  102. last_added=$pos
  103. printf "Generated new piece with value $value at position [$pos]\n" >&3
  104. break;
  105. }
  106. done
  107. let pieces++
  108. }
  109. # perform push operation between two pieces
  110. # inputs:
  111. # $1 - push position, for horizontal push this is row, for vertical column
  112. # $2 - recipient piece, this will hold result if moving or joining
  113. # $3 - originator piece, after moving or joining this will be left empty
  114. # $4 - direction of push, can be either "up", "down", "left" or "right"
  115. # $5 - if anything is passed, do not perform the push, only update number
  116. # of valid moves
  117. # $board - original state of the game board
  118. # outputs:
  119. # $change - indicates if the board was changed this round
  120. # $flag_skip - indicates that recipient piece cannot be modified further
  121. # $board - new state of the game board
  122. function push_pieces {
  123. case $4 in
  124. "up")
  125. let "first=$2*$board_size+$1"
  126. let "second=($2+$3)*$board_size+$1"
  127. ;;
  128. "down")
  129. let "first=(index_max-$2)*$board_size+$1"
  130. let "second=(index_max-$2-$3)*$board_size+$1"
  131. ;;
  132. "left")
  133. let "first=$1*$board_size+$2"
  134. let "second=$1*$board_size+($2+$3)"
  135. ;;
  136. "right")
  137. let "first=$1*$board_size+(index_max-$2)"
  138. let "second=$1*$board_size+(index_max-$2-$3)"
  139. ;;
  140. esac
  141. let ${board[$first]} || {
  142. let ${board[$second]} && {
  143. if test -z $5; then
  144. board[$first]=${board[$second]}
  145. let board[$second]=0
  146. let change=1
  147. printf "move piece with value ${board[$first]} from [$second] to [$first]\n" >&3
  148. else
  149. let moves++
  150. fi
  151. return
  152. }
  153. return
  154. }
  155. let ${board[$second]} && let flag_skip=1
  156. let "${board[$first]}==${board[second]}" && {
  157. if test -z $5; then
  158. let board[$first]*=2
  159. let "board[$first]==$target" && end_game 1
  160. let board[$second]=0
  161. let pieces-=1
  162. let change=1
  163. let score+=${board[$first]}
  164. printf "joined piece from [$second] with [$first], new value=${board[$first]}\n" >&3
  165. else
  166. let moves++
  167. fi
  168. }
  169. }
  170. function apply_push {
  171. printf "\n\ninput: $1 key\n" >&3
  172. for i in $(_seq 0 $index_max); do
  173. for j in $(_seq 0 $index_max); do
  174. flag_skip=0
  175. let increment_max=index_max-j
  176. for k in $(_seq 1 $increment_max); do
  177. let flag_skip && break
  178. push_pieces $i $j $k $1 $2
  179. done
  180. done
  181. done
  182. }
  183. function check_moves {
  184. let moves=0
  185. apply_push up fake
  186. apply_push down fake
  187. apply_push left fake
  188. apply_push right fake
  189. }
  190. function key_react {
  191. let change=0
  192. read -d '' -sn 1
  193. test "$REPLY" = "$ESC" && {
  194. read -d '' -sn 1 -t1
  195. test "$REPLY" = "[" && {
  196. read -d '' -sn 1 -t1
  197. case $REPLY in
  198. A) apply_push up;;
  199. B) apply_push down;;
  200. C) apply_push right;;
  201. D) apply_push left;;
  202. esac
  203. }
  204. } || {
  205. case $REPLY in
  206. k) apply_push up;;
  207. j) apply_push down;;
  208. l) apply_push right;;
  209. h) apply_push left;;
  210. esac
  211. }
  212. }
  213. function end_game {
  214. print_board
  215. printf "GAME OVER\n"
  216. printf "Your score: $score\n"
  217. stty echo
  218. let $1 && {
  219. printf "Congratulations you have achieved $target\n"
  220. exit 0
  221. }
  222. printf "You have lost, better luck next time.\033[0m\n"
  223. exit 0
  224. }
  225. function help {
  226. cat <<END_HELP
  227. Usage: $1 [-b INTEGER] [-t INTEGER] [-l FILE] [-h]
  228. -b specify game board size (sizes 3-9 allowed)
  229. -t specify target score to win (needs to be power of 2)
  230. -l log debug info into specified file
  231. -h this help
  232. END_HELP
  233. }
  234. #parse commandline options
  235. while getopts "b:t:l:h" opt; do
  236. case $opt in
  237. b ) board_size="$OPTARG"
  238. let '(board_size>=3)&(board_size<=9)' || {
  239. printf "Invalid board size, please choose size between 3 and 9\n"
  240. exit -1
  241. };;
  242. t ) target="$OPTARG"
  243. printf "obase=2;$target\n" | bc | grep -e '^1[^1]*$'
  244. let $? && {
  245. printf "Invalid target, has to be power of two\n"
  246. exit -1
  247. };;
  248. h ) help $0
  249. exit 0;;
  250. l ) exec 3>$OPTARG;;
  251. \?) printf "Invalid option: -"$opt", try $0 -h\n" >&2
  252. exit 1;;
  253. : ) printf "Option -"$opt" requires an argument, try $0 -h\n" >&2
  254. exit 1;;
  255. esac
  256. done
  257. #init board
  258. let fields_total=board_size*board_size
  259. let index_max=board_size-1
  260. for i in $(_seq 0 $fields_total); do board[$i]="0"; done
  261. let pieces=0
  262. generate_piece
  263. first_round=$last_added
  264. generate_piece
  265. while true; do
  266. print_board
  267. key_react
  268. let change && generate_piece
  269. first_round=-1
  270. let pieces==fields_total && {
  271. check_moves
  272. let moves==0 && end_game 0 #lose the game
  273. }
  274. done
Advertisement
Add Comment
Please, Sign In to add comment