Browse Source

Поместить в код классы Фишка и Раскладка

master
parent
commit
7aaa564647
1 changed files with 669 additions and 0 deletions
  1. +669
    -0
      код/2019-09-12.js

+ 669
- 0
код/2019-09-12.js View File

@@ -0,0 +1,669 @@

// Фишка.

function Фишка()
{
this.позиция = null;
this.узел = null;
this.группа = null;
this.нейтраль = null;
this.выбор = null;
}
Фишка.prototype.показатьВыбор = function()
{
this.узел.задатьМатериал(this.выбор);
}
Фишка.prototype.показатьНейтраль = function()
{
this.узел.задатьМатериал(this.нейтраль);
}
Фишка.prototype.показать = function()
{
this.узел.задатьМаску(0x0);
}
Фишка.prototype.скрыть = function()
{
// Специальная маска OpenSceneGraph для скрытия узла от камеры.
this.узел.задатьМаску(0xFFFFFFFF);
}
Object.defineProperty(Фишка.prototype, 'имя', {
get: function()
{
return this.узел.имя;
}
});

// Раскладка.

function Раскладка()
{
this.версия = "";
this.ширина = 0;
this.высота = 0;
this.глубина = 0;
this.позиции = [];
// Для внутреннего пользования.
this.поля = [];
};
Раскладка.prototype.разобратьСлужебнуюИнформацию = function(содержимое)
{
const ключи = {
"версия": "kmahjongg-layout-v",
"комментарий": "#",
"ширина": "w",
"высота": "h",
"глубина": "d"
};

// ВНИМАНИЕ Версия 1.0 предполагает заданные заранее ширину и высоту.
this.версия = "";
this.глубина = 0;
this.ширина = 32;
this.высота = 16;
this.поля = [];
var поле = [];
var строки = содержимое.split("\n");
for (var номер in строки)
{
var строка = строки[номер].trim();
// Пропуск.
if (строка.startsWith(ключи.комментарий))
{
continue;
}
// Служебная информация.
if (строка.startsWith(ключи.версия))
{
this.версия = строка.split(ключи.версия)[1];
}
else if (строка.startsWith(ключи.ширина))
{
this.ширина = строка.split(ключи.ширина)[1];
}
else if (строка.startsWith(ключи.высота))
{
this.высота = строка.split(ключи.высота)[1];
}
else if (строка.startsWith(ключи.глубина))
{
this.глубина = строка.split(ключи.глубина)[1];
}
// Поле.
else
{
поле.push(строка);
if (поле.length >= this.высота)
{
this.поля.push(поле.slice());
поле = [];
}
}
}
if (this.глубина == 0)
{
this.глубина = this.поля.length;
}
}
Раскладка.prototype.разобратьПозиции = function()
{
this.позиции = [];
for (var номер in this.поля)
{
var поле = this.поля[номер];
for (var строка = 0; строка < this.высота - 1; ++строка)
{
for (var столбец = 0; столбец < this.ширина - 1; ++столбец)
{
if (
поле[строка][столбец] == "1" &&
поле[строка][столбец + 1] == "2" &&
поле[строка + 1][столбец] == "4" &&
поле[строка + 1][столбец + 1] == "3"
) {
this.позиции.push([номер, строка, столбец]);
}
}
}
}
}
Раскладка.prototype.разобрать = function(содержимое)
{
this.разобратьСлужебнуюИнформацию(содержимое);
this.разобратьПозиции();
}
Раскладка.prototype.отладка = function()
{
var о = "";
о += "Отладочная информация о раскладке:\n";
о += " версия: '" + this.версия + "'\n";
о += " ширина: '" + this.ширина + "'\n";
о += " высота: '" + this.высота + "'\n";
о += " глубина: '" + this.глубина + "'\n";
о += " позиции:\n";
for (var номер in this.позиции)
{
var п = this.позиции[номер];
о += " п(" + номер + "): '" + п[0] + ", " + п[1] + ", " + п[2] + "'\n";
}
return о;
}

// Игра.

мж.ресурсы = [
[Б + "модели/фишка/2019-09-08.osgt", "mod"],
[Б + "текстуры/заглушка.png", "tex.stub"],
[Б + "шейдеры/освещение-изображение.vert", "ver"],
[Б + "шейдеры/освещение-изображение.frag", "fra"],
[Б + "раскладки/X_shaped.layout", "lay"],
];

мж.начали = new Уведомитель();
мж.начать = function()
{
муром.камера.позиция = [0, -70, 0];
муром.камера.вращение = [90, 0, 0];
мж.сцена = муром.узлы.создатьСферу("sce", 0);
мж.сцена.вращение = [60, 0, 0];
var мир = муром.узлы.узел("mir");
мир.добавитьДитя(мж.сцена);
мж.начали.уведомить();
};

мж.задатьНейтральныйМатериал = function()
{
var мат = муром.материалы.создатьМатериал("N");
var изо = муром.ресурсы.ресурс("tex.stub");
мат.задатьТекстуру("image", изо);
var вер = муром.ресурсы.ресурс("ver").содержимое;
var фра = муром.ресурсы.ресурс("fra").содержимое;
мат.задатьШейдеры(вер, фра);
мж.сцена.задатьМатериал(мат);
};

мж.разобратьРаскладку = function()
{
var содержимое = муром.ресурсы.ресурс("lay").содержимое;
мж.раскладка = new Раскладка();
мж.раскладка.разобрать(содержимое);
};

мж.фишки = [];
мж.создатьФишки = function()
{
for (var номер in мж.раскладка.позиции)
{
var ф = new Фишка();
ф.позиция = мж.раскладка.позиции[номер];
мж.фишки.push(ф);
}
};

мж.размерФишки = {
"ширина": 2.0,
"высота": 3.0,
"глубина": 1.0,
};
мж.создатьУзлыФишек = function()
{
const шагФишки = 2.0;
const коэффициенты = {
"x": мж.размерФишки.ширина / шагФишки,
"y": -мж.размерФишки.высота / шагФишки,
"z": мж.размерФишки.глубина,
};
var мод = муром.ресурсы.ресурс("mod");
for (var номер in мж.фишки)
{
var имя = номер.toString();
var узел = муром.узлы.создатьУзел(имя, мод);
мж.сцена.добавитьДитя(узел);
var ф = мж.фишки[номер];
var п = ф.позиция;
узел.позиция = [
п[2] * коэффициенты.x,
п[1] * коэффициенты.y,
п[0] * коэффициенты.z,
];
ф.узел = узел;
}
};

мж.центрироватьСцену = function()
{
var границы = {
"лево": 1000,
"право": -1000,
"верх": -1000,
"низ": 1000,
};
for (var номер in мж.фишки)
{
const ф = мж.фишки[номер];
const x = ф.узел.позиция[0];
const y = ф.узел.позиция[1];
if (x < границы.лево)
{
границы.лево = x;
}
if (x > границы.право)
{
границы.право = x;
}
if (y < границы.низ)
{
границы.низ = y;
}
if (y > границы.верх)
{
границы.верх = y;
}
}

const ширина = границы.право - границы.лево + мж.размерФишки.ширина;
const высота = границы.верх - границы.низ + мж.размерФишки.высота;
мж.сцена.позиция = [-ширина / 2.0, 0, высота / 2.0];
};

// http://www.rubl.com/rules/mahjong-solitaire-rules.html
мж.задатьФишкамГруппыПоследовательно = function()
{
var группы = [];
// Генерируем группы.
const группВсего = 42;
const группПо4Дубля = 34;
for (var г = 0; г < группВсего; ++г)
{
const четыреДубля = (г < группПо4Дубля);
const колвоДублей = четыреДубля ? 4 : 1;
for (var д = 0; д < колвоДублей; ++д)
{
группы.push(г);
}
}
// Задаём.
for (var номер in мж.фишки)
{
var ф = мж.фишки[номер];
ф.группа = Number(группы[номер]);
}
};

мж.применитьТемуФишек = function()
{
const R = RR();
// Создать текстуры.
var обозначения = [];
var текстуры = [];
for (var номер in R)
{
var обозначение = R[номер][0];
обозначения.push(обозначение);
var имя = "tile.tex/" + обозначение;
var содержимое = R[номер][1];
var текстура = муром.ресурсы.создатьРесурс(имя, содержимое);
текстуры.push(текстура);
}
// Создать материалы.
var нейтраль = [];
var выбор = [];
var вер = муром.ресурсы.ресурс("ver").содержимое;
var фра = муром.ресурсы.ресурс("fra").содержимое;
// Нейтраль.
for (var номер = 0; номер < 42; ++номер)
{
var имя = "tile.mat/" + обозначения[номер];
var изо = текстуры[номер];
var мат = муром.материалы.создатьМатериал(имя);
мат.задатьТекстуру("image", изо);
мат.задатьШейдеры(вер, фра);
нейтраль.push(мат);
}
// Выбор.
for (var номер = 42; номер < 83; ++номер)
{
var имя = "tile.mat/" + обозначения[номер];
var изо = текстуры[номер];
var мат = муром.материалы.создатьМатериал(имя);
мат.задатьТекстуру("image", изо);
мат.задатьШейдеры(вер, фра);
выбор.push(мат);
}

// Применить тему.
for (var номер in мж.фишки)
{
var ф = мж.фишки[номер];
ф.нейтраль = нейтраль[ф.группа];
ф.выбор = выбор[ф.группа];
ф.показатьНейтраль();
}
};

мж.маскаВыбора = 0x2;
мж.сделатьФишкиВыбираемыми = function()
{
for (var номер in мж.фишки)
{
var ф = мж.фишки[номер];
ф.узел.задатьМаску(мж.маскаВыбора);
}
}

мж.индексПозиции = function(п)
{
return п[0] * 1000000 + п[1] * 1000 + п[2];
};

мж.индексПозиций = {};
мж.проиндексироватьПозиции = function()
{
for (var номер in мж.фишки)
{
var ф = мж.фишки[номер];
var и = мж.индексПозиции(ф.позиция);
мж.индексПозиций[и] = true;
}
};

мж.естьСоседи = function(позиция, смещениеПоля, смещениеСтолбца)
{
for (var смещениеРяда = -1; смещениеРяда <= 1; ++смещениеРяда)
{
var сосед = [
Number(позиция[0]) + смещениеПоля,
Number(позиция[1]) + смещениеРяда,
Number(позиция[2]) + смещениеСтолбца,
];
var и = мж.индексПозиции(сосед);
if (и in мж.индексПозиций)
{
return true;
}
}
// Соседей нет.
return false;
};

мж.можноВыбратьФишку = function(ф)
{
// Проверяем наличие фишек с левой и правой сторон одновременно.
var слева = this.естьСоседи(ф.позиция, 0, -2);
var справа = this.естьСоседи(ф.позиция, 0, 2);
if (слева && справа)
{
return false;
}
// Проверяем наличие фишек непосредственно сверху.
for (var смещение = -1; смещение <= 1; ++смещение)
{
if (this.естьСоседи(ф.позиция, 1, смещение))
{
return false;
}
}
// Фишка не заблокирована.
return true;
};

мж.номерВыбраннойФишки = null;
мж.выбраннаяФишка = null;
мж.выбранаФишка = new Уведомитель();
мж.выбратьФишку = function()
{
// Определить щелчок.
if (муром.мышь.нажатыеКнопки.length == 1)
{
var узел =
муром.камера.узелВПозиции(
муром.мышь.позиция,
мж.маскаВыбора
);
if (узел)
{
var номер = Number(узел.имя);
var ф = мж.фишки[номер];
if (мж.можноВыбратьФишку(ф))
{
мж.номерВыбраннойФишки = номер;
мж.выбраннаяФишка = ф;
мж.выбранаФишка.уведомить();
}
}
}
};

мж.отладитьВыборФишки = function()
{
мж.выбранаФишка.подписать(function(){
console.log(
"Выбор. Номер: '" +
мж.номерВыбраннойФишки +
"' Группа: '" +
мж.выбраннаяФишка.группа +
"'"
);
});
};

мж.показатьВыбраннуюФишку = function()
{
мж.выбраннаяФишка.показатьВыбор();
};

мж.выбранныеФишки = [];
мж.фишкиРазличаются = new Уведомитель();
мж.фишкиСовпадают = new Уведомитель();
мж.фишкиСравнили = new Уведомитель();
мж.сравнитьВыбранныеФишки = function()
{
// Собираем.
мж.выбранныеФишки.push(мж.выбраннаяФишка);
// Удостоверяемся в наличии пары фишек.
if (мж.выбранныеФишки.length != 2)
{
return;
}
var ф1 = мж.выбранныеФишки[0];
var ф2 = мж.выбранныеФишки[1];
// Убираем дубликат при двойном выборе одной фишки.
if (ф1.имя == ф2.имя)
{
мж.выбранныеФишки.shift();
return;
}
// Сравниваем.
if (ф1.группа == ф2.группа)
{
мж.фишкиСовпадают.уведомить();
}
else
{
мж.фишкиРазличаются.уведомить();
}
мж.фишкиСравнили.уведомить();
};

мж.отладитьСравнениеФишек = function()
{
мж.фишкиСовпадают.подписать(function(){
console.log("Фишки совпадают");
});
мж.фишкиРазличаются.подписать(function(){
console.log("Фишки различаются");
});
};

