Files
K/игра/001.мир.js

191 lines
5.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*
* Реализация шаблона "издатель-подписчик"
*
*/
function Уведомитель()
{
function Подписка(id, отклик, уведомитель)
{
this.id = id;
this.отклик = отклик;
this.уведомитель = уведомитель;
};
this.уведомить = function()
{
// Попутно собираем подписки без отклика.
var безотклика = [];
for (var номер in this.подписки)
{
var подписка = this.подписки[номер];
if (подписка.отклик)
{
подписка.отклик();
}
else
{
безотклика.push(подписка);
}
}
// И удаляем их.
if (безотклика.length)
{
this._удалитьПодпискиБезОтклика(безотклика);
}
};
this.подписать = function(отклик)
{
var id = this._сгенерироватьUUID();
var подписка = new Подписка(id, отклик, this);
this.подписки.push(подписка);
return подписка;
};
this.отписать = function(подписка)
{
подписка.отклик = null;
};
this._удалитьПодпискиБезОтклика = function(удалить)
{
var подписка = удалить.shift()
while (подписка)
{
var индекс = this.подписки.indexOf(подписка);
if (индекс !== -1)
{
this.подписки.splice(индекс, 1);
}
var подписка = удалить.shift()
}
};
this._сгенерироватьUUID = function()
{
// https://stackoverflow.com/a/2117523
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
/[xy]/g,
function(c)
{
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
}
);
};
// Конструктор.
this.подписки = [];
}
/*
*
* Связь событий и реакций в виде последовательности (череды)
*
*/
function Мир()
{
// Разобрать события и реакции, выраженные в тексте.
this.разобрать = function(череда)
{
var соответствия = this._событияРеакции(череда);
for (var событие in соответствия)
{
if (!(событие in this.события))
{
this.события[событие] = new Уведомитель();
}
var реакции = соответствия[событие];
for (var номер in реакции)
{
const реакция = реакции[номер];
const название = this._имяФункцииИзРеакции(реакция);
const функция = eval(название);
var тут = this;
this.события[событие].подписать(function(){
функция(тут);
});
}
}
};
// Уведомить о событии при его наличии.
this.уведомить = function(событие)
{
if (событие in this.события)
{
this.события[событие].уведомить();
}
};
// Разобрать текст с событиями и реакциями, вернуть словарь их соответствия.
this._событияРеакции = function(текст)
{
var соответствие = {};
var элементы = текст.split("\n");
var имяСобытия = null;
for (var номер in элементы)
{
var элемент = элементы[номер];
// Пропускаем комментарии.
if (элемент.charAt(0) == "#")
{
continue;
}
var имя = элемент.trim();
// Пропускаем пустые строки.
if (!имя.length)
{
continue;
}
// Событие.
if (имя == элемент)
{
if (!(имя in соответствие))
{
имяСобытия = имя;
соответствие[имя] = [];
}
}
// Реакция.
else
{
соответствие[имяСобытия].push(имя);
}
}
return соответствие;
};
// Преобразовать имя реакции в название функции.
this._имяФункцииИзРеакции = function(реакция)
{
var имя = "";
var части = реакция.split(" ");
for (var номер in части)
{
var часть = части[номер];
имя += часть.charAt(0).toUpperCase() + часть.slice(1);
}
return имя;
};
// Конструктор.
this.события = {};
}
/*
*
* Создание глобального мира.
*
*/
мир = new Мир();