Авторизация
×

Логин (e-mail)

Пароль

Интерактивные истории, текстовые игры и квесты
Гиперкнига

Библиотека    Блог

Посетите наш новый сайт AXMAJS.RU

Пишем интерактивную историю вместе. Часть 20-я

Борис Семёнов (Morych), 04.10.13 | Практика ASM

Загадки и списки

В главе «Игра в игре» мы уже ознакомились с примером применения циклов и методов Javascript в истории. Самое время нам окончательно перейти на третий уровень интерактивности ASM и рассмотреть пример использования списков (массивов). Однако перед этим очень полезно будет почитать про списки в «Руководстве пользователя ASM». А кто руководство прочитал, уже знает, что списки — это такой особый вид объектов, который может хранить не одно значение, а сразу несколько. Причём у каждого значения имеется свой числовой индекс (номер).

Давайте перепрыгнем по сюжету нашей истории к тому моменту, как герой нашёл новый дом, и теперь ему следует о новом своём доме позаботиться. Добавим в историю так называемую загадку, которую нужно будет обязательно решить для достижения успешной концовки.

Пусть в доме будут три сундука, в которых вперемешку содержатся всевозможные предметы. Все эти предметы можно разделить на три типа: вещи главы семейства, посуда и вещи для приданного. При этом каждый сундук подходит для хранения предметов только одного типа. Наш герой сможет извлекать из сундука один верхний предмет и помещать его в любой другой сундук. Загадка будет считаться решённой, если все предметы окажутся в соответствующих сундуках.

Начнём с параграфа «Новый дом», при первом посещении которого нам предстоит наполнить сундуки всевозможным скарбом. При этом для повышения реиграбельности сундуки будут наполняться случайным образом, чтобы каждый раз последовательность перемещения предметов была разная.

Новый дом

<<display 'Новая сцена'>>
<<set $сцена = "Новый дом">>
<<display 'Заголовок'>>
<<if $новый_дом eq 1>>
    <<set $сундук_1 = []>>
    <<set $сундук_2 = []>>
    <<set $сундук_3 = []>>
    <<set $скарб = ["1 рыболовную сеть", "1 железный топор", "1 железную пилу", "1 точильный камень", "1 кресало", "2 бронзовый котелок", "2 деревянную ложку", "2 глиняный кувшин", "2 деревянную миску", "2 глиняную кружку", "3 красную рубаху", "3 отрез белёного льна", "3 моток узорной тесьмы", "3 тканый пояс", "3 нарядный сарафан"]>>
    <<loop 4>>
        <<set $сундук = 1>>
        <<loop 3>>
            <<set $номер = Math.round(Math.random() * ($скарб.length - 1))>>
            <<set $текст = $скарб.splice($номер, 1) + "">>        
            <<if $сундук eq 1>>
                <<set $сундук_1.push($текст)>>
            <<elseif $сундук eq 2>>
                <<set $сундук_2.push($текст)>>
            <<else>>
                <<set $сундук_3.push($текст)>>
            <<endif>>
            <<set $сундук++>>
        <<endloop>>
    <<endloop>>
    <<set $новый_дом = 2>>
<<endif>>
Мой новый дом.
<<if ($сундук_1.join(",").indexOf("2") gt -1) or ($сундук_1.join(",").indexOf("3") gt -1) or ($сундук_2.join(",").indexOf("1") gt -1) or ($сундук_2.join(",").indexOf("3") gt -1) or ($сундук_3.join(",").indexOf("1") gt -1) or ($сундук_3.join(",").indexOf("2") gt -1)>>
    <<set $добро_разложено = false>>
    Едва окинув взглядом сундуки со скарбом, я понял, что-то в них не так. И, вроде бы, сундуки, как сундуки, даже хорошие, вместительные и прочные сундуки, но неприятное чувство не давало покоя.
<<else>>
    <<set $добро_разложено = true>>
    При взгляде на сундуки со скарбом глаз радовался -- всё добро там содержалось на своих местах, как добру и положено.
<<endif>>
----
[[''Проверить сундуки''|Сундуки {$сундук = -1} {$действие = 0}]]

Для каждого сундука мы создаём свой объект-список: «$сундук_1», «$сундук_2» и «$сундук_3». Квадратные скобки в макросах «set» пустые. Это значит, что первоначально эти списки не будут содержать значений. А вот список «$скарб», напротив, содержит наименования всех возможных предметов. Чтобы история сама знала, к какому типу относится каждый предмет, мы поставили перед названиями номера типов.

