Advertisement
Guest User

2048 awk

a guest
Mar 26th, 2014
264
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.61 KB | None | 0 0
  1. ==> onetenth <==
  2. #!/bin/sh
  3.  
  4. # Copyright (c) 2014, Michael Sliczniak
  5. # All rights reserved.
  6. #
  7. # Redistribution and use in source and binary forms, with or without
  8. # modification, are permitted provided that the following conditions are
  9. # met:
  10. #
  11. # 1. Redistributions of source code must retain the above copyright
  12. # notice, this list of conditions and the following disclaimer.
  13. #
  14. # 2. Redistributions in binary form must reproduce the above copyright
  15. # notice, this list of conditions and the following disclaimer in the
  16. # documentation and/or other materials provided with the distribution.
  17. #
  18. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  19. # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  20. # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  21. # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  24. # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25. # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26. # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  27. # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  
  30. # @(#)onetenth 0.1 (mzs) 3/25/14
  31.  
  32. # in case it's a function
  33. unset trap
  34. unset kill
  35. unset r
  36.  
  37. # going to use the PATH to find it, in case it's a function
  38. unset stty
  39. unset dd
  40.  
  41. # want to use the default stty command, but the BSD compat one on Solaris,
  42. # the SysV stty does not understand cbreak, you are supposed to use something
  43. # like -icanon min 1 instead!
  44. PATH="/usr/ucb:/bin"
  45.  
  46. # exit status
  47. r=2
  48.  
  49. # smcup mode
  50. unset s
  51. unset hi
  52. unset lo
  53. unset cl
  54.  
  55. case "$1" in
  56. -s)
  57. shift
  58. s=1
  59.  
  60. # Maybe I should be using smso/rmso for standout mode instead...
  61. hi=`NCURSES_NO_PADDING=1 /usr/bin/tput rev`
  62. lo=`NCURSES_NO_PADDING=1 /usr/bin/tput sgr0`
  63. cl=`NCURSES_NO_PADDING=1 /usr/bin/tput clear`
  64.  
  65. ;;
  66. esac
  67.  
  68. # return controlling terminal to cooked mode
  69. cooked () {
  70. stty -cbreak echo
  71.  
  72. case "$s" in
  73. 1)
  74. # te (exit_ca_mode)
  75. NCURSES_NO_PADDING=1 /usr/bin/tput rmcup
  76. ;;
  77. esac
  78.  
  79. # reset SIGINT to default handling
  80. trap 2
  81.  
  82. # reset EXIT handling
  83. trap 0
  84. }
  85.  
  86. # bash EXIT trap - must use zero so other shells do not complain
  87. # this also works on some other shells
  88. trap cooked 0
  89.  
  90. # SIGINT is special case, need to send it to myself again after resetting the
  91. # handler, cooked() does that.
  92. trap 'cooked; kill -2 $$' 2
  93.  
  94. # SIGQUIT (^/ - dump core and exit) and SIGTERM
  95. trap cooked 3 15
  96.  
  97. # don't need to worry about SIGHUP, means terminal is detached anyway
  98. # won't care about bugs in the shell, like SIGSEGV, cause can it eve
  99. # handle that reliably? Also then I don't need to worry about if kill
  100. # can use signal names and what the signal numbers are.
  101.  
  102. # put terminal in rare mode
  103. stty cbreak -echo
  104.  
  105. case "$s" in
  106. 1)
  107. # enter_ca_mode (ti)
  108. NCURSES_NO_PADDING=1 /usr/bin/tput smcup
  109. ;;
  110. esac
  111.  
  112. # wish I could just use: /usr/bin/fold -1 but it buffers stdout
  113. # oh yeah, print one byte from stdin to stdout, then a newline
  114. fold() {
  115. # echo will fail when awk quits, throw away the error message
  116. while echo 2>/dev/null; do
  117. dd bs=1 count=1 2>/dev/null
  118. done
  119. }
  120.  
  121. # awk on Solaris does not have funtions or rand(), use nawk
  122. awk() {
  123. if [ -x /usr/bin/nawk ]; then
  124. /usr/bin/nawk "$@"
  125. else
  126. /usr/bin/awk "$@"
  127. fi
  128. }
  129.  
  130.  
  131. # use fold so each character is it's own line for awk
  132. fold | awk -f "$0".awk ${s:+hi="$hi"} ${s:+lo="$lo"} ${s:+cl="$cl"} "$@"
  133. r=$?
  134.  
  135. # also resets EXIT handler, so does not get called twice
  136. cooked
  137.  
  138. exit $r
  139.  
  140. ==> onetenth.2 <==
  141. .\" Copyright (c) 2014, Michael Sliczniak
  142. .\" All rights reserved.
  143. .\"
  144. .\" Redistribution and use in source and binary forms, with or without
  145. .\" modification, are permitted provided that the following conditions are
  146. .\" met:
  147. .\"
  148. .\" 1. Redistributions of source code must retain the above copyright
  149. .\" notice, this list of conditions and the following disclaimer.
  150. .\"
  151. .\" 2. Redistributions in binary form must reproduce the above copyright
  152. .\" notice, this list of conditions and the following disclaimer in the
  153. .\" documentation and/or other materials provided with the distribution.
  154. .\"
  155. .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  156. .\" IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  157. .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  158. .\" PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  159. .\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  160. .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  161. .\" TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  162. .\" PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  163. .\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  164. .\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  165. .\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  166. .\"
  167. .\" @(#)onetenth.2 0.1 (mzs) 3/25/14
  168.  
  169. Game inspired by 2048 implemented in awk
  170.  
  171. USAGE
  172.  
  173. onetenth [ -s ] [ awkopts ]
  174. onetenth.awk [ awkopts ]
  175.  
  176. -s screen mode
  177.  
  178. awkopts:
  179.  
  180. seed=""
  181.  
  182. # must be lower case
  183. wkey="h"
  184. nkey="k"
  185. skey="j"
  186. ekey="l"
  187. qkey="q"
  188.  
  189. rows=4
  190. cols=4
  191.  
  192. syms="ABCDEFGHIJKLMNOPQRSTUVWXYZ*"
  193. high=11
  194.  
  195. esym="." # empty symbol
  196.  
  197. bl="" # blank lines
  198.  
  199. cl="" # clear
  200. hi=""
  201. lo=""
  202.  
  203. # must match from frist character on line
  204. comment="##"
  205.  
  206. # if the first char is |, then it is a command to pipe into
  207. of=""
  208.  
  209. EXAMPLES
  210.  
  211. have upper case hilighted symbols
  212.  
  213. onetenth esym=" ." syms=" a b c d e f g h i j k"
  214.  
  215. use hex symbols
  216.  
  217. onetenth esym=" ." syms=" 1 2 4 8 10 20 40 80 100 200 400" bl='\n' cl='\n'
  218.  
  219. emulate a hc (hardcopy) device that supports os (overstrike), the ^H is bs
  220. (backspace) and varies on system and shell how to enter - typically you can
  221. press ^V (control+v) and then ^H (control+h)
  222.  
  223. onetenth esym=" ." syms=" 2 4 8 16 32 64 128 256 512 1K 2K" hi='_^H' of="|/usr/bin/ul"
  224.  
  225. clear screen and reverse video highlight
  226.  
  227. ./onetenth -s esym=" ." syms=" 1 2 4 8 10 20 40 80 100 200 400" bl='\n'
  228.  
  229. RESOURCES
  230.  
  231. Gabriele Cirulli http://gabrielecirulli.github.io/2048/
  232.  
  233. Baptiste Fontaine https://github.com/bfontaine/term2048
  234.  
  235. ==> onetenth.awk <==
  236. #!/usr/bin/awk -f
  237.  
  238. # Copyright (c) 2014, Michael Sliczniak
  239. # All rights reserved.
  240. #
  241. # Redistribution and use in source and binary forms, with or without
  242. # modification, are permitted provided that the following conditions are
  243. # met:
  244. #
  245. # 1. Redistributions of source code must retain the above copyright
  246. # notice, this list of conditions and the following disclaimer.
  247. #
  248. # 2. Redistributions in binary form must reproduce the above copyright
  249. # notice, this list of conditions and the following disclaimer in the
  250. # documentation and/or other materials provided with the distribution.
  251. #
  252. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  253. # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  254. # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  255. # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  256. # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  257. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  258. # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  259. # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  260. # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  261. # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  262. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  263.  
  264. # @(#)onetenth.awk 0.1 (mzs) 3/25/14
  265.  
  266. # initialization
  267. BEGIN {
  268. seed=""
  269.  
  270. # must be lower case
  271. wkey="h"
  272. nkey="k"
  273. skey="j"
  274. ekey="l"
  275. qkey="q"
  276.  
  277. rows=4
  278. cols=4
  279.  
  280. syms="ABCDEFGHIJKLMNOPQRSTUVWXYZ*"
  281. high=11
  282.  
  283. esym="." # empty symbol
  284.  
  285. bl="" # blank lines
  286.  
  287. cl="" # clear
  288. hi=""
  289. lo=""
  290.  
  291. # must match from frist character on line
  292. comment="##"
  293.  
  294. # if the first char is |, then it is a command to pipe into
  295. of=""
  296. }
  297.  
  298. # print an error message to stderr and then exit with exit status 2
  299. function errexit(s) {
  300. print "onetenth.awk: " s | "/bin/cat >&2"
  301. exit 2
  302. }
  303.  
  304. # In the translated board: pick a new random symbol.
  305. function pick(w, h, j) {
  306. if (free == 0) return (0)
  307.  
  308. # pick a free space and put 1 or 2 on it
  309. j = int(rand() * free--)
  310.  
  311. for (h-=1; h >= 0; h--) {
  312. j-=w - lpop[h]
  313. if (j < 0) break
  314.  
  315. }
  316.  
  317. pickx=w + j
  318. picky=h
  319.  
  320. # this is the reason of the name, one tenth chance to be a value of 2
  321. if (rand() < 0.1)
  322. return (2)
  323. else
  324. return (1)
  325. }
  326.  
  327. # In the translated board: move symbols west and merge matching symbols
  328. function merge(w, h, i, j, sm, x, y, pop, l, last, v) {
  329. # print ""
  330. #
  331. # for (i=0; i < cells;) {
  332. # printf("%d:", lpop[i / w])
  333. #
  334. # for (j=0; j < w; j++) printf(" %d", tran[i++])
  335. #
  336. # print ""
  337. # }
  338.  
  339. # shifts and merges
  340. sm=0
  341.  
  342. # Yes this is written in a strange way, user defined functions can
  343. # be slow in some awks for various reasons, so don't want slow
  344. # functions in an inner loop.
  345. #
  346. # XXX: x and y are not coords on the translated board, should be renamed
  347. h-=1
  348. for (y=w * h; y >= 0; y-=w) {
  349. # how many symbols are there in this line
  350. pop=lpop[h]
  351.  
  352. # print "y=" y " pop=" pop
  353.  
  354. if (pop == 0) {
  355. h--
  356. continue
  357. }
  358.  
  359. x=y
  360. l=x
  361.  
  362. # find first non empty cell
  363. last=tran[l++]
  364. while (last == 0) last=tran[l++]
  365. if (last < 0) last=-last
  366.  
  367. # print "last=" last " l=" l
  368.  
  369. while (--pop != 0) {
  370. # find next non empty cell
  371. v=tran[l++]
  372. while (v == 0) v=tran[l++]
  373. if (v < 0) v=-v
  374.  
  375. if (last != v) {
  376. tran[x++]=last
  377. last=v
  378.  
  379. continue
  380. }
  381.  
  382. free++
  383. score+=v
  384. v=-v - 1
  385.  
  386. # if this was the last one, do this little trick
  387. # to have the correct increased value put into the
  388. # translated array when breaking out of this while
  389. # loop
  390. if (--pop == 0) {
  391. last=v
  392.  
  393. break
  394. }
  395.  
  396. tran[x++]=v
  397.  
  398. last=tran[l++]
  399. while (last == 0) last=tran[l++]
  400. if (last < 0) last=-last
  401. }
  402.  
  403. tran[x++]=last
  404.  
  405. # update the population of symbols in the current line
  406. lpop[h--]=x - y
  407.  
  408. # update the shifted or moved count
  409. sm+=l - x
  410. }
  411.  
  412. # print sm
  413. #
  414. # for (i=0; i < cells;) {
  415. # printf("%d:", lpop[i / w])
  416. #
  417. # for (j=0; j < w; j++) printf(" %d", tran[i++])
  418. #
  419. # print ""
  420. # }
  421.  
  422. return (sm)
  423. }
  424.  
  425. # handle printing to output pipe or file as well as stdout
  426. function oprint(s) {
  427. if (op != "")
  428. printf("%s", s) | op
  429. else if (of != "")
  430. printf("%s", s) > of
  431. else
  432. printf("%s", s)
  433. }
  434.  
  435. # print taking into account highlighting
  436. function pprint(v, h, i, j) {
  437. # oprint(sprintf("%3d>", v))
  438.  
  439. if (v == 0) {
  440. # it's a blank cell
  441. oprint(sprintf("%s", esym))
  442. return
  443. }
  444.  
  445. if (v > 0) {
  446. # it's not hilighted, just print
  447. oprint(sprintf("%s", substr(syms, (v - 1) * slen + 1, slen)))
  448. return
  449. }
  450.  
  451. # it's highlighted
  452. i=(-v - 1) * slen + 1
  453. v=substr(hisyms, i, slen)
  454.  
  455. # if there is no hi escape, just print the sym from hisyms
  456. if (hi == "") {
  457. oprint(sprintf("%s", v))
  458. return
  459. }
  460.  
  461. h=substr(losyms, i, slen)
  462.  
  463. # if there is no lo escape, then assume each character must be escaped
  464. if (lo == "") {
  465. # if first chars is bs, assume trying to bold like nroff
  466. # will need to print every character before the backspace
  467. # and then after again
  468. if (substr(hi, 1, 1) == "\b") {
  469. for (i=1; i <= slen; i++) {
  470. j=substr(v, i, 1)
  471. oprint(sprintf("%s", j))
  472.  
  473. if (substr(h, i, 1) != "-") continue
  474.  
  475. oprint(sprintf("%s%s", hi, j))
  476. }
  477.  
  478. return
  479. }
  480.  
  481. # the first char of hi is something else, like hi could be '_^H'
  482. # for example to be a nroff style underline, in this case only
  483. # print hi followed by the character from the sym for every
  484. # highlighted character.
  485. for (i=1; i <= slen; i++) {
  486. if (substr(h, i, 1) == "-") oprint(sprintf("%s", hi))
  487.  
  488. oprint(sprintf("%s", substr(v, i, 1)))
  489. }
  490.  
  491. return
  492. }
  493.  
  494. # There is a hi and a lo escape sequence, the idea then is to print the
  495. # hi seq, then some hilighted characters, and then the lo escape seq.
  496. j=0
  497. for (i=1; i<= slen; i++) {
  498. if (substr(h, i, 1) == "-") {
  499. if (j == 0) {
  500. j=1
  501. oprint(sprintf("%s", hi))
  502. }
  503. } else {
  504. if (j == 1) {
  505. j=0
  506. oprint(sprintf("%s", lo))
  507. }
  508. }
  509.  
  510. oprint(sprintf("%s", substr(v, i, 1)))
  511. }
  512.  
  513. if (j == 1) oprint(sprintf("%s", lo))
  514. }
  515.  
  516. # draw the board
  517. function draw( i, r, c) {
  518. # place last picked sym into the draw board and hilight it
  519. if (pickv != 0) board[cols * row + col]=-pickv
  520.  
  521. oprint(cl)
  522. if (key == wkey) oprint("Wsne")
  523. else if (key == skey) oprint("wSne")
  524. else if (key == nkey) oprint("wsNe")
  525. else if (key == ekey) oprint("wsnE")
  526. oprint(sprintf(" %x\n", score))
  527.  
  528. i=0
  529. for (r=0; r < rows; r++) {
  530. oprint(bl)
  531. for (c=0; c < cols; c++) pprint(board[i++])
  532. oprint("\n")
  533. }
  534. }
  535.  
  536. # NB: saving the last picked sym and tucking it into the translated board
  537. # later was a good idea, it was simple and clean to deal with and let me
  538. # make the transforms faster. It made sense when this awk script was just
  539. # for trying-out strategies to play the game because I would not make moves
  540. # where the board would not change. But if you made such a move it added
  541. # a symbol. This makes the game too easy, because sometimes you have to
  542. # move in a way that unlocks the row or column where you have your highest
  543. # valued sym in a corner and you get unlucky and a low value symbol appears
  544. # in that corner. In that version, you could press the direction where nothing
  545. # moves and your high value sym remains in the corner. I should just do away
  546. # with this 'not tucking away the last picked piece until I know what
  547. # direction was selected next' to make it simpler, but I was rushing to
  548. # make the interactive version started by the shell script. So anyway,
  549. # that's why all of these functions now return how much that last piece
  550. # shifted, need to see if there was piece added, and are more complicated.
  551.  
  552. # XXX: I should comment these, but I so much want to change them and comment
  553. # the new versions instead... See above
  554.  
  555. function quickest(w, h, i) {
  556. if (pickv == 0) return (0)
  557.  
  558. i=lpop[picky]++
  559. tran[w * picky + i]=pickv
  560.  
  561. return (pickx - i)
  562. }
  563.  
  564. function quicker(w, h, yi, yj, popi, popj, i, j, k) {
  565. if (pickv != 0) {
  566. i=lpop[picky]++
  567. tran[w * picky + i]=pickv
  568. }
  569.  
  570. yi=0
  571. yj=h - 1
  572. while (yi < yj) {
  573. # print "yi=" yi " yj=" yj
  574. popi=lpop[yi]
  575. popj=lpop[yj]
  576.  
  577. lpop[yi]=popj
  578. lpop[yj]=popi
  579.  
  580. if (popi > popj) {
  581. # i,j ... ...
  582. # ...
  583. # ... k
  584.  
  585. # i,j ... ...
  586. # ...
  587. # ... ... k
  588.  
  589. # ABC yii ...
  590. # ...
  591. # ... k CBA
  592. i=yi * w
  593. k=yj * w + popi - 1
  594. popi-=popj
  595. } else {
  596. i=yj * w
  597. k=yi * w + popj - 1
  598. j=popi
  599. popi=popj-popi
  600. popj=j
  601.  
  602. }
  603.  
  604. j=i
  605. yi++
  606. yj--
  607.  
  608. # print "popi=" popi " popj=" popj " i=" i " j=" j " k=" k
  609.  
  610. while (popi-- > 0) {
  611. tran[k--]=tran[j++]
  612. # print "j=" j, "k=" k
  613. }
  614.  
  615. while (popj-- > 0) {
  616. # i can be equal to j so copy
  617. popi=tran[j++]
  618. tran[i++]=tran[k]
  619. tran[k--]=popi
  620. # print "i=" i, "j=" j, "k=" k
  621. }
  622. }
  623.  
  624. # probably could be handled above, but right now it reverses twice
  625. # back to the same
  626. if (yi == yj) {
  627. j=yi * w
  628. k=j + lpop[yi] - 1
  629. while (j < k) {
  630. i=tran[j]
  631. tran[j++]=tran[k]
  632. tran[k--]=i
  633. }
  634.  
  635. }
  636.  
  637. return (free)
  638. }
  639.  
  640. # NB: there is probably better way for the 90 degree rotations, the orignial
  641. # script without drawing a board used two arrays, one for horizontal and the
  642. # other for vertical, and never drew a board, it was just concerned if the
  643. # game was won or not.
  644. #
  645. # copy the translated board into the drawing board taking care to zero fill
  646. # then copy out of the drawing board back into the translated board with
  647. # the proper rotation
  648.  
  649. function cw(w, h, i, j, x, y, pop, v) {
  650. # for (i=0; i < cells;) {
  651. # printf("%d:", lpop[i / w])
  652. # for (j=0; j < w; j++) printf(" %d", tran[i++])
  653. # print ""
  654. # }
  655.  
  656. i=0
  657. for (y=0; y < h; y++) {
  658. for (x=0; x < lpop[y]; x++) { board[i]=tran[i]; i++ }
  659. for (; x < w; x++) board[i++]=0
  660. }
  661.  
  662. # print "pickv=" pickv " pickx=" pickx " picky=" picky
  663.  
  664. if (pickv != 0) {
  665. board[w * picky + pickx]=pickv
  666. }
  667.  
  668. # for (i=0; i < cells;) {
  669. # for (j=0; j < w; j++) printf("%d ", board[i++])
  670. # print ""
  671. # }
  672.  
  673. j=0
  674. for (x=0; x < w; x++) {
  675. pop=0
  676. i=cells - w + x
  677. for (y=0; y < h; y++) {
  678. v=board[i]; i-=w
  679. if (v != 0) pop++
  680. tran[j++]=v
  681. }
  682.  
  683. lpop[x]=pop
  684. }
  685.  
  686. # for (i=0; i < cells;) {
  687. # printf("%d:", lpop[i / h])
  688. # for (j=0; j < h; j++) printf(" %d", tran[i++])
  689. # print ""
  690. # }
  691.  
  692. return (0)
  693. }
  694.  
  695. function ccw(w, h, i, j, x, y, pop, v) {
  696. # print "w=" w " h=" h
  697. #
  698. # for (i=0; i < cells;) {
  699. # printf("%d:", lpop[i / w])
  700. # for (j=0; j < w; j++) printf(" %d", tran[i++])
  701. # print ""
  702. # }
  703.  
  704. i=0
  705. for (y=0; y < h; y++) {
  706. for (x=0; x < lpop[y]; x++) { board[i]=tran[i]; i++ }
  707. for (; x < w; x++) board[i++]=0
  708. }
  709.  
  710. # print "pickv=" pickv " pickx=" pickx " picky=" picky
  711.  
  712. if (pickv != 0) {
  713. board[w * picky + pickx]=pickv
  714. }
  715.  
  716. # for (i=0; i < cells;) {
  717. # for (j=0; j < w; j++) printf("%d ", board[i++])
  718. # print ""
  719. # }
  720.  
  721. j=0
  722. for (x=0; x < w; x++) {
  723. pop=0
  724. i=w - x - 1
  725. for (y=0; y < h; y++) {
  726. v=board[i]; i+=w
  727. if (v != 0) pop++
  728. tran[j++]=v
  729. }
  730.  
  731. lpop[x]=pop
  732. }
  733.  
  734. # for (i=0; i < cells;) {
  735. # printf("%d:", lpop[i / h])
  736. # for (j=0; j < h; j++) printf(" %d", tran[i++])
  737. # print ""
  738. # }
  739.  
  740. return (0)
  741. }
  742.  
  743. # cwk: clockwise key
  744. # k: key (no rotation)
  745. # ccwk: counter clockwise key
  746. #
  747. # the key for 180 rotation is implied
  748. #
  749. # w and h: current width and height
  750. function direction(cwk, k, ccwk, w, h, da) {
  751. # print ""
  752. # print "key=" key " k=" k " w=" w " h=" h
  753.  
  754. if (key == k) {
  755. da=quickest(w, h)
  756. } else if (key == cwk) {
  757. da=cw(h, w)
  758. } else if (key == ccwk) {
  759. da=ccw(h, w)
  760. } else {
  761. da=quicker(w, h)
  762. }
  763.  
  764. key=k
  765. # print da
  766.  
  767. # If no syms moved around or merged, don't pick a new empty cell
  768. # for an additional symbol because then the game is too simple.
  769. if (merge(w, h) == 0) {
  770. if (da == 0) {
  771. pickv=0
  772. return (0)
  773. }
  774. }
  775.  
  776. pickv=pick(w, h)
  777.  
  778. # print "pickv=" pickv " pickx=" pickx " picky=" picky
  779.  
  780. return (1)
  781. }
  782.  
  783. function dow( w, h, i, x, y, pop) {
  784. w=cols; h=rows
  785. direction(nkey, wkey, skey, w, h)
  786.  
  787. col=pickx
  788. row=picky
  789.  
  790. # print "col=" col " row=" row
  791.  
  792. i=0
  793. for (y=0; y < h; y++) {
  794. pop=lpop[y]
  795. for (x=0; x < pop; x++) { board[i]=tran[i]; i++ }
  796. for (; x < w; x++) board[i++]=0
  797. }
  798.  
  799. draw()
  800. }
  801.  
  802. function doe( w, h, i, j, x, y, pop) {
  803. w=cols; h=rows
  804. direction(skey, ekey, nkey, w, h)
  805.  
  806. col=w - pickx - 1
  807. row=h - picky - 1
  808.  
  809. # print "col=" col " row=" row
  810.  
  811. i=0
  812. j=cells - 1
  813. for (y=0; y < h; y++) {
  814. pop=lpop[y]
  815. for (x=0; x < pop; x++) board[j--]=tran[i++]
  816. for (; x < w; x++) { board[j--]=0; i++ }
  817. }
  818.  
  819. draw()
  820. }
  821.  
  822. function don( w, h, i, j, x, y, pop) {
  823. w=rows; h=cols
  824. direction(ekey, nkey, wkey, w, h)
  825.  
  826. col=h - picky - 1
  827. row=pickx
  828.  
  829. # print "col=" col " row=" row
  830.  
  831. i=0
  832. for (x=0; x < h; x++) {
  833. pop=lpop[x]
  834. j=h - x - 1
  835. for (y=0; y < pop; y++) { board[j]=tran[i++]; j+=h }
  836. for (; y < w; y++) { board[j]=0; i++; j+=h }
  837. }
  838.  
  839. draw()
  840. }
  841.  
  842. function dos( w, h, i, j, x, y, pop) {
  843. w=rows; h=cols
  844. direction(wkey, skey, ekey, w, h)
  845.  
  846. col=picky
  847. row=w - pickx - 1
  848.  
  849. # print "col=" col " row=" row
  850.  
  851. i=0
  852. for (x=0; x < h; x++) {
  853. pop=lpop[x]
  854. j=cells - h + x
  855. for (y=0; y < pop; y++) { board[j]=tran[i++]; j-=h }
  856. for (; y < w; y++) { board[j]=0; i++; j-=h }
  857. }
  858.  
  859. draw()
  860. }
  861.  
  862. # tabs don't work well with the backspace style
  863. # highlighting anyway, just ignore them
  864. function findsp(start, n, len, dir, k, m) {
  865. for (k=start; n-- > 0; k+=dir) {
  866. for (m=k; m <= len; m+=slen) {
  867. if (substr(hisyms, m, 1) != " ")
  868. return (k)
  869. }
  870. }
  871.  
  872. return (k)
  873. }
  874.  
  875. function init( i, j, k, l, m, n) {
  876. # if there was no seed provided, get one from the system time
  877. if (seed == "") {
  878. # returns 0, but picks one based on time
  879. srand()
  880.  
  881. # what was it
  882. seed=srand()
  883. }
  884.  
  885. srand(seed)
  886.  
  887. # seems to help the early distribution on some old awks
  888. for (i=0; i<256; i+=1) rand();
  889.  
  890. rows=int(rows)
  891. if ((rows + 0) !~ /^[1-9][0-9]?$/)
  892. errexit("rows must be a positive integer smaller than one-hundred: " rows)
  893.  
  894. cols=int(cols)
  895. if ((cols + 0) !~ /^[1-9][0-9]?$/)
  896. errexit("cols must be a positive integer smaller than one-hundred: " cols)
  897.  
  898. cells=rows * cols
  899. for (i=0; i < cells; i++) {
  900. board[i]=0
  901. tran[i]=0
  902. }
  903.  
  904. for (i=0; i < rows; i++) lpop[i]=0
  905.  
  906. # in case more cols than rows
  907. for (; i < cols; i++) lpop[i]=0
  908.  
  909. # syms, hisyms, and losyms magic
  910.  
  911. # the length of every cell when drawn is the length of the empty cell
  912. # representation
  913. slen=length(esym)
  914.  
  915. i=length(syms)
  916. if (i % slen != 0)
  917. errexit("len(syms)=" i " must be a multiple of len(esym)=" slen)
  918.  
  919. j=i / slen
  920. if (high > j) errexit("too few syms")
  921.  
  922. # makes them the upper case of syms, don't like that, set hisyms or use
  923. # only uppercase anyway in syms like the default.
  924. if (hisyms == "") hisyms=toupper(syms)
  925.  
  926. if (length(hisyms) != i)
  927. errexit("hisyms and syms must be equal in length")
  928.  
  929. # figure-out how to highlight, don't like this way, create losysms how
  930. # you want, the syntrax is simple, imagine the output of /usr/bin/ul -i
  931. #
  932. # if there is a space charater, that portion of hisyms will not be
  933. # hilighted
  934. #
  935. # if there is a - character, that portion of hisyms will be
  936. # highlighted
  937. #
  938. # notice that regardless of highlighting (terminal escapes, nroff style)
  939. # the string from hisyms will always be used for a highlighted value -
  940. # in particular if the case of syms and hisyms differ, that will be
  941. # resopected in the output
  942. if (losyms == "") {
  943. # The idea is to find the minimum start and end that envelops
  944. # all characters that are not leading or trailing spaces, so for
  945. # example if the symbols were in hex:
  946. #
  947. # ' 1'
  948. # ' 2'
  949. # ' 4'
  950. # ...
  951. # ' 10'
  952. # ' 20'
  953. #
  954. # You would want losyms to be ' -- --' ... ' -- --'
  955. k = findsp(1, slen, i, 1)
  956. l = findsp(slen, slen - k, i, -1)
  957.  
  958. # old awk does not have len params in sprintf to use and I'm
  959. # not sure about the length between % and s, likely depends
  960. # on libc on the system if that is supported or not
  961. n=""
  962. for (m=1; m < k; m++) {
  963. n=n " "
  964. }
  965.  
  966. for (;m <= l; m++) {
  967. n=n "-"
  968. }
  969.  
  970. for (;m <= slen; m++) {
  971. n=n " "
  972. }
  973.  
  974. losyms=""
  975. for (m=0; m < j; m++) losyms=losyms n
  976. }
  977.  
  978. if (length(losyms) != i)
  979. errexit("hisyms and syms must be equal in length")
  980.  
  981. free=cells
  982. score=0
  983. key=wkey
  984.  
  985. # I know this is gross, globals that pick() returns into
  986. pickx=0
  987. picky=0
  988.  
  989. pickv=pick(cols, rows)
  990.  
  991. # similarly ugly, draw uses these
  992. col=pickx
  993. row=picky
  994.  
  995. won=0
  996.  
  997. # print syms
  998. # print hisyms
  999. # print losyms
  1000.  
  1001. op=""
  1002.  
  1003. if (of != "") {
  1004. if (substr(of, 1, 1) == "|") {
  1005. op=substr(of, 2)
  1006. of=""
  1007. }
  1008. }
  1009.  
  1010. draw()
  1011. }
  1012.  
  1013. # argument processing
  1014. NR == 1 {
  1015. init()
  1016. }
  1017.  
  1018. # quit
  1019. tolower($0) == qkey { exit }
  1020.  
  1021. tolower($0) == wkey { dow() }
  1022.  
  1023. tolower($0) == ekey { doe() }
  1024.  
  1025. tolower($0) == nkey { don() }
  1026.  
  1027. tolower($0) == skey { dos() }
  1028.  
  1029. END {
  1030. if (won == 1) {
  1031. print "congratulations"
  1032. exit 0
  1033. }
  1034.  
  1035. if (won == 0) {
  1036. print "thanks for playing"
  1037. } else {
  1038. print "please try again"
  1039. }
  1040.  
  1041. exit 1
  1042. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement