Проблема в том, что многие языки (часто недолговечные) являются экспериментальными с очень нетипичными парадигмами, для которых типичные выражения программирования вообще не имеют никакого смысла. Так что «большинство всех языков» практически невозможно выполнить. Вы должны ограничить это каким-то образом, например, «большинством языков, регулярно используемых на codegolf.SE». На данный момент ответы выглядят очень похоже на «большинство языков, производных от C», но те, хотя в них написано подавляющее большинство всего написанного кода , не являются большинством языков .
перестал поворачивать против часовой стрелки
3
осталось около, я думаю, мы все знаем, что они примерно имеют в виду. Это в основном независимые от языка оптимизации, то есть те, которые полезны не только в Brainfuck, но, возможно, в Python, C, Java и Fortran одновременно. Общие идеи, которые вы можете применить на многих языках, которые работают аналогично. Я не думаю, что нужно быть настолько точным и конкретным в подсказках и CW-вопросе. Речь идет о помощи другим в гольфе, а не о том, чтобы разозлить их.
Джои
14
Надеюсь, никто не создаст язык под названием <all languages>...
mbomb007
Ответы:
72
Объединить петли
Обычно вы можете объединить два последовательных цикла или два вложенных цикла в один.
До:
for (i=0; i<a; i++) foo();
for (i=0; i<b; i++) bar();
петли угорен все равно не одинаковые. @ Гаффи прав.
Каод
5
@kaoD, в обоих случаях fooназывается aвременем, barназывается bвременем. Это связано с тем, что в «после» цикл выполняется a+bраз, первый aвызов foo, следующий вызов bar.
Угорен
Я смотрю на это снова (намного, намного позже), и я не понимаю свой собственный вопрос сейчас. Может я раньше не понимал троичную операцию? То, как я это вижу сейчас, имеет смысл.
Гаффи
1
Woops, я прочитал это очень поздно ночью. Вы правы!
Каод
3
Очень похоже: for(y=0;y<Y;++y)for(x=0;x<X;++x)часто становятся for(i=0;i<X*Y;++i)с xзаменены i%Xи yзаменены i/X.
Линн
62
Просто упомянуть очевидное:
Задайте вопрос о выборе алгоритма и попробуйте что-то совершенно новое.
Когда вы играете в гольф (особенно сложные проблемы, которые приводят к более длительным программам) слишком часто, вы можете придерживаться выбранного вами пути, не пытаясь использовать другие фундаментальные варианты. Конечно, вы можете играть в микро-гольф по одной или нескольким линиям за раз или как часть общей идеи, но часто не пытайтесь использовать совершенно другое решение.
Это было особенно заметно в Удар 495 (Капрекар), где отклонение от фактического алгоритма и поиск шаблонов, которые вы можете применить, чтобы получить тот же результат, были короче во многих языках (только не в J).
Недостатком является то, что вы, возможно, решаете одно и то же полдюжины раз. Но он работает практически на всех языках, кроме HQ9 + (где найти другой способ вывода Hello World было бы немного бесполезно).
+1 В дополнение к хорошему для игры в гольф, это хорошее упражнение для любого программиста во многих реальных ситуациях!
Гаффи
52
Используйте тестовую разработку
Если код должен обрабатывать различные входные данные, тогда напишите комплексные тесты и упростите их выполнение очень быстро. Это позволяет попробовать рискованные трансформации по одному детскому шагу за раз. Тогда игра в гольф становится рефакторингом с извращенным намерением.
Я использую дополнительный доход этого метода. Поскольку сами проблемы обычно довольно просты, я пишу программу, которая делает эту работу. Обычно это «легко читаемый», так что он лаконичен, но есть новые строки и т. Д. Я копирую этот файл в новое место и проверяю его, время от времени проверяя, чтобы программы возвращали одни и те же значения для некоторых выбранных входных данных. Если я когда-либо совершу ошибку, оставив меня с испорченной программой, без памяти о том, что я изменил, и без понимания моей игры в гольф, у меня будет что-то вроде «спецификации», сохраненной в качестве справочного источника.
Шион
2
Мне нравится этот метод, и это одна из причин, по которой я стараюсь включать комплексные тестовые наборы для всех задач, которые я пишу.
Джои
@RubberDuck Принцип " Не повторяйся" часто строго соблюдается.
Джонатан Фрех
48
Попробуйте уменьшить логические высказывания
Например, если Aи Bявляются булевыми и вашим язык обрабатывает булевы как числа в некоторой степень, A and (not B)и A>Bэквивалентны. Например в Python
B>A or foo()было бы еще более коротким способом выразить это, воспользовавшись ленивой оценкой булевых выражений, чтобы гарантировать, что он вычисляет вещи только тогда, когда это необходимо.
scragar
5
@scragar: Правильно, но суть не в этом. (Это ценный независимый совет.)
Wrzlprmft
3
@scragar, B>A or fooоценил fooбы, если B==Aэто не то, что мы хотим. (Верно?)
msh210
2
Кроме того, если у вас есть длинные неопределенные условия (скажем, с параметрами 5/6), вы можете использовать таблицу Истины и карту Карно, чтобы найти самое короткое логическое выражение для этого
Katenkyo
33
Инициализируйте переменные, используя значения, которые у вас уже есть.
Вместо этого x=1попробуйте найти что-то, что уже равно 1.
Например, возвращаемое значение функции: printf("..");x=0;-> x=!printf("..");. Проще всего с 0, потому что вы всегда можете отрицать, или когда все, что вам нужно, это правильное значение истинности (и не волнует, если это 1 или 19).
@ std''OrgnlDave, правда, но этот вопрос о вещах, общих для всех языков.
Угорен
33
Используйте одинарные ~для x+1иx-1
Этот прием применим к языкам, которые имеют унарный побитовый оператор отрицания ~и унарный регулярный оператор отрицания -.
Если ваша программа случайно содержит выражение -x-1, вы можете заменить его, ~xчтобы сохранить байты. Это происходит не слишком часто, но посмотрите, что произойдет, если мы отвергнем ( -) оба выражения: x+1равно -~x! Точно так же, x-1равно ~-x. (Подумайте, в какую сторону указывает тильда: справа есть +, слева есть -.)
Это полезно, потому что во всех языках, о которых я могу думать, эти операторы имеют более высокий приоритет, чем большинство операторов. Это позволяет сэкономить на скобках. Посмотрите, как мы сохраняем четыре байта здесь:
Знайте правила для пробелов на вашем языке. Некоторым знакам препинания или другим символам может не понадобиться окружающий пробел. Рассмотрим эту функцию оболочки Борна :
f () { echo a; echo b; }
В оболочке Bourne ();есть метасимволы, и не нужно окружать их пробелами. Тем не менее, {}слова являются и нуждаются в пробеле, если они не находятся рядом с метасимволами. Мы можем поиграть в гольф на 4 поля рядом с ();, но мы должны оставить расстояние между {и echo.
f(){ echo a;echo b;}
В Common Lisp и PicoLisp , ()есть метасимволы. Рассмотрим этот код, чтобы найти среднее из двух чисел:
(/ (+ a b) 2)
Мы можем сыграть в гольф на 2 места.
(/(+ a b)2)
Некоторые языки имеют странные и тонкие правила для пробелов. Рассмотрим программу Ruby, которая выводит сумму и произведение строки целых чисел.
Каждому &нужно пространство перед собой. В Ruby i=$F.map &:to_iозначает, i=$F.map(&:to_i)где &передается параметр блока. Но, i=$F.map&:to_iозначает, i=$F.map.&(:to_i)где &бинарный оператор.
Эта странность встречается в языках, таких как Perl или Ruby, которые используют неоднозначную пунктуацию. В случае сомнений используйте REPL или напишите короткие программы для проверки правил пробелов.
Почему между "{" и "echo" должен быть пробел, а не между ";" и "эхо"?
Райан
3
Я использовал термины из руководства для OpenBSD sh (1), которое говорит, что «{» является зарезервированным словом и «;» это метасимвол Из-за этого "{эхо" - это одно слово, а "; эхо" - это два слова. Другие руководства могут объяснить это по-другому. Кроме того, оболочка Z zsh имеет другие правила.
Kernigh
28
назначать функции новые имена, если они используются несколько раз
x = SomeLongFunctionName
x(somedata)
x(somemoredata)
etc
У вас есть 52 из них; использовать их все! Не бойтесь пробовать разные подходы и сравнивать длины. Знать язык и специальные ярлыки / доступные функции библиотеки.
Часто $и _могут быть использованы в качестве идентификаторов.
Гриффин
4
@Gaffi: И более чем достаточно для языков, которые допускают идентификаторы Unicode, если только задача не ограничивает вас ASCII или не учитывает байты, а не символы.
Hammar
Если вы подсчитываете байты вместо юникода, то использование расширенного ascii может быть способом сжать еще ~ 120 идентификаторов, если они вам нужны (не то, что для сценария игры в гольф вам нужно в любом случае больше 26)
scragar
2
@является допустимым именем переменной в T-SQL, используйте его вместо @a.
BradC
25
Используйте условный оператор.
Условный оператор
bool ? condition_true : condition_false
является более полезным, характерным, чем заявление IF .
Языки, которые не имеют троичного, могут использовать a&&b||cвместо этого. Чуть дольше, но все же короче, чем if.
Майкл Коль
С другой стороны, некоторые не могут использовать ни одну из этих опций (VBA приходит на ум), но оба они все еще являются хорошими предложениями. :-)
Gaffi
1
Гаффи: VBA имеет Iff, хотя это функция, поэтому при условии оценки всех аргументов.
Джои
Использование тройных в случае утверждения могут также быть очень полезныif(a ? b : c)
Jojodmo
4
@MichaelKohl примечание, которое a&&b||cможет возвращаться, cкогда aистинно, если bложно, небольшой
крайний
24
Напишите объяснение вашего кода
Написание объяснения заставляет вас снова тщательно рассмотреть каждую часть вашего кода и сделать ваши мысли и выбор в написании определенного отрывка явным. При этом вы можете обнаружить, что возможны разные подходы, которые могут сэкономить несколько байтов, или что вы подсознательно сделали предположения, которые не обязательно выполняются.
Звучит как ежу понятно, но если вы будете осторожны, вы сможете «спасти» нескольких персонажей, ничего не делая!
Если вы используете Windows, вы можете вводить \r\nвместо обычного \rили \nкогда вы нажимаете Return, добавляя дополнительный байт на строку! Поверните управляющие символы, чтобы дважды проверить, что вы этого не делаете.
В Notepad ++ вы можете конвертировать все \r\nокончания строк, просто \rперейдя в Edit > EOL Conversion > UNIX/OSX Format.
Также убедитесь, что вы не включаете пробелы в число своих персонажей! Перевод строки в нижней строке вашего кода также несущественен, так что подсчитывать его тоже не нужно.
Я не думаю, что когда-либо видел случай, когда это действительно считалось ...
Джейкоб
4
У меня только что была эта проблема сама (поэтому я и добавляю ее).
Шон Лэтэм
21
Внимательно прочитайте вопрос
Гольф-код - это не только понимание вопроса (что задается, а что нет , даже если это подразумевается в любой другой ситуации), а также создание кода, который (может) удовлетворять только то, что спрашивается.
Любой ввод, кроме того, что явно запрашивается, не должен обрабатываться. Если есть несколько тестовых случаев и нет общих требований, ваш код может работать только в этих случаях. И т.п.
Я думаю, что лучшим заголовком здесь будет «Не обрабатывать необязательные крайние случаи». Фраза «Попытка найти лазейки» напоминает способы избежать выполнения того, что указано в некоторой хитрой реинтерпретации правил, тогда как то, что вы предлагаете, является просто хорошим советом, чтобы не переоценить свое решение.
Джонатан Ван Матре
1
Да, но хитрая реинтерпретация правил также является частью игры в гольф! (0 char решений и т. Д.)
Tobia
8
Это будет / должно быть другой ответ, хотя. Существует принципиальное различие между, например, реализацией решения, которое работает только для целых чисел, потому что OP не требует поддержки float, и ответом, который печатает текст «любое простое число больше 100», потому что «вы не сказали, что это нужно было быть фактическим простым числом ".
Джонатан Ван Матре
Я думаю, что некоторые OP включают «Тестовые случаи, подлежащие изменению; ваш код должен все еще работать после изменения», и действительно меняйте их, если они видят только один ответ, жестко кодирующий тестовые случаи.
Эрик Outgolfer
20
Используйте побитовые операции для проверки чисел между 0 и любыми 2 n -1
Может быть, это немного необычный случай, но иногда он может пригодиться. Он основан на том факте, что все числа, к которым применяется m = 2 n -1, имеют самые правые n битов, равные 1.
Хитрость есть x&~m. Это возвращает истину , когда xэто не от 0 до m(включительно), и ложь в противном случае. Он сохраняет 6 байтов из следующего кратчайшего эквивалентного выражения:, x>=0&&x<=mно, очевидно, работает только тогда, когда mудовлетворяет 2 n -1.
Например, в C вашей главной функции всегда передается количество аргументов, переданных в программу (по умолчанию это 1 - имя программы), поэтому main(i){...теперь у вас есть переменная со значением 1 без необходимости делать какие-либо задания. 2 символа сохранены там ..
Гриффин
6
Я думаю, что это довольно специфично для C. Языки сценариев не нуждаются в объявлениях, и в большинстве компилируемых языков определение переменной не дольше, чем определение параметра.
Угорен
в Java, когда нужен массив внутри функции, которая имеет тот же тип, что и один параметр, вы можете сэкономить несколько байтов, поместив этот параметр в качестве последнего и сделав его параметром vararg; (использовал это, чтобы сбрить несколько байтов в функции, чтобы найти самое длинное слово в предложении)
Я не уверен, что понимаю смысл этого. От чего это уменьшается?
Gaffi
@Gaffi вы сохраняете один символ, и они делают то же самое
ajax333221
против какой альтернативы? Извините, не пытаюсь быть упрямым, я просто не понимаю. (newb, здесь, по-видимому ...)
Gaffi
1
Ах я вижу. Работает на любом целочисленном переходе с 9 на 10, на 99 на 100 и т. Д. Извините, что так долго меня занимал! (Я говорю только целое число, потому что я вижу проблему с n = 9,5 ...)
Gaffi
8
Также на некоторых языках (если поддерживается), если ваши числа большие / достаточно малые, научная запись может на самом деле сэкономить вам несколько символов: if(n>99999)vsif(n<1e5)
scragar
16
Используйте> и <вместо> = и <=
При сравнении с жестко запрограммированными целочисленными значениями используйте >и <вместо >=и <=где это возможно. Например, используя
Связанный: Если вы уверены, что результат не может быть отрицательным, вы можете использовать <1вместо ==0нулевой проверки (или >0вместо !=0зеркальной проверки).
Кевин Круйссен
1
Вы не должны добавить примечание о том, xчтобы быть целым числом?
Захари
15
Избегайте преждевременных разрывов петли
Если при выполнении цикла выполняется проверка на наличие одного или нескольких экземпляров логической проверки, это может привести к тому, что более эффективная программа выйдет из цикла с первым истинным значением. Однако удаление разрыва и циклического прохождения всех итераций позволяет сократить код.
int main() {
bool m = false;
int n = 1000;
for (int i = 0; i < n; i++) {
if (i >= 100) {
m = true;
break; // remove this line
}
}
return 0;
}
Кроме того, можно упростить ifзаявление прочь в этих случаях: m|=i>=100. (И в этом случае вы также можете упростить i>=100to, i>99но здесь это не очень актуально)
marinus
15
использовать -вместо!=
для числовых сравнений:
Если a равно b, это a-bприводит к 0ошибочности. Все, кроме 0правды; поэтому,
если используется в логическом контексте, a-b<=>a!=b
Если вы используете его с if/elseили с троичным оператором, это также может сэкономить вам один байт для равенства: a==b?c:d<=>a-b?d:c
В большинстве языков есть способ разбить строку на массив строк вокруг какого-либо токена. Это неизбежно будет короче литерала массива, когда длина достигнет порогового значения, зависящего от языка, поскольку дополнительные издержки на строку будут представлять собой одну копию токена с одним символом, а не (как минимум) двух разделителей строк.
Например, в GolfScript
["Foo""Bar""Baz""Quux"] # 23 chars
становится
"Foo
Bar
Baz
Quux"n/ # 20 chars
Для некоторых языков порог составляет всего одну строку. Например, на Яве,
Заметным исключением является рубин, который обеспечивает массив из-строки литералов , которые автоматически разбивается на пространствах за счет двух байт: %w{Foo Bar Baz Quux}.
Мартин Эндер
1
Perl предоставляет нечто подобное: qw(Foo Bar Baz Quux)становится списком строк.
Бен Голдберг
12
Понять, что сделали другие люди
Помимо удовольствия, если вы изучаете код других людей, вы можете иногда найти хороший алгоритм, о котором вы не задумывались, или трюк (иногда очевидный), который вы пропускаете.
Иногда существует существующий ответ, который вы можете перевести на другой язык и воспользоваться его вкусностями.
Всякий раз, когда вы комбинируете несколько выражений, проверяйте таблицу приоритетов операторов для вашего языка, чтобы увидеть, можете ли вы изменить порядок вещей, чтобы сохранить скобки.
Примеры:
На всех языках, которые я знаю, побитовые операторы имеют более высокий приоритет, чем логические операторы: не
(a&b)&&cнуждается в скобках: так a&b&&cже, как (a*b)+cи нет.
a+(b<<c)можно переписать как a+b*2**c.
Это ничего не сохраняет для этого примера, но будет, если cэто маленький целочисленный литерал (<14).
Битовые операции имеют меньший приоритет, чем большинство арифметических операций, поэтому, если ваш язык неявно преобразует логическое значение в int, вы можете сохранить байт a<b&&c<dс помощью a<b&c<d(если только вам не нужна оценка короткого замыкания)
Если у вас есть Xоператоры {внутри }цикла for, вы можете переместить X-1операторы (внутри )цикла for после второй точки for(blah;blah;HERE)с запятой, чтобы сохранить 3 байта. (разделите операторы запятыми ,)
Вместо
for(int i=0;i<9;){s+=s.length();println(i++);}
Вы можете переместить одно из утверждений в (фигурные скобки цикла for, )оставляя другое вне
for(int i=0;i<9;println(i++))s+=s.length();
и сохраните 3 байта (еще 1 байт благодаря @ETHProductions)
Проще говоря,
вместо
for(blah;blah;){blah 1;blah 2;...;blah X}
переместить утверждения вокруг, чтобы вы в конечном итоге с этим
Это может выглядеть как совет, который вы не будете использовать все так часто, вроде как ~xвместо того, -x-1чтобы встречаться не часто, но я использовал его достаточно много раз, чтобы увидеть его здесь как полезный совет. Особенно с индексированием массива вы можете использовать их выше в некоторых случаях.
Простой трюк, который я придумал, пытаясь сжать длинную полосу условий, прикованных цепью ands (или ors, в данном случае просто заменить «all» на «any»).
Какие языки имеют all(array-of-Booleans)встроенный?
Питер Тейлор
3
У Руби есть это. [a>0,a<10,a+b==4,a+3<1].all?
Kernigh
4
Хотя, если бы это был Python, вы бы использовали что-то вродеif 10>a>0 and a+b==4>1>a+3:
Sp3000
@PeterTaylor Haskell тоже
гордый haskeller
6
Положитесь на компилятор, чтобы обеспечить требуемую производительность.
Убедитесь, что вы знаете, какие оптимизации гарантированы компилятором и на каких уровнях оптимизации, и используйте их свободно. И даже если производительность не является проблема требования, вы можете проверить с оптимизациями на, а затем только скидку на один символ , потому что ваш код все еще технически действует без флага компилятора.
Рассмотрим следующую функцию Haskell для вычисления 2 ^ n (игнорируя тот факт, что Haskell уже имеет встроенный оператор возведения в степень или три) (23 символа):
p 0=1;p x=p(x-1)+p(x-1)
Проблема в том, что это ужасно медленно, оно работает в геометрической прогрессии. Это может сделать ваш код непроверенным или потерять любые ограничения производительности, заданные вопросом. У вас может возникнуть соблазн использовать временную переменную или литерал функции, вызываемой немедленно, чтобы избежать повторных вызовов функций (25 символов):
p 0=1;p x=(\y->y+y)$p$x-1
Но компилятор уже может сделать это за вас, вам просто нужно установить -Oфлаг компилятора! Вместо того, чтобы тратить несколько лишних символов на сайт для устранения общих подвыражений вручную, просто скажите компилятору выполнить базовую оптимизацию для вас, чтобы получить всего один или два символа во всей программе.
На каком языке вы можете сделать назначение внутри звонка? или это ключевое слово arg?
кот
2
Я думаю, что присваивания являются выражениями (с новым значением назначенной переменной в качестве значения их выражения) по крайней мере в C, C ++, C # и Java. a = (b=c)+1;устанавливает bв c, а затем устанавливает aв b+1.
Линн
@ Линн Попробуй a=1+b=c. И вы можете добавить PHP и JavaScript в свой список.
Титус
2
Руби делает это лучше всего. Он дает =оператору более высокий приоритет слева, чем справа, поэтому 1+x=2он действителен и оценивает3
Cyoce
@Cyoce afaik это так на всех языках, где присваивание является выражением.
Тит
5
Использовать языковую версию / компилятор / особенности среды / новые функции
Это особенно полезно для полиглотов , но может быть применено к другим задачам. Иногда ошибка компилятора может отставать от байта, ошибка реализации может позволить вам сэкономить несколько символов, или действительно передовая функция может улучшить ваш счет.
Кроме того, используйте битовые условия ( &, `|), чтобы удалить больше символов.
FUZxxl
2
Хотя использование поразрядно &вместо &&удаления 1 символа в некоторых случаях портит приоритет оператора, и вам придется ставить круглые скобки, чтобы он работал. Используйте его с умом.
Доллар Акшай
4
Найдите лучшие способы инициализации ваших переменных
Некоторые другие ответы уже были близки к упоминанию об этом, но во многих (строго типизированных?) Языках короче инициализировать xкак пустую строку, например:
x:=""
или xкак пустая руна (символ) как:
x:=''
чем
var x string
а также
var x rune
Использование ранее существующих значений, очевидно, предпочтительнее, но не так просто.
<all languages>
...Ответы:
Объединить петли
Обычно вы можете объединить два последовательных цикла или два вложенных цикла в один.
До:
После:
источник
foo
называетсяa
временем,bar
называетсяb
временем. Это связано с тем, что в «после» цикл выполняетсяa+b
раз, первыйa
вызовfoo
, следующий вызовbar
.for(y=0;y<Y;++y)for(x=0;x<X;++x)
часто становятсяfor(i=0;i<X*Y;++i)
сx
замененыi%X
иy
замененыi/X
.Просто упомянуть очевидное:
Задайте вопрос о выборе алгоритма и попробуйте что-то совершенно новое.
Когда вы играете в гольф (особенно сложные проблемы, которые приводят к более длительным программам) слишком часто, вы можете придерживаться выбранного вами пути, не пытаясь использовать другие фундаментальные варианты. Конечно, вы можете играть в микро-гольф по одной или нескольким линиям за раз или как часть общей идеи, но часто не пытайтесь использовать совершенно другое решение.
Это было особенно заметно в Удар 495 (Капрекар), где отклонение от фактического алгоритма и поиск шаблонов, которые вы можете применить, чтобы получить тот же результат, были короче во многих языках (только не в J).
Недостатком является то, что вы, возможно, решаете одно и то же полдюжины раз. Но он работает практически на всех языках, кроме HQ9 + (где найти другой способ вывода Hello World было бы немного бесполезно).
источник
Используйте тестовую разработку
Если код должен обрабатывать различные входные данные, тогда напишите комплексные тесты и упростите их выполнение очень быстро. Это позволяет попробовать рискованные трансформации по одному детскому шагу за раз. Тогда игра в гольф становится рефакторингом с извращенным намерением.
источник
Попробуйте уменьшить логические высказывания
Например, если
A
иB
являются булевыми и вашим язык обрабатывает булевы как числа в некоторой степень,A and (not B)
иA>B
эквивалентны. Например в Pythonтакой же как:
источник
B>A or foo()
было бы еще более коротким способом выразить это, воспользовавшись ленивой оценкой булевых выражений, чтобы гарантировать, что он вычисляет вещи только тогда, когда это необходимо.B>A or foo
оценилfoo
бы, еслиB==A
это не то, что мы хотим. (Верно?)Инициализируйте переменные, используя значения, которые у вас уже есть.
Вместо этого
x=1
попробуйте найти что-то, что уже равно 1.Например, возвращаемое значение функции:
printf("..");x=0;
->x=!printf("..");
. Проще всего с 0, потому что вы всегда можете отрицать, или когда все, что вам нужно, это правильное значение истинности (и не волнует, если это 1 или 19).источник
Используйте одинарные
~
дляx+1
иx-1
Этот прием применим к языкам, которые имеют унарный побитовый оператор отрицания
~
и унарный регулярный оператор отрицания-
.Если ваша программа случайно содержит выражение
-x-1
, вы можете заменить его,~x
чтобы сохранить байты. Это происходит не слишком часто, но посмотрите, что произойдет, если мы отвергнем (-
) оба выражения:x+1
равно-~x
! Точно так же,x-1
равно~-x
. (Подумайте, в какую сторону указывает тильда: справа есть+
, слева есть-
.)Это полезно, потому что во всех языках, о которых я могу думать, эти операторы имеют более высокий приоритет, чем большинство операторов. Это позволяет сэкономить на скобках. Посмотрите, как мы сохраняем четыре байта здесь:
источник
Сожмите пробел
Знайте правила для пробелов на вашем языке. Некоторым знакам препинания или другим символам может не понадобиться окружающий пробел. Рассмотрим эту функцию оболочки Борна :
В оболочке Bourne
();
есть метасимволы, и не нужно окружать их пробелами. Тем не менее,{}
слова являются и нуждаются в пробеле, если они не находятся рядом с метасимволами. Мы можем поиграть в гольф на 4 поля рядом с();
, но мы должны оставить расстояние между{
иecho
.В Common Lisp и PicoLisp ,
()
есть метасимволы. Рассмотрим этот код, чтобы найти среднее из двух чисел:Мы можем сыграть в гольф на 2 места.
Некоторые языки имеют странные и тонкие правила для пробелов. Рассмотрим программу Ruby, которая выводит сумму и произведение строки целых чисел.
Каждому
&
нужно пространство перед собой. В Rubyi=$F.map &:to_i
означает,i=$F.map(&:to_i)
где&
передается параметр блока. Но,i=$F.map&:to_i
означает,i=$F.map.&(:to_i)
где&
бинарный оператор.Эта странность встречается в языках, таких как Perl или Ruby, которые используют неоднозначную пунктуацию. В случае сомнений используйте REPL или напишите короткие программы для проверки правил пробелов.
источник
назначать функции новые имена, если они используются несколько раз
источник
x
.Однобуквенные имена переменных
У вас есть 52 из них; использовать их все! Не бойтесь пробовать разные подходы и сравнивать длины. Знать язык и специальные ярлыки / доступные функции библиотеки.
источник
$
и_
могут быть использованы в качестве идентификаторов.@
является допустимым именем переменной в T-SQL, используйте его вместо@a
.Используйте условный оператор.
Условный оператор
является более полезным, характерным, чем заявление IF .
можно записать как
источник
a&&b||c
вместо этого. Чуть дольше, но все же короче, чемif
.Iff
, хотя это функция, поэтому при условии оценки всех аргументов.if(a ? b : c)
a&&b||c
может возвращаться,c
когдаa
истинно, еслиb
ложно, небольшойНапишите объяснение вашего кода
Написание объяснения заставляет вас снова тщательно рассмотреть каждую часть вашего кода и сделать ваши мысли и выбор в написании определенного отрывка явным. При этом вы можете обнаружить, что возможны разные подходы, которые могут сэкономить несколько байтов, или что вы подсознательно сделали предположения, которые не обязательно выполняются.
Этот совет похож на вопрос о выборе алгоритма и попробуйте что-то совершенно новое ; тем не менее, я обнаружил, что этап написания того, как каждая часть должна работать, иногда имеет решающее значение для осознания альтернатив.
В качестве бонуса, ответы, включая объяснения, более интересны для других пользователей и, следовательно, с большей вероятностью будут проголосованы.
источник
Дважды проверьте количество символов
Звучит как ежу понятно, но если вы будете осторожны, вы сможете «спасти» нескольких персонажей, ничего не делая!
Если вы используете Windows, вы можете вводить
\r\n
вместо обычного\r
или\n
когда вы нажимаете Return, добавляя дополнительный байт на строку! Поверните управляющие символы, чтобы дважды проверить, что вы этого не делаете.В Notepad ++ вы можете конвертировать все
\r\n
окончания строк, просто\r
перейдя вEdit > EOL Conversion > UNIX/OSX Format
.Также убедитесь, что вы не включаете пробелы в число своих персонажей! Перевод строки в нижней строке вашего кода также несущественен, так что подсчитывать его тоже не нужно.
источник
Внимательно прочитайте вопрос
Гольф-код - это не только понимание вопроса (что задается, а что нет , даже если это подразумевается в любой другой ситуации), а также создание кода, который (может) удовлетворять только то, что спрашивается.
Любой ввод, кроме того, что явно запрашивается, не должен обрабатываться. Если есть несколько тестовых случаев и нет общих требований, ваш код может работать только в этих случаях. И т.п.
источник
Используйте побитовые операции для проверки чисел между 0 и любыми 2 n -1
Может быть, это немного необычный случай, но иногда он может пригодиться. Он основан на том факте, что все числа, к которым применяется m = 2 n -1, имеют самые правые n битов, равные 1.
Итак, 7 10 == 00000111 2 , 15 10 == 00001111 2 , 31 10 == 00011111 2 и так далее.
Хитрость есть
x&~m
. Это возвращает истину , когдаx
это не от 0 доm
(включительно), и ложь в противном случае. Он сохраняет 6 байтов из следующего кратчайшего эквивалентного выражения:,x>=0&&x<=m
но, очевидно, работает только тогда, когдаm
удовлетворяет 2 n -1.источник
Повторно используйте параметры функции вместо новых переменных
источник
main(i){...
теперь у вас есть переменная со значением 1 без необходимости делать какие-либо задания. 2 символа сохранены там ..Больше / меньше, чем для сохранения цифры:
Просто не забудьте поменять код с
if
на,else
и они будут делать то же самое (или переключать стороны неравенства)!Примечание: это может быть применено с любой степенью 10 и их минусами:
...-100, -10, 10, 100...
(ссылка на источник)
источник
if(n>99999)
vsif(n<1e5)
Используйте> и <вместо> = и <=
При сравнении с жестко запрограммированными целочисленными значениями используйте
>
и<
вместо>=
и<=
где это возможно. Например, используяНа 2 байта короче, чем при использовании
источник
<1
вместо==0
нулевой проверки (или>0
вместо!=0
зеркальной проверки).x
чтобы быть целым числом?Избегайте преждевременных разрывов петли
Если при выполнении цикла выполняется проверка на наличие одного или нескольких экземпляров логической проверки, это может привести к тому, что более эффективная программа выйдет из цикла с первым истинным значением. Однако удаление разрыва и циклического прохождения всех итераций позволяет сократить код.
источник
if
заявление прочь в этих случаях:m|=i>=100
. (И в этом случае вы также можете упроститьi>=100
to,i>99
но здесь это не очень актуально)использовать
-
вместо!=
для числовых сравнений:
Если a равно b, это
a-b
приводит к0
ошибочности. Все, кроме0
правды; поэтому,если используется в логическом контексте,
a-b
<=>a!=b
Если вы используете его с
if/else
или с троичным оператором, это также может сэкономить вам один байт для равенства:a==b?c:d
<=>a-b?d:c
источник
Сплит-строки для длинных массивов
В большинстве языков есть способ разбить строку на массив строк вокруг какого-либо токена. Это неизбежно будет короче литерала массива, когда длина достигнет порогового значения, зависящего от языка, поскольку дополнительные издержки на строку будут представлять собой одну копию токена с одним символом, а не (как минимум) двух разделителей строк.
Например, в GolfScript
становится
Для некоторых языков порог составляет всего одну строку. Например, на Яве,
становится
источник
%w{Foo Bar Baz Quux}
.qw(Foo Bar Baz Quux)
становится списком строк.Понять, что сделали другие люди
Помимо удовольствия, если вы изучаете код других людей, вы можете иногда найти хороший алгоритм, о котором вы не задумывались, или трюк (иногда очевидный), который вы пропускаете.
Иногда существует существующий ответ, который вы можете перевести на другой язык и воспользоваться его вкусностями.
источник
знать приоритет вашего оператора
Всякий раз, когда вы комбинируете несколько выражений, проверяйте таблицу приоритетов операторов для вашего языка, чтобы увидеть, можете ли вы изменить порядок вещей, чтобы сохранить скобки.
Примеры:
(a&b)&&c
нуждается в скобках: такa&b&&c
же, как(a*b)+c
и нет.a+(b<<c)
можно переписать какa+b*2**c
.Это ничего не сохраняет для этого примера, но будет, если
c
это маленький целочисленный литерал (<14).a<b&&c<d
с помощьюa<b&c<d
(если только вам не нужна оценка короткого замыкания)источник
Короче петли
Если у вас есть
X
операторы{
внутри}
цикла for, вы можете переместитьX-1
операторы(
внутри)
цикла for после второй точкиfor(blah;blah;HERE)
с запятой, чтобы сохранить 3 байта. (разделите операторы запятыми,
)Вместо
Вы можете переместить одно из утверждений в
(
фигурные скобки цикла for,)
оставляя другое внеи сохраните 3 байта (еще 1 байт благодаря @ETHProductions)
Проще говоря,
вместо
переместить утверждения вокруг, чтобы вы в конечном итоге с этим
и сохранить 3 байта
источник
for
это окончательное утверждение, оно;
становится необязательнымИспользуйте одинарные
~
дляa-b-1
иa+b+1
В дополнение к предложениям @Lynn относительно
x+1
→-~x
; иx-1
→~-x
, вы также можете играть в гольфa-b-1
иa+b+1
.Это может выглядеть как совет, который вы не будете использовать все так часто, вроде как
~x
вместо того,-x-1
чтобы встречаться не часто, но я использовал его достаточно много раз, чтобы увидеть его здесь как полезный совет. Особенно с индексированием массива вы можете использовать их выше в некоторых случаях.источник
Сжатие или / и полосы
Простой трюк, который я придумал, пытаясь сжать длинную полосу условий, прикованных цепью ands (или ors, в данном случае просто заменить «all» на «any»).
Например:
становится
источник
all(array-of-Booleans)
встроенный?[a>0,a<10,a+b==4,a+3<1].all?
if 10>a>0 and a+b==4>1>a+3:
Положитесь на компилятор, чтобы обеспечить требуемую производительность.
Убедитесь, что вы знаете, какие оптимизации гарантированы компилятором и на каких уровнях оптимизации, и используйте их свободно. И даже если производительность не является
проблематребования, вы можете проверить с оптимизациями на, а затем только скидку на один символ , потому что ваш код все еще технически действует без флага компилятора.Рассмотрим следующую функцию Haskell для вычисления 2 ^ n (игнорируя тот факт, что Haskell уже имеет встроенный оператор возведения в степень или три) (23 символа):
Проблема в том, что это ужасно медленно, оно работает в геометрической прогрессии. Это может сделать ваш код непроверенным или потерять любые ограничения производительности, заданные вопросом. У вас может возникнуть соблазн использовать временную переменную или литерал функции, вызываемой немедленно, чтобы избежать повторных вызовов функций (25 символов):
Но компилятор уже может сделать это за вас, вам просто нужно установить
-O
флаг компилятора! Вместо того, чтобы тратить несколько лишних символов на сайт для устранения общих подвыражений вручную, просто скажите компилятору выполнить базовую оптимизацию для вас, чтобы получить всего один или два символа во всей программе.источник
p(x-1)*2
?Может быть, несколько очевидно, но ...
Используйте оператор возвращаемых значений
Имейте в виду, что оператор присваивания возвращает значение!
Например, если вы хотите добавить y к x, а затем проверить, больше ли x чем-то, вы можете сделать
вместо
Или, может быть, вы хотите найти длину строки после обрезки:
Скорее, чем
источник
a = (b=c)+1;
устанавливаетb
вc
, а затем устанавливаетa
вb+1
.a=1+b=c
. И вы можете добавить PHP и JavaScript в свой список.=
оператору более высокий приоритет слева, чем справа, поэтому1+x=2
он действителен и оценивает3
Использовать языковую версию / компилятор / особенности среды / новые функции
Это особенно полезно для полиглотов , но может быть применено к другим задачам. Иногда ошибка компилятора может отставать от байта, ошибка реализации может позволить вам сэкономить несколько символов, или действительно передовая функция может улучшить ваш счет.
источник
Комбинируйте множественные / вложенные, если проверки, используя И / Или, когда это возможно.
то есть:
вместо:
источник
&
, `|), чтобы удалить больше символов.&
вместо&&
удаления 1 символа в некоторых случаях портит приоритет оператора, и вам придется ставить круглые скобки, чтобы он работал. Используйте его с умом.Найдите лучшие способы инициализации ваших переменных
Некоторые другие ответы уже были близки к упоминанию об этом, но во многих (строго типизированных?) Языках короче инициализировать
x
как пустую строку, например:или
x
как пустая руна (символ) как:чем
а также
Использование ранее существующих значений, очевидно, предпочтительнее, но не так просто.
источник