Наполнять сундуки будем в двух вложенных циклах. В каждый из трёх сундуков положим по четыре предмета вытянутых из списка «$скарб» случайным образом. У каждого списка есть свойство «length», которое содержит количество элементов списка. Первый элемент имеет индекс «0», последний — «length - 1». Значит, нам нужно получить случайное число в этих границах. Занесём этот случайный индекс в объект «$номер»:

<<set $номер = Math.round(Math.random() * ($скарб.length - 1))>>

Теперь извлечём из списка элемент с выбранным индексом. Для этого воспользуемся методом списка «splice», которому в качестве аргументов в скобках нужно передать первый индекс и количество элементов для извлечения. Мы извлекаем один элемент и помещаем его в объект «$текст»:

<<set $текст = $скарб.splice($номер, 1) + "">>

Извлекаемый элемент исчезает из списка, а длина списка уменьшается на 1. При этом все индексы, которые следуют за индексом «$номер», также уменьшатся на 1. И если в первый раз мы выбирали случайный индекс от 0 до 14, то на следующем шаге цикла будем выбирать индекс уже от 0 до 13. Таким образом, в сундуках не будет повторяющихся предметов.

Обратите внимание, что мы добавляем к объекту «$текст» ещё и две кавычки, которые представляют собой пустую строку. Дело в том, что метод «splice» возвращает список извлечённых элементов, пусть и состоящий всего из одной строки. И хотя строка и список из одной строки очень похожи, но методы Javascript у них абсолютно разные. Добавляя две кавычки, мы выполняем преобразование объекта «$текст» к строковому типу. С тем же успехом, кстати, мы могли бы воспользоваться методом списка «join». Итак, строка, содержащая название предмета, у нас есть, можно добавить её в список сундука:

<<set $сундук_1.push($текст)>>

Объект «$сундук» содержит номер сундука, в который мы добавляем очередной предмет. Каждый раз перед началом внутреннего цикла («loop 3») устанавливаем значение объекта «$сундук» в 1. После отработки циклов во всех списках сундуков будет содержаться по четыре строки с названиями предметов.

Нам осталось разобраться с этим длинным и страшным на первый взгляд условием в макросе «if». Это условие как раз и проверяет, разложены ли все предметы по своим сундукам. Если присмотреться, можно заметить, что условие состоит из аналогичных частей:

$сундук_1.join(",").indexOf("2") gt -1

Изменяются только номера сундуков и цифры в кавычках. Метод «join» собирает из списка строку, в которой названия предметов будут разделены запятыми. Затем в полученной строке при помощи метода «indexOf» мы ищем символ «2». Если этот символ будет найден, «indexOf» вернёт его индекс. В противном случае будет возвращено значение «-1».

Таким образом, мы проверяем, содержатся ли в первом сундуке предметы, в названиях которых присутствует цифра 2 (то есть предметы второго типа). Следующая часть условия проверяет наличие в первом сундуке предметов третьего типа. Затем нужно проверить второй сундук на присутствие предметов первого и третьего типов, и третий сундук на наличие предметов первого и второго типов. Поскольку все части условия связаны через «or», условие сработает, если хотя бы одна его часть окажется истинной. В этом случае устанавливаем значение объекта «$добро_разложено» в «false» и показываем соответствующее описание.

При наполнении сундуков теоретически может случиться ситуация, когда все предметы сразу окажутся в правильных сундуках. Однако вероятность этого, как известно, крайне мала, поэтому не будем учитывать в программе этот случай. Посчитаем просто, что игроку несказанно повезло. :)

Продолжение следует...

Комментарии: 1.

Профиль


Закрыть
Morych
05.09.18 17:29

Тут мне подсказали, что если скопировать приведённый код как есть, то работать ничего не будет (ну или будет, но не так, как ожидалось) :)

Чтобы всё починить:

1) удалите из приведенного кода первую строку (<<display 'Новая сцена'>>)

2) перед переходом в параграф "новый дом", объявите объект <<set $новый_дом = 1>> (в параграфе "Start" или в "создание объектов" — если делаете всё по учебнику)

Для того, чтобы оставлять комментарии, необходимо зарегистрироваться и подтвердить в профиле указанный e-mail адрес.

При использовании любых материалов блога обязательно указание ссылки на источник