мж.скрытьСовпадающиеФишки = function()
{
мж.выбранныеФишки[0].скрыть();
мж.выбранныеФишки[1].скрыть();
};

мж.убратьСовпадающиеФишки = function()
{
var ф1 = мж.выбранныеФишки[0];
var ф2 = мж.выбранныеФишки[1];
var и1 = мж.индексПозиции(ф1.позиция);
var и2 = мж.индексПозиции(ф2.позиция);
delete мж.индексПозиций[и1];
delete мж.индексПозиций[и2];
};

мж.очиститьОтображениеВыбора = function()
{
мж.выбранныеФишки[0].показатьНейтраль();
мж.выбранныеФишки[1].показатьНейтраль();
};

мж.очиститьВыбор = function()
{
мж.номерВыбраннойФишки = 0;
мж.выбраннаяФишка = null;
мж.выбранныеФишки = [];
};

мж.оставшиесяФишки = [];
мж.задатьОставшиесяФишки = function()
{
мж.оставшиесяФишки = мж.фишки.slice();
};

мж.обновилиОставшиесяФишки = new Уведомитель();
мж.обновитьОставшиесяФишки = function()
{
var и1 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[0]);
мж.оставшиесяФишки.splice(и1, 1);
var и2 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[1]);
мж.оставшиесяФишки.splice(и2, 1);

мж.обновилиОставшиесяФишки.уведомить();
};

мж.доступныеДляВыбораФишки = function()
{
var фишки = [];
for (var номер in мж.оставшиесяФишки)
{
var ф = мж.оставшиесяФишки[номер];
if (мж.можноВыбратьФишку(ф))
{
фишки.push(ф);
}
}
return фишки;
};

мж.естьХод = function()
{
var фишки = мж.доступныеДляВыбораФишки();
for (var н1 in фишки)
{
for (var н2 in фишки)
{
var ф1 = фишки[н1];
var ф2 = фишки[н2];
if (
(ф1.имя != ф2.имя) &&
(ф1.группа == ф2.группа)
) {
return true;
}
}
}
return false;
}

мж.победа = new Уведомитель();
мж.поражение = new Уведомитель();
мж.проверитьЗавершение = function()
{
var кончилисьФишки = (мж.оставшиесяФишки.length == 0);
if (кончилисьФишки)
{
мж.победа.уведомить();
return;
}
if (!мж.естьХод())
{
мж.поражение.уведомить();
}
};

мж.отладитьЗавершение = function()
{
мж.победа.подписать(function(){
console.log("Игра завершена. ПОБЕДА!");
});
мж.поражение.подписать(function(){
console.log("Игра завершена. ПОРАЖЕНИЕ :(");
});
};

мж.задатьОтображениеЗавершения = function()
{
мж.победа.подписать(function(){
муром.камера.цветОчистки = [0.2, 0.5, 0.2];
});
мж.поражение.подписать(function(){
муром.камера.цветОчистки = [0.5, 0.2, 0.2];
});
};

// Игра.

мж.начали.подписатьМного([
мж.задатьНейтральныйМатериал,
мж.разобратьРаскладку,
мж.создатьФишки,
мж.создатьУзлыФишек,
мж.центрироватьСцену,
мж.задатьФишкамГруппыПоследовательно,
мж.применитьТемуФишек,
мж.сделатьФишкиВыбираемыми,
мж.отладитьВыборФишки,
мж.проиндексироватьПозиции,
мж.отладитьСравнениеФишек,
мж.задатьОставшиесяФишки,
мж.отладитьЗавершение,
мж.задатьОтображениеЗавершения,
]);
муром.мышь.нажатыеКнопкиИзменились.подписать(мж.выбратьФишку);
мж.выбранаФишка.подписатьМного([
мж.показатьВыбраннуюФишку,
мж.сравнитьВыбранныеФишки,
]);
мж.фишкиСовпадают.подписатьМного([
мж.убратьСовпадающиеФишки,
мж.обновитьОставшиесяФишки,
function(){
setTimeout(мж.скрытьСовпадающиеФишки, 200);
},
]);
мж.фишкиРазличаются.подписать(function(){
setTimeout(мж.очиститьОтображениеВыбора, 200);
});
мж.фишкиСравнили.подписать(function(){
setTimeout(мж.очиститьВыбор, 200);
});
мж.обновилиОставшиесяФишки.подписать(мж.проверитьЗавершение);
// Начать после загрузки ресурсов.
муром.ресурсы.получить(мж.ресурсы, мж.начать);

Loading…
Cancel
Save