bubbles.el 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462
  1. ;;; bubbles.el --- Puzzle game for Emacs
  2. ;; Copyright (C) 2007-2012 Free Software Foundation, Inc.
  3. ;; Author: Ulf Jasper <ulf.jasper@web.de>
  4. ;; URL: http://ulf.epplejasper.de/
  5. ;; Created: 5. Feb. 2007
  6. ;; Keywords: games
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; Bubbles is a puzzle game. Its goal is to remove as many bubbles as
  20. ;; possible in as few moves as possible.
  21. ;; Bubbles is an implementation of the "Same Game", similar to "Same
  22. ;; GNOME" and many others, see <http://en.wikipedia.org/wiki/SameGame>.
  23. ;; Installation
  24. ;; ------------
  25. ;; Add the following lines to your Emacs startup file (`~/.emacs').
  26. ;; (add-to-list 'load-path "/path/to/bubbles/")
  27. ;; (autoload 'bubbles "bubbles" "Play Bubbles" t)
  28. ;; ======================================================================
  29. ;;; History:
  30. ;; 0.5 (2007-09-14)
  31. ;; - Minor bugfixes.
  32. ;; 0.4 (2007-08-27)
  33. ;; - Allow for undoing last move.
  34. ;; - Bonus for removing all bubbles.
  35. ;; - Speed improvements.
  36. ;; - Animation enhancements.
  37. ;; - Added `bubbles-mode-hook'.
  38. ;; - Fixes: Don't move point.
  39. ;; - New URL.
  40. ;; 0.3 (2007-03-11)
  41. ;; - Renamed shift modes and thus names of score files. All
  42. ;; high scores are lost, unless you rename the score files from
  43. ;; bubbles-shift-... to bubbles-...!
  44. ;; - Bugfixes: Check for successful image creation.
  45. ;; Disable menus and counter when game is over.
  46. ;; Tested with GNU Emacs 22.0.93
  47. ;; 0.2 (2007-02-24)
  48. ;; - Introduced game themes.
  49. ;; - Introduced graphics themes (changeable while playing).
  50. ;; - Added menu.
  51. ;; - Customization: grid size, colors, chars, shift mode.
  52. ;; - More keybindings.
  53. ;; - Changed shift direction from to-right to to-left.
  54. ;; - Bugfixes: Don't remove single-bubble regions;
  55. ;; Animation glitches fixed.
  56. ;; Tested with GNU Emacs 22.0.93 and 21.4.1.
  57. ;; 0.1 (2007-02-11)
  58. ;; Initial release. Tested with GNU Emacs 22.0.93 and 21.4.1.
  59. ;; ======================================================================
  60. ;;; Code:
  61. (defconst bubbles-version "0.5" "Version number of bubbles.el.")
  62. (require 'gamegrid)
  63. (eval-when-compile (require 'cl)) ; for 'case
  64. ;; User options
  65. ;; Careful with that axe, Eugene! Order does matter in the custom
  66. ;; section below.
  67. (defcustom bubbles-game-theme
  68. 'easy
  69. "Overall game theme.
  70. The overall game theme specifies a grid size, a set of colors,
  71. and a shift mode."
  72. :type '(radio (const :tag "Easy" easy)
  73. (const :tag "Medium" medium)
  74. (const :tag "Difficult" difficult)
  75. (const :tag "Hard" hard)
  76. (const :tag "User defined" user-defined))
  77. :group 'bubbles)
  78. (defun bubbles-set-game-easy ()
  79. "Set game theme to 'easy'."
  80. (interactive)
  81. (setq bubbles-game-theme 'easy)
  82. (bubbles))
  83. (defun bubbles-set-game-medium ()
  84. "Set game theme to 'medium'."
  85. (interactive)
  86. (setq bubbles-game-theme 'medium)
  87. (bubbles))
  88. (defun bubbles-set-game-difficult ()
  89. "Set game theme to 'difficult'."
  90. (interactive)
  91. (setq bubbles-game-theme 'difficult)
  92. (bubbles))
  93. (defun bubbles-set-game-hard ()
  94. "Set game theme to 'hard'."
  95. (interactive)
  96. (setq bubbles-game-theme 'hard)
  97. (bubbles))
  98. (defun bubbles-set-game-userdefined ()
  99. "Set game theme to 'user-defined'."
  100. (interactive)
  101. (setq bubbles-game-theme 'user-defined)
  102. (bubbles))
  103. (defgroup bubbles nil
  104. "Bubbles, a puzzle game."
  105. :group 'games)
  106. (defcustom bubbles-graphics-theme
  107. 'circles
  108. "Graphics theme.
  109. It is safe to choose a graphical theme. If Emacs cannot display
  110. images the `ascii' theme will be used."
  111. :type '(radio (const :tag "Circles" circles)
  112. (const :tag "Squares" squares)
  113. (const :tag "Diamonds" diamonds)
  114. (const :tag "Balls" balls)
  115. (const :tag "Emacs" emacs)
  116. (const :tag "ASCII (no images)" ascii))
  117. :group 'bubbles)
  118. (defconst bubbles--grid-small '(10 . 10)
  119. "Predefined small bubbles grid.")
  120. (defconst bubbles--grid-medium '(15 . 10)
  121. "Predefined medium bubbles grid.")
  122. (defconst bubbles--grid-large '(20 . 15)
  123. "Predefined large bubbles grid.")
  124. (defconst bubbles--grid-huge '(30 . 20)
  125. "Predefined huge bubbles grid.")
  126. (defcustom bubbles-grid-size
  127. bubbles--grid-medium
  128. "Size of bubbles grid."
  129. :type `(radio (const :tag "Small" ,bubbles--grid-small)
  130. (const :tag "Medium" ,bubbles--grid-medium)
  131. (const :tag "Large" ,bubbles--grid-large)
  132. (const :tag "Huge" ,bubbles--grid-huge)
  133. (cons :tag "User defined"
  134. (integer :tag "Width")
  135. (integer :tag "Height")))
  136. :group 'bubbles)
  137. (defconst bubbles--colors-2 '("orange" "violet")
  138. "Predefined bubbles color list with two colors.")
  139. (defconst bubbles--colors-3 '("lightblue" "palegreen" "pink")
  140. "Predefined bubbles color list with three colors.")
  141. (defconst bubbles--colors-4 '("firebrick" "sea green" "steel blue" "chocolate")
  142. "Predefined bubbles color list with four colors.")
  143. (defconst bubbles--colors-5 '("firebrick" "sea green" "steel blue"
  144. "sandy brown" "bisque3")
  145. "Predefined bubbles color list with five colors.")
  146. (defcustom bubbles-colors
  147. bubbles--colors-3
  148. "List of bubble colors.
  149. The length of this list determines how many different bubble
  150. types are present."
  151. :type `(radio (const :tag "Red, darkgreen" ,bubbles--colors-2)
  152. (const :tag "Red, darkgreen, blue" ,bubbles--colors-3)
  153. (const :tag "Red, darkgreen, blue, orange" ,bubbles--colors-4)
  154. (const :tag "Red, darkgreen, blue, orange, violet"
  155. ,bubbles--colors-5)
  156. (repeat :tag "User defined" color))
  157. :group 'bubbles)
  158. (defcustom bubbles-chars
  159. '(?+ ?O ?# ?X ?. ?* ?& ?§)
  160. "Characters used for bubbles.
  161. Note that the actual number of different bubbles is determined by
  162. the number of colors, see `bubbles-colors'."
  163. :type '(repeat character)
  164. :group 'bubbles)
  165. (defcustom bubbles-shift-mode
  166. 'default
  167. "Shift mode.
  168. Available modes are `shift-default' and `shift-always'."
  169. :type '(radio (const :tag "Default" default)
  170. (const :tag "Shifter" always)
  171. ;;(const :tag "Mega Shifter" 'mega)
  172. )
  173. :group 'bubbles)
  174. (defcustom bubbles-mode-hook nil
  175. "Hook run by Bubbles mode."
  176. :group 'bubbles
  177. :type 'hook)
  178. (defun bubbles-customize ()
  179. "Open customization buffer for bubbles."
  180. (interactive)
  181. (customize-group 'bubbles))
  182. ;; ======================================================================
  183. ;; internal variables
  184. (defvar bubbles--score 0
  185. "Current Bubbles score.")
  186. (defvar bubbles--neighbourhood-score 0
  187. "Score of active bubbles neighborhood.")
  188. (defvar bubbles--faces nil
  189. "List of currently used faces.")
  190. (defvar bubbles--playing nil
  191. "Play status indicator.")
  192. (defvar bubbles--empty-image nil
  193. "Image used for removed bubbles (empty grid cells).")
  194. (defvar bubbles--images nil
  195. "List of images for bubbles.")
  196. (defvar bubbles--images-ok nil
  197. "Indicate whether images have been created successfully.")
  198. (defvar bubbles--col-offset 0
  199. "Horizontal offset for centering the bubbles grid.")
  200. (defvar bubbles--row-offset 0
  201. "Vertical offset for centering the bubbles grid.")
  202. (defvar bubbles--save-data nil
  203. "List containing bubbles save data (SCORE BUFFERCONTENTS).")
  204. (defconst bubbles--image-template-circle
  205. "/* XPM */
  206. static char * dot_xpm[] = {
  207. \"20 20 2 1\",
  208. \" c None\",
  209. \". c #FFFFFF\",
  210. \" ...... \",
  211. \" .......... \",
  212. \" .............. \",
  213. \" ................ \",
  214. \" ................ \",
  215. \" .................. \",
  216. \" .................. \",
  217. \"....................\",
  218. \"....................\",
  219. \"....................\",
  220. \"....................\",
  221. \"....................\",
  222. \"....................\",
  223. \" .................. \",
  224. \" .................. \",
  225. \" ................ \",
  226. \" ................ \",
  227. \" .............. \",
  228. \" .......... \",
  229. \" ...... \"};")
  230. (defconst bubbles--image-template-square
  231. "/* XPM */
  232. static char * dot_xpm[] = {
  233. \"20 20 2 1\",
  234. \"0 c None\",
  235. \"1 c #FFFFFF\",
  236. \"00000000000000000000\",
  237. \"01111111111111111110\",
  238. \"01111111111111111110\",
  239. \"01111111111111111110\",
  240. \"01111111111111111110\",
  241. \"01111111111111111110\",
  242. \"01111111111111111110\",
  243. \"01111111111111111110\",
  244. \"01111111111111111110\",
  245. \"01111111111111111110\",
  246. \"01111111111111111110\",
  247. \"01111111111111111110\",
  248. \"01111111111111111110\",
  249. \"01111111111111111110\",
  250. \"01111111111111111110\",
  251. \"01111111111111111110\",
  252. \"01111111111111111110\",
  253. \"01111111111111111110\",
  254. \"01111111111111111110\",
  255. \"00000000000000000000\"};")
  256. (defconst bubbles--image-template-diamond
  257. "/* XPM */
  258. static char * dot_xpm[] = {
  259. \"20 20 2 1\",
  260. \"0 c None\",
  261. \"1 c #FFFFFF\",
  262. \"00000000011000000000\",
  263. \"00000000111100000000\",
  264. \"00000001111110000000\",
  265. \"00000011111111000000\",
  266. \"00000111111111100000\",
  267. \"00001111111111110000\",
  268. \"00011111111111111000\",
  269. \"00111111111111111100\",
  270. \"01111111111111111110\",
  271. \"11111111111111111111\",
  272. \"01111111111111111110\",
  273. \"00111111111111111100\",
  274. \"00011111111111111000\",
  275. \"00001111111111110000\",
  276. \"00000111111111100000\",
  277. \"00000011111111000000\",
  278. \"00000001111110000000\",
  279. \"00000000111100000000\",
  280. \"00000000011000000000\",
  281. \"00000000000000000000\"};")
  282. (defconst bubbles--image-template-emacs
  283. "/* XPM */
  284. static char * emacs_24_xpm[] = {
  285. \"24 24 129 2\",
  286. \" c None\",
  287. \". c #837DA4\",
  288. \"+ c #807AA0\",
  289. \"@ c #9894B2\",
  290. \"# c #CCCAD9\",
  291. \"$ c #C2C0D2\",
  292. \"% c #B6B3C9\",
  293. \"& c #A19DB9\",
  294. \"* c #8681A5\",
  295. \"= c #7D779B\",
  296. \"- c #B6B3C7\",
  297. \"; c #ABA7BE\",
  298. \"> c #9792AF\",
  299. \", c #AAA6BD\",
  300. \"' c #CBC9D7\",
  301. \") c #AAA7BE\",
  302. \"! c #908BAA\",
  303. \"~ c #797397\",
  304. \"{ c #948FAC\",
  305. \"] c #9A95B1\",
  306. \"^ c #EBEAEF\",
  307. \"/ c #F1F1F5\",
  308. \"( c #BCB9CB\",
  309. \"_ c #A9A5BD\",
  310. \": c #757093\",
  311. \"< c #918DA9\",
  312. \"[ c #DDDBE4\",
  313. \"} c #FFFFFF\",
  314. \"| c #EAE9EF\",
  315. \"1 c #A7A4BA\",
  316. \"2 c #716C8F\",
  317. \"3 c #8D89A5\",
  318. \"4 c #9C98B1\",
  319. \"5 c #DBDAE3\",
  320. \"6 c #A4A1B7\",
  321. \"7 c #6E698A\",
  322. \"8 c #8B87A1\",
  323. \"9 c #928EA7\",
  324. \"0 c #C5C3D1\",
  325. \"a c #F8F8F9\",
  326. \"b c #CCCAD6\",
  327. \"c c #A29FB4\",
  328. \"d c #6A6585\",
  329. \"e c #88849D\",
  330. \"f c #B5B2C2\",
  331. \"g c #F0F0F3\",
  332. \"h c #E1E0E6\",
  333. \"i c #A5A2B5\",
  334. \"j c #A09DB1\",
  335. \"k c #676281\",
  336. \"l c #85819A\",
  337. \"m c #9591A7\",
  338. \"n c #E1E0E5\",
  339. \"o c #F0EFF2\",
  340. \"p c #B3B0C0\",
  341. \"q c #9D9AAE\",
  342. \"r c #635F7C\",
  343. \"s c #827F96\",
  344. \"t c #9997AA\",
  345. \"u c #F7F7F9\",
  346. \"v c #C8C7D1\",
  347. \"w c #89869D\",
  348. \"x c #9B99AB\",
  349. \"y c #5F5B78\",
  350. \"z c #7F7C93\",
  351. \"A c #CFCDD6\",
  352. \"B c #B7B5C2\",
  353. \"C c #9996A9\",
  354. \"D c #5C5873\",
  355. \"E c #7A778D\",
  356. \"F c #F5F5F6\",
  357. \"G c #8E8C9E\",
  358. \"H c #7D798F\",
  359. \"I c #58546F\",
  360. \"J c #6C6981\",
  361. \"K c #D5D4DB\",
  362. \"L c #F5F4F6\",
  363. \"M c #9794A5\",
  364. \"N c #625F78\",
  365. \"O c #79768C\",
  366. \"P c #55516A\",
  367. \"Q c #605C73\",
  368. \"R c #CAC9D1\",
  369. \"S c #EAE9EC\",
  370. \"T c #B4B3BE\",
  371. \"U c #777488\",
  372. \"V c #514E66\",
  373. \"W c #DEDEE2\",
  374. \"X c #F4F4F5\",
  375. \"Y c #9D9BA9\",
  376. \"Z c #747185\",
  377. \"` c #4E4B62\",
  378. \" . c #DEDDE1\",
  379. \".. c #A6A5B0\",
  380. \"+. c #716F81\",
  381. \"@. c #4A475D\",
  382. \"#. c #A4A3AE\",
  383. \"$. c #F4F3F5\",
  384. \"%. c #777586\",
  385. \"&. c #6E6C7D\",
  386. \"*. c #464358\",
  387. \"=. c #514E62\",
  388. \"-. c #B9B8C0\",
  389. \";. c #D1D0D5\",
  390. \">. c #747282\",
  391. \",. c #6B6979\",
  392. \"'. c #434054\",
  393. \"). c #5A5769\",
  394. \"!. c #D0CFD4\",
  395. \"~. c #5B5869\",
  396. \"{. c #696676\",
  397. \"]. c #403D50\",
  398. \"^. c #DBDADE\",
  399. \"/. c #F3F3F4\",
  400. \"(. c #646271\",
  401. \"_. c #666473\",
  402. \":. c #3D3A4C\",
  403. \"<. c #555362\",
  404. \"[. c #9E9DA6\",
  405. \"}. c #9E9CA5\",
  406. \"|. c #646170\",
  407. \"1. c #393647\",
  408. \"2. c #514E5D\",
  409. \"3. c #83818C\",
  410. \"4. c #A8A7AE\",
  411. \"5. c #E6E6E8\",
  412. \"6. c #DAD9DC\",
  413. \"7. c #353343\",
  414. \"8. c #32303E\",
  415. \" . . . . . . . . . . . . . . . . . . \",
  416. \" + @ # $ % % % % % % % % % % % % % % & * + + \",
  417. \" = - ; > > > > > > > > , ' ) > > > > > > ! = \",
  418. \"~ ~ { { { { { { { { { { { ] ^ / ( { { { { _ ~ ~ \",
  419. \": : < < < < < < < < < < < < [ } } | < < < 1 : : \",
  420. \"2 2 3 3 3 3 3 3 3 3 3 3 4 5 } } } 5 3 3 3 6 2 2 \",
  421. \"7 7 8 8 8 8 8 8 8 8 9 0 a } } } b 8 8 8 8 c 7 7 \",
  422. \"d d e e e e e e e f g } } } h i e e e e e j d d \",
  423. \"k k l l l l l m n } } } o p l l l l l l l q k k \",
  424. \"r r s s s s t u } } } v w s s s s s s s s x r r \",
  425. \"y y z z z z A } } } B z z z z z z z z z z C y y \",
  426. \"D D D D D D E F } } G D D D D D D D D D D H D D \",
  427. \"I I I I I I I J K } L M N I I I I I I I I O I I \",
  428. \"P P P P P P Q R } } } S T P P P P P P P P U P P \",
  429. \"V V V V V V W } } X Y V V V V V V V V V V Z V V \",
  430. \"` ` ` ` ` ` .} } ..` ` ` ` ` ` ` ` ` ` ` +.` ` \",
  431. \"@.@.@.@.@.@.@.#.$.$.%.@.@.@.@.@.@.@.@.@.@.&.@.@.\",
  432. \"*.*.*.*.*.*.*.*.=.-.} ;.>.*.*.*.*.*.*.*.*.,.*.*.\",
  433. \"'.'.'.'.'.'.'.'.'.'.).!.} !.~.'.'.'.'.'.'.{.'.'.\",
  434. \"].].].].].].].].].].].].^.} /.(.].].].].]._.].].\",
  435. \":.:.:.:.:.:.:.:.:.:.<.[./.} } }.:.:.:.:.:.|.:.:.\",
  436. \" 1.1.1.1.1.1.1.1.2.3.4.5.6.3.1.1.1.1.1.1.1.1. \",
  437. \" 7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7. \",
  438. \" 8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8. \"};")
  439. (defconst bubbles--image-template-ball
  440. "/* XPM */
  441. static char * dot3d_xpm[] = {
  442. \"20 20 190 2\",
  443. \" c None\",
  444. \". c #F9F6F6\",
  445. \"+ c #D6D0D0\",
  446. \"@ c #BFBBBB\",
  447. \"# c #AAA4A4\",
  448. \"$ c #ABAAAB\",
  449. \"% c #A8A8A8\",
  450. \"& c #A29D9D\",
  451. \"* c #B5B2B2\",
  452. \"= c #CDC9C9\",
  453. \"- c #D7D0D0\",
  454. \"; c #B3AFAF\",
  455. \"> c #B5B5B5\",
  456. \", c #B7B7B7\",
  457. \"' c #B8B8B8\",
  458. \") c #B6B6B6\",
  459. \"! c #B3B3B3\",
  460. \"~ c #AFAFAF\",
  461. \"{ c #A9A9A9\",
  462. \"] c #A2A2A2\",
  463. \"^ c #9C9A9A\",
  464. \"/ c #C9C5C5\",
  465. \"( c #FDFBFB\",
  466. \"_ c #C3BCBC\",
  467. \": c #BBBBBB\",
  468. \"< c #C0C0C0\",
  469. \"[ c #C3C2C2\",
  470. \"} c #C3C3C3\",
  471. \"| c #C2C2C2\",
  472. \"1 c #BEBEBE\",
  473. \"2 c #B9B9B9\",
  474. \"3 c #B2B2B2\",
  475. \"4 c #ABAAAA\",
  476. \"5 c #999999\",
  477. \"6 c #ACA7A7\",
  478. \"7 c #C2BBBB\",
  479. \"8 c #C5C5C5\",
  480. \"9 c #CACBCB\",
  481. \"0 c #CECECE\",
  482. \"a c #CFCFCF\",
  483. \"b c #CDCDCD\",
  484. \"c c #C8C9C9\",
  485. \"d c #9F9F9F\",
  486. \"e c #959595\",
  487. \"f c #A9A5A5\",
  488. \"g c #D5CFCE\",
  489. \"h c #BDBDBD\",
  490. \"i c #C6C6C6\",
  491. \"j c #D5D5D5\",
  492. \"k c #D9D9D9\",
  493. \"l c #DADADA\",
  494. \"m c #D8D8D8\",
  495. \"n c #D2D2D2\",
  496. \"o c #CBCBCB\",
  497. \"p c #A4A4A5\",
  498. \"q c #9A9A9A\",
  499. \"r c #8F8F8F\",
  500. \"s c #C3BFBF\",
  501. \"t c #AFACAB\",
  502. \"u c #CCCCCC\",
  503. \"v c #D6D6D6\",
  504. \"w c #DEDEDE\",
  505. \"x c #E4E4E4\",
  506. \"y c #E5E5E5\",
  507. \"z c #E2E2E2\",
  508. \"A c #DBDBDB\",
  509. \"B c #C9C8C8\",
  510. \"C c #A8A9A8\",
  511. \"D c #9D9E9D\",
  512. \"E c #929292\",
  513. \"F c #8A8888\",
  514. \"G c #D3CECE\",
  515. \"H c #B0B0B0\",
  516. \"I c #D1D1D1\",
  517. \"J c #DCDCDC\",
  518. \"K c #E6E6E6\",
  519. \"L c #EEEEEE\",
  520. \"M c #F1F1F0\",
  521. \"N c #EBEBEB\",
  522. \"O c #D7D7D8\",
  523. \"P c #ABABAB\",
  524. \"Q c #A0A0A0\",
  525. \"R c #949494\",
  526. \"S c #898989\",
  527. \"T c #C0BDBD\",
  528. \"U c #B9B6B6\",
  529. \"V c #B1B1B1\",
  530. \"W c #BCBCBC\",
  531. \"X c #C8C8C8\",
  532. \"Y c #D3D3D3\",
  533. \"Z c #DFDFDE\",
  534. \"` c #EAEAEA\",
  535. \" . c #F5F5F5\",
  536. \".. c #FAFAFA\",
  537. \"+. c #F1F1F1\",
  538. \"@. c #CECFCF\",
  539. \"#. c #ACACAC\",
  540. \"$. c #A1A1A1\",
  541. \"%. c #8A8A8A\",
  542. \"&. c #9B9999\",
  543. \"*. c #C7C7C7\",
  544. \"=. c #DDDDDD\",
  545. \"-. c #E8E8E8\",
  546. \";. c #F2F2F2\",
  547. \">. c #898A89\",
  548. \",. c #7A7878\",
  549. \"'. c #AEAEAE\",
  550. \"). c #C4C4C4\",
  551. \"!. c #CBCBCA\",
  552. \"~. c #AAAAAA\",
  553. \"{. c #939393\",
  554. \"]. c #888888\",
  555. \"^. c #7C7C7C\",
  556. \"/. c #AAAAAB\",
  557. \"(. c #BFBFBF\",
  558. \"_. c #C9C9C9\",
  559. \":. c #DFDEDF\",
  560. \"<. c #A6A6A6\",
  561. \"[. c #9B9B9B\",
  562. \"}. c #909191\",
  563. \"|. c #858586\",
  564. \"1. c #797979\",
  565. \"2. c #989494\",
  566. \"3. c #A5A6A5\",
  567. \"4. c #B9B9B8\",
  568. \"5. c #C1C1C1\",
  569. \"6. c #CFCFCE\",
  570. \"7. c #979797\",
  571. \"8. c #8D8D8D\",
  572. \"9. c #828282\",
  573. \"0. c #747171\",
  574. \"a. c #ADAAAA\",
  575. \"b. c #A9A8A9\",
  576. \"c. c #B8B9B9\",
  577. \"d. c #A5A5A5\",
  578. \"e. c #9C9C9C\",
  579. \"f. c #7E7E7D\",
  580. \"g. c #929191\",
  581. \"h. c #C9C4C4\",
  582. \"i. c #989898\",
  583. \"j. c #ADADAD\",
  584. \"k. c #9D9D9D\",
  585. \"l. c #8C8C8C\",
  586. \"m. c #787878\",
  587. \"n. c #B8B6B6\",
  588. \"o. c #939191\",
  589. \"p. c #A5A5A6\",
  590. \"q. c #ABABAA\",
  591. \"r. c #A8A8A9\",
  592. \"s. c #A3A3A3\",
  593. \"t. c #858585\",
  594. \"u. c #757474\",
  595. \"v. c #C5C1C1\",
  596. \"w. c #969696\",
  597. \"x. c #9B9B9C\",
  598. \"y. c #A4A4A4\",
  599. \"z. c #9E9E9E\",
  600. \"A. c #939394\",
  601. \"B. c #7D7D7D\",
  602. \"C. c #747474\",
  603. \"D. c #B7B5B5\",
  604. \"E. c #A5A1A1\",
  605. \"F. c #919191\",
  606. \"G. c #9A9999\",
  607. \"H. c #838383\",
  608. \"I. c #757575\",
  609. \"J. c #939090\",
  610. \"K. c #A29E9E\",
  611. \"L. c #868686\",
  612. \"M. c #8D8D8C\",
  613. \"N. c #8E8E8E\",
  614. \"O. c #8D8D8E\",
  615. \"P. c #8B8C8C\",
  616. \"Q. c #848485\",
  617. \"R. c #7F7F80\",
  618. \"S. c #7A7A7A\",
  619. \"T. c #737373\",
  620. \"U. c #929090\",
  621. \"V. c #828080\",
  622. \"W. c #818181\",
  623. \"X. c #808080\",
  624. \"Y. c #7E7E7E\",
  625. \"Z. c #737272\",
  626. \"`. c #B7B4B4\",
  627. \" + c #BCBABA\",
  628. \".+ c #959494\",
  629. \"++ c #747172\",
  630. \"@+ c #767676\",
  631. \"#+ c #6F6D6D\",
  632. \"$+ c #8F8E8E\",
  633. \" . + @ # $ % & * = . \",
  634. \" - ; > , ' ) ! ~ { ] ^ / \",
  635. \" ( _ > : < [ } | 1 2 3 4 ] 5 6 ( \",
  636. \" 7 ) 1 8 9 0 a b c | : 3 { d e f \",
  637. \" g ! h i 0 j k l m n o | 2 ~ p q r s \",
  638. \". t ' | u v w x y z A n B 1 ! C D E F . \",
  639. \"G H : i I J K L M N z O b | ) P Q R S T \",
  640. \"U V W X Y Z ` ...+.y l @.} ' #.$.e %.&.\",
  641. \"& H W *.n =.-.;. .L x k 0 [ , #.Q e >.,.\",
  642. \"] '.2 ).a k z -.` K w j !.< > ~.d {.].^.\",
  643. \"d /.> (._.I k =.:.J v 0 8 : V <.[.}.|.1.\",
  644. \"2.3.~ 4.5._.6.n Y I u i 1 > P $.7.8.9.0.\",
  645. \"a.d b.V c.(.).*.X i | h ) '.d.e.E ].f.g.\",
  646. \"h.i.$.C ~ > 2 W W : ' ! j.d.k.e l.9.m.n.\",
  647. \". o.i.d p.q.'.H V H j.r.s.k.e 8.t.^.u.. \",
  648. \" v.r w.x.Q s.d.d.y.] z.5 A.8.t.B.C.D. \",
  649. \" E.l.F.e i.G.q 5 7.{.r %.H.^.I.J. \",
  650. \" ( K.L.%.M.N.N.O.P.S Q.R.S.T.U.( \",
  651. \" @ V.W.H.H.9.X.Y.S.I.Z.`. \",
  652. \" . +.+++@+C.#+$+D.. \"};")
  653. ;; ======================================================================
  654. ;; Functions
  655. (defsubst bubbles--grid-width ()
  656. "Return the grid width for the current game theme."
  657. (car (case bubbles-game-theme
  658. (easy
  659. bubbles--grid-small)
  660. (medium
  661. bubbles--grid-medium)
  662. (difficult
  663. bubbles--grid-large)
  664. (hard
  665. bubbles--grid-huge)
  666. (user-defined
  667. bubbles-grid-size))))
  668. (defsubst bubbles--grid-height ()
  669. "Return the grid height for the current game theme."
  670. (cdr (case bubbles-game-theme
  671. (easy
  672. bubbles--grid-small)
  673. (medium
  674. bubbles--grid-medium)
  675. (difficult
  676. bubbles--grid-large)
  677. (hard
  678. bubbles--grid-huge)
  679. (user-defined
  680. bubbles-grid-size))))
  681. (defsubst bubbles--colors ()
  682. "Return the color list for the current game theme."
  683. (case bubbles-game-theme
  684. (easy
  685. bubbles--colors-2)
  686. (medium
  687. bubbles--colors-3)
  688. (difficult
  689. bubbles--colors-4)
  690. (hard
  691. bubbles--colors-5)
  692. (user-defined
  693. bubbles-colors)))
  694. (defsubst bubbles--shift-mode ()
  695. "Return the shift mode for the current game theme."
  696. (case bubbles-game-theme
  697. (easy
  698. 'default)
  699. (medium
  700. 'default)
  701. (difficult
  702. 'always)
  703. (hard
  704. 'always)
  705. (user-defined
  706. bubbles-shift-mode)))
  707. (defun bubbles-save-settings ()
  708. "Save current customization settings."
  709. (interactive)
  710. (custom-set-variables
  711. (list 'bubbles-game-theme `(quote ,bubbles-game-theme) t)
  712. (list 'bubbles-graphics-theme `(quote ,bubbles-graphics-theme) t))
  713. (customize-save-customized))
  714. (defsubst bubbles--empty-char ()
  715. "The character used for removed bubbles (empty grid cells)."
  716. ?\s)
  717. (defun bubbles-set-graphics-theme-ascii ()
  718. "Set graphics theme to `ascii'."
  719. (interactive)
  720. (setq bubbles-graphics-theme 'ascii)
  721. (bubbles--update-faces-or-images))
  722. (defun bubbles-set-graphics-theme-circles ()
  723. "Set graphics theme to `circles'."
  724. (interactive)
  725. (setq bubbles-graphics-theme 'circles)
  726. (bubbles--initialize-images)
  727. (bubbles--update-faces-or-images))
  728. (defun bubbles-set-graphics-theme-squares ()
  729. "Set graphics theme to `squares'."
  730. (interactive)
  731. (setq bubbles-graphics-theme 'squares)
  732. (bubbles--initialize-images)
  733. (bubbles--update-faces-or-images))
  734. (defun bubbles-set-graphics-theme-diamonds ()
  735. "Set graphics theme to `diamonds'."
  736. (interactive)
  737. (setq bubbles-graphics-theme 'diamonds)
  738. (bubbles--initialize-images)
  739. (bubbles--update-faces-or-images))
  740. (defun bubbles-set-graphics-theme-balls ()
  741. "Set graphics theme to `balls'."
  742. (interactive)
  743. (setq bubbles-graphics-theme 'balls)
  744. (bubbles--initialize-images)
  745. (bubbles--update-faces-or-images))
  746. (defun bubbles-set-graphics-theme-emacs ()
  747. "Set graphics theme to `emacs'."
  748. (interactive)
  749. (setq bubbles-graphics-theme 'emacs)
  750. (bubbles--initialize-images)
  751. (bubbles--update-faces-or-images))
  752. ;; game theme menu
  753. (defvar bubbles-game-theme-menu
  754. (let ((menu (make-sparse-keymap "Game Theme")))
  755. (define-key menu [bubbles-set-game-userdefined]
  756. (list 'menu-item "User defined" 'bubbles-set-game-userdefined
  757. :button '(:radio . (eq bubbles-game-theme 'user-defined))))
  758. (define-key menu [bubbles-set-game-hard]
  759. (list 'menu-item "Hard" 'bubbles-set-game-hard
  760. :button '(:radio . (eq bubbles-game-theme 'hard))))
  761. (define-key menu [bubbles-set-game-difficult]
  762. (list 'menu-item "Difficult" 'bubbles-set-game-difficult
  763. :button '(:radio . (eq bubbles-game-theme 'difficult))))
  764. (define-key menu [bubbles-set-game-medium]
  765. (list 'menu-item "Medium" 'bubbles-set-game-medium
  766. :button '(:radio . (eq bubbles-game-theme 'medium))))
  767. (define-key menu [bubbles-set-game-easy]
  768. (list 'menu-item "Easy" 'bubbles-set-game-easy
  769. :button '(:radio . (eq bubbles-game-theme 'easy))))
  770. menu)
  771. "Map for bubbles game theme menu.")
  772. ;; graphics theme menu
  773. (defvar bubbles-graphics-theme-menu
  774. (let ((menu (make-sparse-keymap "Graphics Theme")))
  775. (define-key menu [bubbles-set-graphics-theme-ascii]
  776. (list 'menu-item "ASCII" 'bubbles-set-graphics-theme-ascii
  777. :button '(:radio . (eq bubbles-graphics-theme 'ascii))))
  778. (define-key menu [bubbles-set-graphics-theme-emacs]
  779. (list 'menu-item "Emacs" 'bubbles-set-graphics-theme-emacs
  780. :button '(:radio . (eq bubbles-graphics-theme 'emacs))))
  781. (define-key menu [bubbles-set-graphics-theme-balls]
  782. (list 'menu-item "Balls" 'bubbles-set-graphics-theme-balls
  783. :button '(:radio . (eq bubbles-graphics-theme 'balls))))
  784. (define-key menu [bubbles-set-graphics-theme-diamonds]
  785. (list 'menu-item "Diamonds" 'bubbles-set-graphics-theme-diamonds
  786. :button '(:radio . (eq bubbles-graphics-theme 'diamonds))))
  787. (define-key menu [bubbles-set-graphics-theme-squares]
  788. (list 'menu-item "Squares" 'bubbles-set-graphics-theme-squares
  789. :button '(:radio . (eq bubbles-graphics-theme 'squares))))
  790. (define-key menu [bubbles-set-graphics-theme-circles]
  791. (list 'menu-item "Circles" 'bubbles-set-graphics-theme-circles
  792. :button '(:radio . (eq bubbles-graphics-theme 'circles))))
  793. menu)
  794. "Map for bubbles graphics theme menu.")
  795. ;; menu
  796. (defvar bubbles-menu
  797. (let ((menu (make-sparse-keymap "Bubbles")))
  798. (define-key menu [bubbles-quit]
  799. (list 'menu-item "Quit" 'bubbles-quit))
  800. (define-key menu [bubbles]
  801. (list 'menu-item "New game" 'bubbles))
  802. (define-key menu [bubbles-separator-1]
  803. '("--"))
  804. (define-key menu [bubbles-save-settings]
  805. (list 'menu-item "Save all settings" 'bubbles-save-settings))
  806. (define-key menu [bubbles-customize]
  807. (list 'menu-item "Edit all settings" 'bubbles-customize))
  808. (define-key menu [bubbles-game-theme-menu]
  809. (list 'menu-item "Game Theme" bubbles-game-theme-menu))
  810. (define-key menu [bubbles-graphics-theme-menu]
  811. (list 'menu-item "Graphics Theme" bubbles-graphics-theme-menu
  812. :enable 'bubbles--playing))
  813. (define-key menu [bubbles-separator-2]
  814. '("--"))
  815. (define-key menu [bubbles-undo]
  816. (list 'menu-item "Undo last move" 'bubbles-undo
  817. :enable '(and bubbles--playing (listp buffer-undo-list))))
  818. menu)
  819. "Map for bubbles menu.")
  820. ;; bubbles mode map
  821. (defvar bubbles-mode-map
  822. (let ((map (make-sparse-keymap 'bubbles-mode-map)))
  823. ;; (suppress-keymap map t)
  824. (define-key map "q" 'bubbles-quit)
  825. (define-key map "\n" 'bubbles-plop)
  826. (define-key map " " 'bubbles-plop)
  827. (define-key map [double-down-mouse-1] 'bubbles-plop)
  828. (define-key map [mouse-2] 'bubbles-plop)
  829. (define-key map "\C-m" 'bubbles-plop)
  830. (define-key map "u" 'bubbles-undo)
  831. (define-key map "p" 'previous-line)
  832. (define-key map "n" 'next-line)
  833. (define-key map "f" 'forward-char)
  834. (define-key map "b" 'backward-char)
  835. ;; bind menu to mouse
  836. (define-key map [down-mouse-3] bubbles-menu)
  837. ;; Put menu in menu-bar
  838. (define-key map [menu-bar Bubbles] (cons "Bubbles" bubbles-menu))
  839. map)
  840. "Mode map for bubbles.")
  841. (define-derived-mode bubbles-mode nil "Bubbles"
  842. "Major mode for playing bubbles.
  843. \\{bubbles-mode-map}"
  844. (setq buffer-read-only t
  845. show-trailing-whitespace nil)
  846. (buffer-disable-undo)
  847. (force-mode-line-update)
  848. (redisplay)
  849. (add-hook 'post-command-hook 'bubbles--mark-neighbourhood t t))
  850. ;;;###autoload
  851. (defun bubbles ()
  852. "Play Bubbles game.
  853. \\<bubbles-mode-map>
  854. The goal is to remove all bubbles with as few moves as possible.
  855. \\[bubbles-plop] on a bubble removes that bubble and all
  856. connected bubbles of the same color. Unsupported bubbles fall
  857. down, and columns that do not contain any bubbles suck the
  858. columns on its right towards the left.
  859. \\[bubbles-set-game-easy] sets the difficulty to easy.
  860. \\[bubbles-set-game-medium] sets the difficulty to medium.
  861. \\[bubbles-set-game-difficult] sets the difficulty to difficult.
  862. \\[bubbles-set-game-hard] sets the difficulty to hard."
  863. (interactive)
  864. (switch-to-buffer (get-buffer-create "*bubbles*"))
  865. (when (or (not bubbles--playing)
  866. (y-or-n-p "Start new game? "))
  867. (setq bubbles--save-data nil)
  868. (setq bubbles--playing t)
  869. (bubbles--initialize)))
  870. (defun bubbles-quit ()
  871. "Quit Bubbles."
  872. (interactive)
  873. (message "bubbles-quit")
  874. (bury-buffer))
  875. (declare-function image-size "image.c" (spec &optional pixels frame))
  876. (defun bubbles--compute-offsets ()
  877. "Update horizontal and vertical offsets for centering the bubbles grid.
  878. Set `bubbles--col-offset' and `bubbles--row-offset'."
  879. (cond ((and (display-images-p)
  880. bubbles--images-ok
  881. (not (eq bubbles-graphics-theme 'ascii))
  882. (fboundp 'window-inside-pixel-edges))
  883. ;; compute offset in units of pixels
  884. (let ((bubbles--image-size
  885. (car (image-size (car bubbles--images) t))))
  886. (setq bubbles--col-offset
  887. (list
  888. (max 0 (/ (- (nth 2 (window-inside-pixel-edges))
  889. (nth 0 (window-inside-pixel-edges))
  890. (* ( + bubbles--image-size 2) ;; margin
  891. (bubbles--grid-width))) 2))))
  892. (setq bubbles--row-offset
  893. (list
  894. (max 0 (/ (- (nth 3 (window-inside-pixel-edges))
  895. (nth 1 (window-inside-pixel-edges))
  896. (* (+ bubbles--image-size 1) ;; margin
  897. (bubbles--grid-height))) 2))))))
  898. (t
  899. ;; compute offset in units of chars
  900. (setq bubbles--col-offset
  901. (max 0 (/ (- (window-width)
  902. (bubbles--grid-width)) 2)))
  903. (setq bubbles--row-offset
  904. (max 0 (/ (- (window-height)
  905. (bubbles--grid-height) 2) 2))))))
  906. (defun bubbles--remove-overlays ()
  907. "Remove all overlays."
  908. (if (fboundp 'remove-overlays)
  909. (remove-overlays)))
  910. (defun bubbles--initialize ()
  911. "Initialize Bubbles game."
  912. (bubbles--initialize-faces)
  913. (bubbles--initialize-images)
  914. (bubbles--remove-overlays)
  915. (switch-to-buffer (get-buffer-create "*bubbles*"))
  916. (bubbles--compute-offsets)
  917. (let ((inhibit-read-only t))
  918. (set-buffer-modified-p nil)
  919. (erase-buffer)
  920. (insert " ")
  921. (add-text-properties
  922. (point-min) (point) (list 'intangible t 'display
  923. (cons 'space
  924. (list :height bubbles--row-offset))))
  925. (insert "\n")
  926. (let ((max-char (length (bubbles--colors))))
  927. (dotimes (i (bubbles--grid-height))
  928. (let ((p (point)))
  929. (insert " ")
  930. (add-text-properties
  931. p (point) (list 'intangible t
  932. 'display (cons 'space
  933. (list :width
  934. bubbles--col-offset)))))
  935. (dotimes (j (bubbles--grid-width))
  936. (let* ((index (random max-char))
  937. (char (nth index bubbles-chars)))
  938. (insert char)
  939. (add-text-properties (1- (point)) (point) (list 'index index))))
  940. (insert "\n"))
  941. (insert "\n ")
  942. (add-text-properties
  943. (1- (point)) (point) (list 'intangible t 'display
  944. (cons 'space
  945. (list :width bubbles--col-offset)))))
  946. (put-text-property (point-min) (point-max) 'pointer 'arrow))
  947. (bubbles-mode)
  948. (bubbles--reset-score)
  949. (bubbles--update-faces-or-images)
  950. (bubbles--goto 0 0)
  951. (setq buffer-undo-list t)
  952. (force-mode-line-update)
  953. (redisplay))
  954. (defun bubbles--initialize-faces ()
  955. "Prepare faces for playing `bubbles'."
  956. (copy-face 'default 'bubbles--highlight-face)
  957. (set-face-background 'bubbles--highlight-face "#8080f4")
  958. (when (display-color-p)
  959. (setq bubbles--faces
  960. (mapcar (lambda (color)
  961. (let ((fname (intern (format "bubbles--face-%s" color))))
  962. (unless (facep fname)
  963. (copy-face 'default fname)
  964. (set-face-foreground fname color))
  965. fname))
  966. (bubbles--colors)))))
  967. (defsubst bubbles--row (pos)
  968. "Return row of point POS."
  969. (save-excursion
  970. (goto-char pos)
  971. (beginning-of-line)
  972. (1- (count-lines (point-min) (point)))))
  973. (defsubst bubbles--col (pos)
  974. "Return column of point POS."
  975. (save-excursion
  976. (goto-char pos)
  977. (1- (current-column))))
  978. (defun bubbles--goto (row col)
  979. "Move point to bubble at coordinates ROW and COL."
  980. (if (or (< row 0)
  981. (< col 0)
  982. (>= row (bubbles--grid-height))
  983. (>= col (bubbles--grid-width)))
  984. ;; Error! return nil
  985. nil
  986. ;; go
  987. (goto-char (point-min))
  988. (forward-line (1+ row))
  989. (forward-char (1+ col))
  990. (point)))
  991. (defun bubbles--char-at (row col)
  992. "Return character at bubble ROW and COL."
  993. (save-excursion
  994. (if (bubbles--goto row col)
  995. (char-after (point))
  996. nil)))
  997. (defun bubbles--mark-direct-neighbours (row col char)
  998. "Mark direct neighbors of bubble at ROW COL with same CHAR."
  999. (save-excursion
  1000. (let ((count 0))
  1001. (when (and (bubbles--goto row col)
  1002. (eq char (char-after (point)))
  1003. (not (get-text-property (point) 'active)))
  1004. (add-text-properties (point) (1+ (point))
  1005. '(active t face 'bubbles--highlight-face))
  1006. (setq count (+ 1
  1007. (bubbles--mark-direct-neighbours row (1+ col) char)
  1008. (bubbles--mark-direct-neighbours row (1- col) char)
  1009. (bubbles--mark-direct-neighbours (1+ row) col char)
  1010. (bubbles--mark-direct-neighbours (1- row) col char))))
  1011. count)))
  1012. (defun bubbles--mark-neighbourhood (&optional pos)
  1013. "Mark neighborhood of point.
  1014. Use optional parameter POS instead of point if given."
  1015. (when bubbles--playing
  1016. (unless pos (setq pos (point)))
  1017. (condition-case err
  1018. (let ((char (char-after pos))
  1019. (inhibit-read-only t)
  1020. (row (bubbles--row (point)))
  1021. (col (bubbles--col (point))))
  1022. (add-text-properties (point-min) (point-max)
  1023. '(face default active nil))
  1024. (let ((count 0))
  1025. (when (and row col (not (eq char (bubbles--empty-char))))
  1026. (setq count (bubbles--mark-direct-neighbours row col char))
  1027. (unless (> count 1)
  1028. (add-text-properties (point-min) (point-max)
  1029. '(face default active nil))
  1030. (setq count 0)))
  1031. (bubbles--update-neighbourhood-score count))
  1032. (put-text-property (point-min) (point-max) 'pointer 'arrow)
  1033. (bubbles--update-faces-or-images)
  1034. (sit-for 0))
  1035. (error (message "Bubbles: Internal error %s" err)))))
  1036. (defun bubbles--neighbourhood-available ()
  1037. "Return t if another valid neighborhood is available."
  1038. (catch 'found
  1039. (save-excursion
  1040. (dotimes (i (bubbles--grid-height))
  1041. (dotimes (j (bubbles--grid-width))
  1042. (let ((c (bubbles--char-at i j)))
  1043. (if (and (not (eq c (bubbles--empty-char)))
  1044. (or (eq c (bubbles--char-at (1+ i) j))
  1045. (eq c (bubbles--char-at i (1+ j)))))
  1046. (throw 'found t)))))
  1047. nil)))
  1048. (defun bubbles--count ()
  1049. "Count remaining bubbles."
  1050. (let ((count 0))
  1051. (save-excursion
  1052. (dotimes (i (bubbles--grid-height))
  1053. (dotimes (j (bubbles--grid-width))
  1054. (let ((c (bubbles--char-at i j)))
  1055. (if (not (eq c (bubbles--empty-char)))
  1056. (setq count (1+ count)))))))
  1057. count))
  1058. (defun bubbles--reset-score ()
  1059. "Reset bubbles score."
  1060. (setq bubbles--neighbourhood-score 0
  1061. bubbles--score 0)
  1062. (bubbles--update-score))
  1063. (defun bubbles--update-score ()
  1064. "Calculate and display new bubbles score."
  1065. (setq bubbles--score (+ bubbles--score bubbles--neighbourhood-score))
  1066. (bubbles--show-scores))
  1067. (defun bubbles--update-neighbourhood-score (size)
  1068. "Calculate and display score of active neighborhood from its SIZE."
  1069. (if (> size 1)
  1070. (setq bubbles--neighbourhood-score (expt (- size 1) 2))
  1071. (setq bubbles--neighbourhood-score 0))
  1072. (bubbles--show-scores))
  1073. (defun bubbles--show-scores ()
  1074. "Display current scores."
  1075. (save-excursion
  1076. (goto-char (or (next-single-property-change (point-min) 'status)
  1077. (point-max)))
  1078. (let ((inhibit-read-only t)
  1079. (pos (point)))
  1080. (delete-region (point) (point-max))
  1081. (insert (format "Selected: %4d\n" bubbles--neighbourhood-score))
  1082. (insert " ")
  1083. (add-text-properties (1- (point)) (point)
  1084. (list 'intangible t 'display
  1085. (cons 'space
  1086. (list :width bubbles--col-offset))))
  1087. (insert (format "Score: %4d" bubbles--score))
  1088. (put-text-property pos (point) 'status t))))
  1089. (defun bubbles--game-over ()
  1090. "Finish bubbles game."
  1091. (bubbles--update-faces-or-images)
  1092. (setq bubbles--playing nil
  1093. bubbles--save-data nil)
  1094. ;; add bonus if all bubbles were removed
  1095. (when (= 0 (bubbles--count))
  1096. (setq bubbles--score (+ bubbles--score (* (bubbles--grid-height)
  1097. (bubbles--grid-width))))
  1098. (bubbles--show-scores))
  1099. ;; Game over message
  1100. (goto-char (point-max))
  1101. (let* ((inhibit-read-only t))
  1102. (insert "\n ")
  1103. (add-text-properties (1- (point)) (point)
  1104. (list 'intangible t 'display
  1105. (cons 'space
  1106. (list :width bubbles--col-offset))))
  1107. (insert "Game Over!"))
  1108. ;; save score
  1109. (gamegrid-add-score (format "bubbles-%s-%d-%d-%d-scores"
  1110. (symbol-name (bubbles--shift-mode))
  1111. (length (bubbles--colors))
  1112. (bubbles--grid-width) (bubbles--grid-height))
  1113. bubbles--score))
  1114. (defun bubbles-plop ()
  1115. "Remove active bubbles region."
  1116. (interactive)
  1117. (when (and bubbles--playing
  1118. (> bubbles--neighbourhood-score 0))
  1119. (setq bubbles--save-data (list bubbles--score (buffer-string)))
  1120. (let ((inhibit-read-only t))
  1121. ;; blank out current neighbourhood
  1122. (let ((row (bubbles--row (point)))
  1123. (col (bubbles--col (point))))
  1124. (goto-char (point-max))
  1125. (while (not (bobp))
  1126. (backward-char)
  1127. (while (get-text-property (point) 'active)
  1128. (delete-char 1)
  1129. (insert (bubbles--empty-char))
  1130. (add-text-properties (1- (point)) (point) (list 'removed t
  1131. 'index -1))))
  1132. (bubbles--goto row col))
  1133. ;; show new score
  1134. (bubbles--update-score)
  1135. ;; update display and wait
  1136. (bubbles--update-faces-or-images)
  1137. (sit-for 0)
  1138. (sleep-for 0.2)
  1139. (discard-input)
  1140. ;; drop down
  1141. (let ((something-dropped nil))
  1142. (save-excursion
  1143. (dotimes (i (bubbles--grid-height))
  1144. (dotimes (j (bubbles--grid-width))
  1145. (bubbles--goto i j)
  1146. (while (get-text-property (point) 'removed)
  1147. (setq something-dropped (or (bubbles--shift 'top i j)
  1148. something-dropped))))))
  1149. ;; update display and wait
  1150. (bubbles--update-faces-or-images)
  1151. (when something-dropped
  1152. (sit-for 0)))
  1153. (discard-input)
  1154. ;; shift to left
  1155. (put-text-property (point-min) (point-max) 'removed nil)
  1156. (save-excursion
  1157. (goto-char (point-min))
  1158. (let ((removed-string (format "%c" (bubbles--empty-char))))
  1159. (while (search-forward removed-string nil t)
  1160. (put-text-property (1- (point)) (point) 'removed t))))
  1161. (let ((shifted nil))
  1162. (cond ((eq (bubbles--shift-mode) 'always)
  1163. (save-excursion
  1164. (dotimes (i (bubbles--grid-height))
  1165. (dotimes (j (bubbles--grid-width))
  1166. (bubbles--goto i j)
  1167. (while (get-text-property (point) 'removed)
  1168. (setq shifted (or (bubbles--shift 'right i j)
  1169. shifted))))))
  1170. (bubbles--update-faces-or-images)
  1171. (sleep-for 0.5))
  1172. (t ;; default shift-mode
  1173. (save-excursion
  1174. (dotimes (j (bubbles--grid-width))
  1175. (bubbles--goto (1- (bubbles--grid-height)) j)
  1176. (let ((shifted-cols 0))
  1177. (while (get-text-property (point) 'removed)
  1178. (setq shifted-cols (1+ shifted-cols))
  1179. (bubbles--shift 'right (1- (bubbles--grid-height)) j))
  1180. (dotimes (k shifted-cols)
  1181. (let ((i (- (bubbles--grid-height) 2)))
  1182. (while (>= i 0)
  1183. (setq shifted (or (bubbles--shift 'right i j)
  1184. shifted))
  1185. (setq i (1- i))))))))))
  1186. (when shifted
  1187. ;;(sleep-for 0.5)
  1188. (bubbles--update-faces-or-images)
  1189. (sit-for 0)))
  1190. (put-text-property (point-min) (point-max) 'removed nil)
  1191. (unless (bubbles--neighbourhood-available)
  1192. (bubbles--game-over)))
  1193. ;; undo
  1194. (setq buffer-undo-list '((apply bubbles-undo . nil)))
  1195. (force-mode-line-update)
  1196. (redisplay)))
  1197. (defun bubbles-undo ()
  1198. "Undo last move."
  1199. (interactive)
  1200. (when bubbles--save-data
  1201. (let ((inhibit-read-only t)
  1202. (pos (point)))
  1203. (erase-buffer)
  1204. (insert (cadr bubbles--save-data))
  1205. (bubbles--update-faces-or-images)
  1206. (setq bubbles--score (car bubbles--save-data))
  1207. (goto-char pos))
  1208. (setq buffer-undo-list t)
  1209. (force-mode-line-update)
  1210. (redisplay)))
  1211. (defun bubbles--shift (from row col)
  1212. "Move bubbles FROM one side to position ROW COL.
  1213. Return t if new char is non-empty."
  1214. (save-excursion
  1215. (when (bubbles--goto row col)
  1216. (let ((char-new (bubbles--empty-char))
  1217. (removed nil)
  1218. (trow row)
  1219. (tcol col)
  1220. (index -1))
  1221. (cond ((eq from 'top)
  1222. (setq trow (1- row)))
  1223. ((eq from 'left)
  1224. (setq tcol (1- col)))
  1225. ((eq from 'right)
  1226. (setq tcol (1+ col))))
  1227. (save-excursion
  1228. (when (bubbles--goto trow tcol)
  1229. (setq char-new (char-after (point)))
  1230. (setq removed (get-text-property (point) 'removed))
  1231. (setq index (get-text-property (point) 'index))
  1232. (bubbles--shift from trow tcol)))
  1233. (insert char-new)
  1234. (delete-char 1)
  1235. (add-text-properties (1- (point)) (point) (list 'index index
  1236. 'removed removed))
  1237. (not (eq char-new (bubbles--empty-char)))))))
  1238. (defun bubbles--initialize-images ()
  1239. "Prepare images for playing `bubbles'."
  1240. (when (and (display-images-p)
  1241. (not (eq bubbles-graphics-theme 'ascii)))
  1242. (let ((template (case bubbles-graphics-theme
  1243. (circles bubbles--image-template-circle)
  1244. (balls bubbles--image-template-ball)
  1245. (squares bubbles--image-template-square)
  1246. (diamonds bubbles--image-template-diamond)
  1247. (emacs bubbles--image-template-emacs))))
  1248. (setq bubbles--empty-image
  1249. (create-image (replace-regexp-in-string
  1250. "^\"\\(.*\\)\t.*c .*\",$"
  1251. "\"\\1\tc None\"," template)
  1252. 'xpm t
  1253. ;;:mask 'heuristic
  1254. :margin '(2 . 1)))
  1255. (setq bubbles--images
  1256. (mapcar (lambda (color)
  1257. (let* ((rgb (color-values color))
  1258. (red (nth 0 rgb))
  1259. (green (nth 1 rgb))
  1260. (blue (nth 2 rgb)))
  1261. (with-temp-buffer
  1262. (insert template)
  1263. (goto-char (point-min))
  1264. (re-search-forward
  1265. "^\"[0-9]+ [0-9]+ \\(.*?\\) .*\",$" nil t)
  1266. (goto-char (point-min))
  1267. (while (re-search-forward
  1268. "^\"\\(.*\\)\t.*c \\(#.*\\)\",$" nil t)
  1269. (let* ((crgb (color-values (match-string 2)))
  1270. (r (nth 0 crgb))
  1271. (g (nth 1 crgb))
  1272. (b (nth 2 crgb))
  1273. (brightness (/ (+ r g b) 3.0 256 256))
  1274. (val (sin (* brightness (/ float-pi 2))))
  1275. (rr (* red val))
  1276. (gg (* green val))
  1277. (bb (* blue val))
  1278. ;;(rr (/ (+ red r) 2))
  1279. ;;(gg (/ (+ green g) 2))
  1280. ;;(bb (/ (+ blue b) 2))
  1281. (color (format "#%02x%02x%02x"
  1282. (/ rr 256) (/ gg 256)
  1283. (/ bb 256))))
  1284. (replace-match (format "\"\\1\tc %s\","
  1285. (upcase color)))))
  1286. (create-image (buffer-string) 'xpm t
  1287. :margin '(2 . 1)
  1288. ;;:mask 'heuristic
  1289. ))))
  1290. (bubbles--colors))))
  1291. ;; check images
  1292. (setq bubbles--images-ok bubbles--empty-image)
  1293. (mapc (lambda (elt)
  1294. (setq bubbles--images-ok (and bubbles--images-ok elt)))
  1295. bubbles--images)))
  1296. (defun bubbles--update-faces-or-images ()
  1297. "Update faces and/or images, depending on graphics mode."
  1298. (bubbles--set-faces)
  1299. (bubbles--show-images))
  1300. (defun bubbles--set-faces ()
  1301. "Update faces in the bubbles buffer."
  1302. (unless (and (display-images-p)
  1303. bubbles--images-ok
  1304. (not (eq bubbles-graphics-theme 'ascii)))
  1305. (when (display-color-p)
  1306. (save-excursion
  1307. (let ((inhibit-read-only t))
  1308. (dotimes (i (bubbles--grid-height))
  1309. (dotimes (j (bubbles--grid-width))
  1310. (bubbles--goto i j)
  1311. (let ((face (nth (get-text-property (point) 'index)
  1312. bubbles--faces)))
  1313. (when (get-text-property (point) 'active)
  1314. (set-face-foreground 'bubbles--highlight-face "#ff0000")
  1315. (setq face 'bubbles--highlight-face))
  1316. (put-text-property (point) (1+ (point))
  1317. 'face face)))))))))
  1318. (defun bubbles--show-images ()
  1319. "Update images in the bubbles buffer."
  1320. (bubbles--remove-overlays)
  1321. (if (and (display-images-p)
  1322. bubbles--images-ok
  1323. (not (eq bubbles-graphics-theme 'ascii)))
  1324. (save-excursion
  1325. (goto-char (point-min))
  1326. (forward-line 1)
  1327. (let ((inhibit-read-only t))
  1328. (dotimes (i (bubbles--grid-height))
  1329. (dotimes (j (bubbles--grid-width))
  1330. (forward-char 1)
  1331. (let ((index (or (get-text-property (point) 'index) -1)))
  1332. (let ((img bubbles--empty-image))
  1333. (if (>= index 0)
  1334. (setq img (nth index bubbles--images)))
  1335. (put-text-property (point) (1+ (point))
  1336. 'display (cons img nil)))))
  1337. (forward-line 1))))
  1338. (save-excursion
  1339. (let ((inhibit-read-only t))
  1340. (goto-char (point-min))
  1341. (while (not (eobp))
  1342. (let ((disp-prop (get-text-property (point) 'display)))
  1343. (if (and (listp disp-prop)
  1344. (listp (car disp-prop))
  1345. (eq (caar disp-prop) 'image))
  1346. (put-text-property (point) (1+ (point)) 'display nil))
  1347. (forward-char 1)))
  1348. (put-text-property (point-min) (point-max) 'pointer 'arrow)))))
  1349. (provide 'bubbles)
  1350. ;;; bubbles.el ends here