NetHack - это игра в стиле roguelike, в которой игрок должен получить Амулет Йендора с самого низкого уровня подземелья. Обычно играется через telnet, вся игра представлена графикой ASCII. Игра чрезвычайно сложна и требует знаний многих игровых механизмов, чтобы добиться успеха.
В целях этого задания предположим, что все подземелье представляет собой один уровень и всего 5 × 16 символов. Кроме того, предположим, что это «безопасное» подземелье или что вы реализуете только прототип - здесь не будет монстров, опасений по поводу голода и т. Д. На самом деле вы должны отслеживать только местоположение персонажа, амулет и игру. эффективно закончится, когда игрок прибудет в то же место, что и амулет.
Требования к вызову
- Там будет подземелье 5 × 16 (один уровень).
- Дайте игроку начальную позицию (необязательно случайную) и амулет в виде отдельной случайной (отличающейся при каждом запуске программы) стартовой клетки внутри подземелья. То есть амулет не может начинаться на том же поле, что и игрок.
- Примите четыре клавиши ввода, которые перемещают игрока на одну клетку за раз (четыре основных направления). Разрешено чтение / обработка другого ввода (функция readline (), которая требует нажатия «enter» и т. Д.).
- Путешествие за пределы подземелья запрещено. Например, если игрок находится на правом краю подземелья, нажатие вправо ничего не должно делать.
- После первоначальной генерации и после каждого движения выведите состояние игры. Поскольку это код игры в гольф, а печать довольно неинтересна, игнорируйте количество символов для функции печати и вызова функции, не предполагая изменений состояния . Пустые ячейки должны быть показаны в виде period (
.
), амулет в виде двойной кавычки ("
) и символ как в символе (@
). - Игра заканчивается, когда игрок «обнаруживает» амулет (прибывает на ту же площадь)
выигрыш
Это кодовый гольф-код, самый короткий код, удовлетворяющий требованиям, который через неделю с сегодняшнего дня будет объявлен победителем.
пример
Вот пример решения в C # (ungolfed), чтобы показать основные требования и пример вывода.
using System;
namespace nh
{
class Program
{
static Random random = new Random();
// player x/y, amulet x/y
static int px, py, ax, ay;
static void Main(string[] args)
{
px = random.Next(0, 16);
py = random.Next(0, 5);
// amulet starts on a position different from the player
do { ax = random.Next(0, 16); } while (px == ax);
do { ay = random.Next(0, 5); } while (py == ay);
print();
do
{
// reads a single keypress (no need to press enter)
// result is cast to int to compare with character literals
var m = (int)Console.ReadKey(true).Key;
// Move the player. Here standard WASD keys are used.
// Boundary checks for edge of dungeon as well.
if (m == 'W')
py = (py > 0) ? py - 1 : py;
if (m == 'S')
py = (py < 5) ? py + 1 : py;
if (m == 'A')
px = (px > 0) ? px - 1 : px;
if (m == 'D')
px = (px < 16) ? px + 1 : px;
// print state after each keypress. If the player doesn't
// move this is redundant but oh well.
print();
// game ends when player is on same square as amulet
} while (px != ax || py != ay);
}
static void print()
{
Console.Write('\n');
for (int y=0; y<5; y++)
{
for (int x = 0; x < 16; x++)
{
if (x == px && y == py)
Console.Write('@');
else if (x == ax && y == ay)
Console.Write('"');
else
Console.Write('.');
}
Console.Write('\n');
}
}
}
}
Общее количество символов составляет 1474, но без учета вызовов функции print и ее определения окончательное количество символов равно 896
.
Вывод при запуске программы:
................
...."...........
..........@.....
................
................
Вывод (включая выше) после двойного нажатия клавиши «а»:
................
...."...........
..........@.....
................
................
................
...."...........
.........@......
................
................
................
...."...........
........@.......
................
................
Ответы:
TI-BASIC,
4241383635 байтДля вашего графического калькулятора серии TI-83 или 84+.
В каком направлении будет двигаться игрок, зависит от кода клавиши нажатой клавиши, но в верхнем ряду однозначно работают четыре клавиши:
Амулет начинается с одного из пяти квадратов в первом столбце, а игрок начинается с нижнего правого квадрата. Например, возможное расположение:
объяснение
Позиция игрока сохраняется как комплексное число от
0+0i
до15+4i
, где действительная часть идет вправо, а мнимая часть понижается. Это облегчает легкую проверку границ сверху и слева: мы просто слегка смещаем число и округляем до нуля. Например, если смещение равно0.5
и наша позиция-1+3i
(за пределами экрана влево), то позиция будет скорректирована до того местаiPart(-0.5+3.5i)=0+3i
, где она должна быть. Проверка на нижнюю и правую границы немного сложнее; нам нужно вычесть число из константыC
, которая составляет около15.635 + 4.093i
(это самое короткое число, которое я мог найти между15+4i
и16+5i
), округлить, вычесть изC
снова, чтобы перевернуть число назад, и снова округлить.Когда нажата клавиша, позиция нескорректированного игрока будет перемещаться на 1 единицу в некотором направлении, но целочисленная часть изменяется только при нажатии определенных клавиш. К счастью, все ключи работают в верхнем ряду. Ниже приведен график смещений в тех случаях, когда клавиши 11, 12, 13 и 15 нажаты, и когда ни одна клавиша не нажата (Нет нажатия - это точка внутри центрального квадрата, в результате чего целочисленные части остаются неизменными; четыре нажатия клавиш смещения имеют разные целочисленные части).
C
это красный крест в центре круга.Старый код (42 байта):
Ограничения
Нет возможности экранировать
"
символ, поэтому строки с"
не могут быть сгенерированы внутри программы. Поэтому¨
вместо кавычки используется знак умляута (если бы уже существовала строка с кавычкой, я мог бы это отобразить). Чтобы попасть¨
и@
в программу, нужен внешний инструмент; однако, это действительно TI-BASIC.источник
ЧИП-8 , 48 байт
Это не может считаться законным, но, черт возьми, нет. Я написал свою программу на CHIP-8, языке программирования на основе байт-кода для виртуальной игровой консоли. Вы можете попробовать полную программу (99 байт) в своем браузере, используя эмулятор / отладчик, который я написал под названием Octo:
http://johnearnest.github.io/Octo/index.html?gist=1318903acdc1dd266469
Шестнадцатеричный дамп этой полной программы выглядит следующим образом:
Вы можете перемещать плеер с помощью клавиш ASWD или клавиш 7589 на оригинальной клавиатуре CHIP-8. Если я удаляю весь код и данные для рисования фона и проигрывателя, я вместо этого получаю этот 48-байтовый дамп:
Неполная, полная форма программы была написана на языке ассемблера высокого уровня следующим образом:
Обратите внимание , что скомпилированный байт сами являются язык программирования ЧИП-8; ассемблер - просто более удобный способ составления таких программ.
источник
Python 3, 86 байт
Только считая две нижние строки и сбрасывая
d();
.источник
a=id(9)%79
наa=id(9)%p
.raw_input
вызов на justinput
.C
122121115104102101 байтПервое размещение здесь! Я надеюсь, вам понравится :)
o
это печать, эм, функция. Наш храбрый герой может перемещаться с 2, 4, 6 и 8, но остерегайтесь не посылать никаких других входных данных (никаких новых строк!).Update 1: принес
a
иi
вmain
«параметры с.Обновление 2: OP подтвердил, что с одной строкой ввода все в порядке, я избавился
scanf
(от которой я пропустил перевод строки).Обновление 3: Использовал литерал составного массива и изменил формат ввода. Программа теперь выходит из строя, если вы введете неверное направление;)
Обновление 4: заметил, что вызов функции печати не считается. Взял на заметку, чтобы прочитать правила более внимательно.
Обновление 5: один байт сохранен, благодаря Миккель Алан Стоккебье Кристиа.
источник
!!(p%16)
бытьp%16>0
? Я не помню свой порядок операций.-
не может удержатьсяp
, поэтому скобки нужны в любом случае. Двойной взрыв - просто запутывание :)CJam,
464544403937 байтПервая строка (определяет функцию, которая печатает текущее состояние игры), а P во второй строке (вызов этой функции) не влияют на количество байтов.
И начальная позиция, и позиция амулета выбираются псевдослучайно. Распределение является столь же равномерным, и основной PRNG позволяет.
Ввод является E, 6, 9и Bдля Up , вниз , влево и вправо , с Caps Lockактивировано, а затем Enter.
Альтернативная версия
За счет еще четырех байтов формат ввода значительно улучшен:
тестирование
Поскольку ввод-вывод является интерактивным, вы должны попробовать этот код с интерпретатором Java .
Загрузите последнюю версию и запустите программу следующим образом:
Чтобы избежать нажатия Enterпосле каждой клавиши и для обновления вывода на месте, вы можете использовать эту оболочку:
Вызвать как это:
Основная версия
Альтернативная версия
Функция P
источник
Java, 231 байт (196, если функция)
Вот полный код программы на 342:
Без функции печати 231:
Если с функцией все в порядке (мне не ясно из спецификации), то я могу еще немного сократить ее до 196:
И с некоторыми переносами строк для большей ясности ...
Обратите внимание , что я не считать функцию печати
p(p,y)
себя, но я я рассчитываю на вызов к нему, так как у меня есть вещи , изменяющиеся в операторе вызова.Работает с заглавными буквами
ASDW
. Из-за того, как он проверяет их, могут работать и другие буквы, но в спецификации ничего не сказано о том, что должно произойти, если я нажму другие клавиши.источник
void m()
становится()->
p+=
?Java, 574 байта
В основном так же, как версия C #, за исключением запутанного и свернутого.
источник
Юлия, 161 байт
Пользы w, a, sи dдвигаться вверх, влево, вниз и вправо, соответственно.
Полный код, включая печать (330 байт):
Забитый код, исключая печать (161 байт):
Разница здесь в том, что мы не сохраняем состояние игры в виде матрицы; вся соответствующая информация содержится в массивах
c
иa
. И, конечно же, ничего не печатается. Пользователь больше не будет запрашивать ввод, как только игрок достигает амулета.Ungolfed + объяснение (полный код):
источник
a=[rand(1:5),1] c=a+1
Пакет, 329 байт
источник
Microsoft Windows [Version 6.1.7601]
Microsoft Windows [Version 6.2.9200]
)Perl,
228222 символа (не считая перевода строки, которые не являются неотъемлемой частью работы кода) - 207, если не считатьprint
иprint if
операторы, которые используются для печати, но не добавляют логику игры; 144, если учесть также код генерации представления поля как часть печати, как предложил Якк в комментариях)Этот код использует нижний регистр для управления; ввод должен быть подтвержден нажатием Enter. Протестировано с Perl 5.14.2.
Обратите внимание, что для этого кода невозможно разделить вычисления и печать, поскольку операции выполняются непосредственно в печатном представлении с использованием регулярных выражений.
Объяснение:
Эта линия определяет положение игрока и амулета. Позиция игрока определяется
$==rand(80)
и на самом деле проста для понимания: на доске 5 × 16 есть 80 различных позиций, где игрок может находиться. Позиция сохраняется в$=
переменной, которая переводит сохраненное значение в целое число; это экономит несколько байтов, так как нет необходимости явно приводить результат к целому числу (rand
предоставляет значение с плавающей запятой).Поскольку одна из позиций уже занята игроком, для амулета остается только 79 позиций, поэтому для позиции амулета
$a=$==rand(79)
используется. Опять же, присвоение$=
заставляет преобразование в целое число, однако я дополнительно назначаю его$a
для повторного использования.$=
для позиции игрока.Теперь, чтобы амулет не занимал ту же позицию, что и игрок, он продвигается на одну позицию, если его позиция, по крайней мере, такая же, как позиция игрока, обеспечивая равномерное распределение по местам, не занятым игроком. Это достигается ,
$a = ($a >= $=)
когда$=
здесь имеет место игрока. Теперь первая строка генерируется путем вставки двух начальных присваиваний вместо первого$a$ and the only
$ = `в этом выражении.Это создает начальное поле, а затем печатает.
("."x80)
просто генерирует строку из 80 точек.=~s/(.{$=})./\1@/r
затем заменяет$=
й символ с@
, а=~s/(.{$=})./\1@/r
в$a
й символ с"
. Благодаряr
модификатору они не пытаются изменить на месте, а возвращают измененную строку, поэтому их можно применять к предыдущим выражениям. Наконец,=~s/(.{16})/\1\n/gr
вставляет новую строку каждые 16 символов. Обратите внимание, что поле хранится в специальной переменной,$_
которая может быть неявно использована в последующих инструкциях.Это создает хеш, содержащий правила замены для разных ходов. Более читаемая версия этого
Ключи - это символы для ходов, а значения - строки, содержащие соответствующее правило замены.
Это основной цикл.
while(/"/)
проверяет, есть ли еще"
символ в$_
(то есть в поле). Если мы переместимся на амулет, его персонаж заменяется персонажем игрока, поэтому он исчезает с поля.eval $r{getc STDIN}
читает символ из стандартного ввода, ищет соответствующее правило замены из has%r
и применяет его к$_
, то есть к полю. Это дает значение true, если замена была фактически сделана (то есть ключ был найден в хэше, и перемещение было возможным; невозможное движение не будет совпадать в правиле замены). В таком случаеprint
выполняется. Поскольку он вызывается без аргумента, он печатает$_
измененное поле.источник
("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/gr
первый взгляд @celtschk довольно близок, но мое перл-фу несколько лет заржавело. Я мог пропустить изменение состояния там.C #,
256 248 234 227 226225 байтДля перемещения используются стрелки NumPad с включенным NumLock.
Отступы и комментарии для ясности:
источник
Main
метод не должен вызыватьсяMain
, так что вы можете сбрить еще три символа.HTML + JavaScript (ES6), оценка может быть 217
Слишком длинная, но играбельная онлайн в фрагментах ниже.
Строка 6 (T.value ...) предназначена для вывода и не учитывается (но для простоты я посчитал теги открытия и закрытия текстовой области, даже если они тоже выводятся)
Что касается случайности: амулет всегда находится в правой половине сетки, а игрок всегда начинает в левой половине.
Нажмите на текстовую область (после ее увеличения), чтобы запустить и перезапустить игру.
EcmaScript 6 Snippet (только Firefox)
Фрагмент EcmaScript 5 (протестирован в Chrome)
источник
ActionScript 3: 267 байт
Рабочий пример онлайн
var a:int,p:int,t;function g(){var r=Math.random;while(p==a){a=r()*80;p=r()*80}addEventListener("keyDown",function(e){if(a==p)return;if(e.keyCode==87&&p>15)p-=16if(e.keyCode==83&&p<64)p+=16if(e.keyCode==65&&p%16>0)p--if(e.keyCode==68&&(p+1)%16>0)p++print()});print()}
Вот полная (с пробелами для удобства чтения) программа, использующая функцию игры:
источник
Javascript:
307216Вы можете поиграть в фрагмент ниже! Цифры слева только для того, чтобы консоль (по крайней мере, chrome) не объединяла строки.
Чтобы запустить код:
Un-golfed:
Изменить 1: Внимательно прочитайте правила и переписайте мой код соответственно
источник
SpecBAS -
428402 (без учета печати,466425 при подсчете)Использует Q / A / O / P для перемещения вверх / вниз / влево / вправо соответственно.
Линия для печати подземелья в строке 1 является единственной линией, которую можно игнорировать, но это тоже немного сбило с толку.
Ссылка на # 34 является всего лишь кратким способом введения CHR $ (34) в код.
Спасибо @Thomas Kwa, я не заметил, что начальная позиция игрока была случайной. Также используются отдельные операторы IF, чтобы сбрить несколько символов.
источник
2 LET px=1: LET py=1: LET ax=2: LET ay=INT(RND*5)
а также с помощьюIF instead of ELSE IF
.Другой C #,
221171170Вот еще один способ в C # с обеими случайными позициями. Хотел показать это, даже если эта часть на 7 байт длиннее, чем решение Hand-E-Food.
Ответ Hand-E-Food, конечно, будет короче, как только он будет использовать Console.Read ().
Недостатком Consol.Read является то, что нажатие требуемой клавиши Enter приводит к тому, что поле будет напечатано еще 2 раза.
Но я не думаю, что есть требование печатать только на (реальном) вводе.
Навигация осуществляется 8426 как в решении Hand-E-Foods.
Редактировать: (добавило новое решение и переместил PrinterClass в конец)
Edit2: (изменил 14 на 15 и сохранил байт, начиная с правого нижнего
края ). Приспосабливая технику Mauris, можно уменьшить его до 171 байта в C # (конечно сейчас без обеих случайных позиций):
Класс принтера почти такой же, просто новая перегрузка печати ...
источник
Рубин, 185
Вот пример Ruby.
Я очень новичок в Ruby, может быть, кто-то знает, как это сделать лучше :)
Я посчитал lineFeeds как 1, так как в противном случае программа потерпит крах ...
Навигация осуществляется по 8462. Вам нужно каждый раз отправлять ввод с помощью ввода.
источник
QBasic, 103 байта
Согласно правилам вызова,
Show
подпрограмма не включена ни в число байтов, ни вShow p, q, a, b
вызов (со следующей новой строкой).Для перемещения введите число и нажмите Enter:
1
чтобы перейти влево,2
подняться вверх,3
чтобы перейти вправо, и4
спуститься вниз.Этот код не выводит состояние игры в конце, когда игрок нашел амулет. Чтобы сделать это, добавьте еще один
Show p, q, a, b
послеIF
оператора.объяснение
Позвольте
a
,b
представить координаты амулета иp
,q
координаты игрока. Игрок начинает игру с (0, 0), а амулет начинается со строки 0 со столбцом от 1 до 9 включительно, основываясь на цифре 1 текущего времени.Остальное - просто математика с условными обозначениями. Важно помнить, что условные выражения в QBasic возвращают значение
0
false, значение-1
true. Давайте посмотрим на оператор обновления строки игрока:Если
m=2
мы хотим двигаться вверх, вычитая 1 изp
, покаp>0
. Точно так же, еслиm=4
мы хотим перейти вниз, добавив 1 кp
, покаp<4
. Мы можем получить желаемое поведение путем умножения. Если оба фактора есть-1
, их продукт будет1
, который мы можем вычесть или добавитьp
. Если0
какое- либо условие есть , продукт будет0
, без эффекта.Аналогично, условие для определения, нашел ли игрок амулет:
Если какое-либо из условий является истинным, их сумма будет отлична от нуля (или,
-1
или-2
) и, следовательно, верна, и программа вернется к строке 1. Как толькоp
равныa
иq
равныb
, оба условия будут0
, поэтому их сумма будет,0
и поток управления может достичь конец программы.источник