Игра Маджонг | Mahjong game
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

472 line
16KB

  1. мж.ресурсы = [
  2. [Б + "модели/фишка/2019-09-08.osgt", "mod"],
  3. [Б + "текстуры/заглушка.png", "tex.stub"],
  4. [Б + "шейдеры/освещение-изображение.vert", "ver"],
  5. [Б + "шейдеры/освещение-изображение.frag", "fra"],
  6. [Б + "раскладки/X_shaped.layout", "lay"],
  7. ];
  8. мж.начали = new Уведомитель();
  9. мж.начать = function()
  10. {
  11. муром.камера.позиция = [0, -70, 0];
  12. муром.камера.вращение = [90, 0, 0];
  13. мж.сцена = муром.узлы.создатьСферу("sce", 0);
  14. мж.сцена.вращение = [60, 0, 0];
  15. var мир = муром.узлы.узел("mir");
  16. мир.добавитьДитя(мж.сцена);
  17. мж.начали.уведомить();
  18. };
  19. мж.задатьНейтральныйМатериал = function()
  20. {
  21. var мат = муром.материалы.создатьМатериал("N");
  22. var изо = муром.ресурсы.ресурс("tex.stub");
  23. мат.задатьТекстуру("image", изо);
  24. var вер = муром.ресурсы.ресурс("ver").содержимое;
  25. var фра = муром.ресурсы.ресурс("fra").содержимое;
  26. мат.задатьШейдеры(вер, фра);
  27. мж.сцена.задатьМатериал(мат);
  28. };
  29. мж.разобратьРаскладку = function()
  30. {
  31. var содержимое = муром.ресурсы.ресурс("lay").содержимое;
  32. мж.раскладка = new Раскладка();
  33. мж.раскладка.разобрать(содержимое);
  34. };
  35. мж.фишки = [];
  36. мж.создатьФишки = function()
  37. {
  38. for (var номер in мж.раскладка.позиции)
  39. {
  40. var ф = new Фишка();
  41. ф.позиция = мж.раскладка.позиции[номер];
  42. мж.фишки.push(ф);
  43. }
  44. };
  45. мж.размерФишки = {
  46. "ширина": 2.0,
  47. "высота": 3.0,
  48. "глубина": 1.0,
  49. };
  50. мж.создатьУзлыФишек = function()
  51. {
  52. const шагФишки = 2.0;
  53. const коэффициенты = {
  54. "x": мж.размерФишки.ширина / шагФишки,
  55. "y": -мж.размерФишки.высота / шагФишки,
  56. "z": мж.размерФишки.глубина,
  57. };
  58. var мод = муром.ресурсы.ресурс("mod");
  59. for (var номер in мж.фишки)
  60. {
  61. var имя = номер.toString();
  62. var узел = муром.узлы.создатьУзел(имя, мод);
  63. мж.сцена.добавитьДитя(узел);
  64. var ф = мж.фишки[номер];
  65. var п = ф.позиция;
  66. узел.позиция = [
  67. п[2] * коэффициенты.x,
  68. п[1] * коэффициенты.y,
  69. п[0] * коэффициенты.z,
  70. ];
  71. ф.узел = узел;
  72. }
  73. };
  74. мж.центрироватьСцену = function()
  75. {
  76. var границы = {
  77. "лево": 1000,
  78. "право": -1000,
  79. "верх": -1000,
  80. "низ": 1000,
  81. };
  82. for (var номер in мж.фишки)
  83. {
  84. const ф = мж.фишки[номер];
  85. const x = ф.узел.позиция[0];
  86. const y = ф.узел.позиция[1];
  87. if (x < границы.лево)
  88. {
  89. границы.лево = x;
  90. }
  91. if (x > границы.право)
  92. {
  93. границы.право = x;
  94. }
  95. if (y < границы.низ)
  96. {
  97. границы.низ = y;
  98. }
  99. if (y > границы.верх)
  100. {
  101. границы.верх = y;
  102. }
  103. }
  104. const ширина = границы.право - границы.лево + мж.размерФишки.ширина;
  105. const высота = границы.верх - границы.низ + мж.размерФишки.высота;
  106. мж.сцена.позиция = [-ширина / 2.0, 0, высота / 2.0];
  107. };
  108. // http://www.rubl.com/rules/mahjong-solitaire-rules.html
  109. мж.задатьФишкамГруппыПоследовательно = function()
  110. {
  111. var группы = [];
  112. // Генерируем группы.
  113. const группВсего = 42;
  114. const группПо4Дубля = 34;
  115. for (var г = 0; г < группВсего; ++г)
  116. {
  117. const четыреДубля = (г < группПо4Дубля);
  118. const колвоДублей = четыреДубля ? 4 : 1;
  119. for (var д = 0; д < колвоДублей; ++д)
  120. {
  121. группы.push(г);
  122. }
  123. }
  124. // Задаём.
  125. for (var номер in мж.фишки)
  126. {
  127. var ф = мж.фишки[номер];
  128. ф.группа = Number(группы[номер]);
  129. }
  130. };
  131. мж.применитьТемуФишек = function()
  132. {
  133. const R = RR();
  134. // Создать текстуры.
  135. var обозначения = [];
  136. var текстуры = [];
  137. for (var номер in R)
  138. {
  139. var обозначение = R[номер][0];
  140. обозначения.push(обозначение);
  141. var имя = "tile.tex/" + обозначение;
  142. var содержимое = R[номер][1];
  143. var текстура = муром.ресурсы.создатьРесурс(имя, содержимое);
  144. текстуры.push(текстура);
  145. }
  146. // Создать материалы.
  147. var нейтраль = [];
  148. var выбор = [];
  149. var вер = муром.ресурсы.ресурс("ver").содержимое;
  150. var фра = муром.ресурсы.ресурс("fra").содержимое;
  151. // Нейтраль.
  152. for (var номер = 0; номер < 42; ++номер)
  153. {
  154. var имя = "tile.mat/" + обозначения[номер];
  155. var изо = текстуры[номер];
  156. var мат = муром.материалы.создатьМатериал(имя);
  157. мат.задатьТекстуру("image", изо);
  158. мат.задатьШейдеры(вер, фра);
  159. нейтраль.push(мат);
  160. }
  161. // Выбор.
  162. for (var номер = 42; номер < 83; ++номер)
  163. {
  164. var имя = "tile.mat/" + обозначения[номер];
  165. var изо = текстуры[номер];
  166. var мат = муром.материалы.создатьМатериал(имя);
  167. мат.задатьТекстуру("image", изо);
  168. мат.задатьШейдеры(вер, фра);
  169. выбор.push(мат);
  170. }
  171. // Применить тему.
  172. for (var номер in мж.фишки)
  173. {
  174. var ф = мж.фишки[номер];
  175. ф.нейтраль = нейтраль[ф.группа];
  176. ф.выбор = выбор[ф.группа];
  177. ф.показатьНейтраль();
  178. }
  179. };
  180. мж.маскаВыбора = 0x2;
  181. мж.сделатьФишкиВыбираемыми = function()
  182. {
  183. for (var номер in мж.фишки)
  184. {
  185. var ф = мж.фишки[номер];
  186. ф.узел.задатьМаску(мж.маскаВыбора);
  187. }
  188. }
  189. мж.индексПозиции = function(п)
  190. {
  191. return п[0] * 1000000 + п[1] * 1000 + п[2];
  192. };
  193. мж.индексПозиций = {};
  194. мж.проиндексироватьПозиции = function()
  195. {
  196. for (var номер in мж.фишки)
  197. {
  198. var ф = мж.фишки[номер];
  199. var и = мж.индексПозиции(ф.позиция);
  200. мж.индексПозиций[и] = true;
  201. }
  202. };
  203. мж.естьСоседи = function(позиция, смещениеПоля, смещениеСтолбца)
  204. {
  205. for (var смещениеРяда = -1; смещениеРяда <= 1; ++смещениеРяда)
  206. {
  207. var сосед = [
  208. Number(позиция[0]) + смещениеПоля,
  209. Number(позиция[1]) + смещениеРяда,
  210. Number(позиция[2]) + смещениеСтолбца,
  211. ];
  212. var и = мж.индексПозиции(сосед);
  213. if (и in мж.индексПозиций)
  214. {
  215. return true;
  216. }
  217. }
  218. // Соседей нет.
  219. return false;
  220. };
  221. мж.можноВыбратьФишку = function(ф)
  222. {
  223. // Проверяем наличие фишек с левой и правой сторон одновременно.
  224. var слева = this.естьСоседи(ф.позиция, 0, -2);
  225. var справа = this.естьСоседи(ф.позиция, 0, 2);
  226. if (слева && справа)
  227. {
  228. return false;
  229. }
  230. // Проверяем наличие фишек непосредственно сверху.
  231. for (var смещение = -1; смещение <= 1; ++смещение)
  232. {
  233. if (this.естьСоседи(ф.позиция, 1, смещение))
  234. {
  235. return false;
  236. }
  237. }
  238. // Фишка не заблокирована.
  239. return true;
  240. };
  241. мж.номерВыбраннойФишки = null;
  242. мж.выбраннаяФишка = null;
  243. мж.выбранаФишка = new Уведомитель();
  244. мж.выбратьФишку = function()
  245. {
  246. // Определить щелчок.
  247. if (муром.мышь.нажатыеКнопки.length == 1)
  248. {
  249. var узел =
  250. муром.камера.узелВПозиции(
  251. муром.мышь.позиция,
  252. мж.маскаВыбора
  253. );
  254. if (узел)
  255. {
  256. var номер = Number(узел.имя);
  257. var ф = мж.фишки[номер];
  258. if (мж.можноВыбратьФишку(ф))
  259. {
  260. мж.номерВыбраннойФишки = номер;
  261. мж.выбраннаяФишка = ф;
  262. мж.выбранаФишка.уведомить();
  263. }
  264. }
  265. }
  266. };
  267. мж.отладитьВыборФишки = function()
  268. {
  269. мж.выбранаФишка.подписать(function(){
  270. console.log(
  271. "Выбор. Номер: '" +
  272. мж.номерВыбраннойФишки +
  273. "' Группа: '" +
  274. мж.выбраннаяФишка.группа +
  275. "'"
  276. );
  277. });
  278. };
  279. мж.показатьВыбраннуюФишку = function()
  280. {
  281. мж.выбраннаяФишка.показатьВыбор();
  282. };
  283. мж.выбранныеФишки = [];
  284. мж.фишкиРазличаются = new Уведомитель();
  285. мж.фишкиСовпадают = new Уведомитель();
  286. мж.фишкиСравнили = new Уведомитель();
  287. мж.сравнитьВыбранныеФишки = function()
  288. {
  289. // Собираем.
  290. мж.выбранныеФишки.push(мж.выбраннаяФишка);
  291. // Удостоверяемся в наличии пары фишек.
  292. if (мж.выбранныеФишки.length != 2)
  293. {
  294. return;
  295. }
  296. var ф1 = мж.выбранныеФишки[0];
  297. var ф2 = мж.выбранныеФишки[1];
  298. // Убираем дубликат при двойном выборе одной фишки.
  299. if (ф1.имя == ф2.имя)
  300. {
  301. мж.выбранныеФишки.shift();
  302. return;
  303. }
  304. // Сравниваем.
  305. if (ф1.группа == ф2.группа)
  306. {
  307. мж.фишкиСовпадают.уведомить();
  308. }
  309. else
  310. {
  311. мж.фишкиРазличаются.уведомить();
  312. }
  313. мж.фишкиСравнили.уведомить();
  314. };
  315. мж.отладитьСравнениеФишек = function()
  316. {
  317. мж.фишкиСовпадают.подписать(function(){
  318. console.log("Фишки совпадают");
  319. });
  320. мж.фишкиРазличаются.подписать(function(){
  321. console.log("Фишки различаются");
  322. });
  323. };
  324. мж.скрытьСовпадающиеФишки = function()
  325. {
  326. мж.выбранныеФишки[0].скрыть();
  327. мж.выбранныеФишки[1].скрыть();
  328. };
  329. мж.убратьСовпадающиеФишки = function()
  330. {
  331. var ф1 = мж.выбранныеФишки[0];
  332. var ф2 = мж.выбранныеФишки[1];
  333. var и1 = мж.индексПозиции(ф1.позиция);
  334. var и2 = мж.индексПозиции(ф2.позиция);
  335. delete мж.индексПозиций[и1];
  336. delete мж.индексПозиций[и2];
  337. };
  338. мж.очиститьОтображениеВыбора = function()
  339. {
  340. мж.выбранныеФишки[0].показатьНейтраль();
  341. мж.выбранныеФишки[1].показатьНейтраль();
  342. };
  343. мж.очиститьВыбор = function()
  344. {
  345. мж.номерВыбраннойФишки = 0;
  346. мж.выбраннаяФишка = null;
  347. мж.выбранныеФишки = [];
  348. };
  349. мж.оставшиесяФишки = [];
  350. мж.задатьОставшиесяФишки = function()
  351. {
  352. мж.оставшиесяФишки = мж.фишки.slice();
  353. };
  354. мж.обновилиОставшиесяФишки = new Уведомитель();
  355. мж.обновитьОставшиесяФишки = function()
  356. {
  357. var и1 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[0]);
  358. мж.оставшиесяФишки.splice(и1, 1);
  359. var и2 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[1]);
  360. мж.оставшиесяФишки.splice(и2, 1);
  361. мж.обновилиОставшиесяФишки.уведомить();
  362. };
  363. мж.доступныеДляВыбораФишки = function()
  364. {
  365. var фишки = [];
  366. for (var номер in мж.оставшиесяФишки)
  367. {
  368. var ф = мж.оставшиесяФишки[номер];
  369. if (мж.можноВыбратьФишку(ф))
  370. {
  371. фишки.push(ф);
  372. }
  373. }
  374. return фишки;
  375. };
  376. мж.естьХод = function()
  377. {
  378. var фишки = мж.доступныеДляВыбораФишки();
  379. for (var н1 in фишки)
  380. {
  381. for (var н2 in фишки)
  382. {
  383. var ф1 = фишки[н1];
  384. var ф2 = фишки[н2];
  385. if (
  386. (ф1.имя != ф2.имя) &&
  387. (ф1.группа == ф2.группа)
  388. ) {
  389. return true;
  390. }
  391. }
  392. }
  393. return false;
  394. }
  395. мж.победа = new Уведомитель();
  396. мж.поражение = new Уведомитель();
  397. мж.проверитьЗавершение = function()
  398. {
  399. var кончилисьФишки = (мж.оставшиесяФишки.length == 0);
  400. if (кончилисьФишки)
  401. {
  402. мж.победа.уведомить();
  403. return;
  404. }
  405. if (!мж.естьХод())
  406. {
  407. мж.поражение.уведомить();
  408. }
  409. };
  410. мж.отладитьЗавершение = function()
  411. {
  412. мж.победа.подписать(function(){
  413. console.log("Игра завершена. ПОБЕДА!");
  414. });
  415. мж.поражение.подписать(function(){
  416. console.log("Игра завершена. ПОРАЖЕНИЕ :(");
  417. });
  418. };
  419. мж.задатьОтображениеЗавершения = function()
  420. {
  421. мж.победа.подписать(function(){
  422. муром.камера.цветОчистки = [0.2, 0.5, 0.2];
  423. });
  424. мж.поражение.подписать(function(){
  425. муром.камера.цветОчистки = [0.5, 0.2, 0.2];
  426. });
  427. };