Статьи

Руби Гольф

Ruby golf — это искусство написания кода, в котором используется как можно меньше символов. Идея берет свое начало в мире Perl (где неудивительно, что он известен как Perl Golf). Как язык, Perl хорошо подходит для этого, так как имеет больше, чем справедливую долю странных конструкций и синтаксического сахара. Рубин также содержит несколько больших кусочков синтаксического сахара, что делает его подходящим для нечетного раунда игры в гольф.

Одержимость попыткой свести к минимуму количество байтов, используемых в программе, возвращает нас к прошлому возрасту, когда память была дороже и каждый байт считался. На самом деле он не имеет практического применения в современном мире, но это не значит, что он до сих пор не используется. Минимизацию кода можно найти в таких конкурсах, как конкурсы 1k JavaScript и Perl Apocalypse . Есть также ряд сайтов, посвященных искусству Code Golf.

С Code Golf часто возникает элемент конкуренции: хакеры пытаются превзойти друг друга, стремясь найти «идеальное» решение. Тот, который достигает цели кода, но не может быть выполнен меньшим количеством символов. Я нахожу это аналогичным для математиков, которые ищут «элегантные доказательства», и мне напоминают цитату Эйнштейна «Все должно быть сделано как можно проще, но не проще».

К сожалению, код, который создается, часто очень сложен для понимания, так как он обычно использует различные методы и ярлыки. На самом деле, бесплатная игра — попытаться выяснить, что на самом деле делает код! Часто между умным и слишком умным существует тонкая грань …

У Code Golf репутация мармита — люди либо любят его, либо ненавидят, поэтому, чтобы попытаться сохранить равновесие, я перечислил некоторые из преимуществ и недостатков попытки попробовать свои силы в раунде или двух:

преимущества

  • Вы можете изучить некоторые менее известные части языка и некоторые хитрые уловки.
  • Внутри вы получите хорошее самодовольное чувство, когда вам удастся отобрать еще несколько персонажей из лучшего решения.
  • Иногда более лаконичный способ написания кода на самом деле выглядит чище.
  • Вы можете изучить методы, которые могут быть полезны в других ситуациях.
  • Сам процесс поощряет изобретательность.
  • Это весело!

Недостатки

  • Код обычно выглядит ужасно
  • Код часто может быть трудным для чтения или понимания, и это позор, потому что одним из лучших аспектов Ruby является его читабельность.
  • Код был бы кошмаром обслуживания — даже сам по себе, не говоря уже о других.

Pro Советы

Если вы хотите поиграть в гольф, вот несколько советов, которые можно использовать, чтобы сократить ваш код на Ruby и уменьшить ваш гандикап в гольфе:

  • Массовое задание

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

    a,b = 1,2 
  • Создание массивов с использованием ярлыка% w

    Вы можете создавать массивы строк, используя следующие обозначения:

     a = %w(abc) => ["a","b","c"] 
  • Используйте троичный оператор для логики
     a>10?"too big":"fine" 
  • Используйте цепочечные троичные операторы для более сложной логики
     a<0?"no negatives":(a>10?"too big":"fine") 
  • Используйте научную запись для чисел

    Если вам нужны большие числа, то 1e6 короче, чем 1000000 .

  • Используйте синтаксис Dash-Rocket для Procs

    Если вы используете Ruby 1.9, используйте синтаксис dash-rocket ( -> ) для procs

     sayhello = -> {p "hello"} sayhello = -> name {p "hello #{name}"} 
  • 1 символьная строка

    Для строк из 1 цифры используйте ?x = "x" (опять же, это работает только в Ruby 1.9)

  • Изучите регулярные выражения

    Регулярные выражения могут выражать некоторые сложные выражения в несколько символов.

  • Используйте оператор по модулю, чтобы проверить, является ли число фактором

    12%3==0 , потому что 12 кратно 3
    13%3!=0 , потому что 13 не кратно 3

    **РЕДАКТИРОВАТЬ**

    Это было улучшено Сайрусом в комментариях. Вы можете просто проверить, если ответ меньше одного, а не равен нулю:

     12%3<1 => true 
  • Используйте карту для итерации

    Итераторы обычно лучше, чем для циклов, и map — лучший итератор, так как в нем меньше всего символов. Он может использоваться вместо each потому что вам не нужно менять каждый элемент в массиве, он все еще проходит через него.

     %w(abc).map{|x| puts x} 
  • Использовать Символ Для Процесса

    Это экономит много времени (и, возможно, выглядит аккуратнее).

     %w(abc).map{ |e| e.upcase } 

    становится

     %w(abc).map(&:upcase) => ["A", "B", "C"] 

    На самом деле происходит то, что & вызывает метод to_proc для следующего символа (в этом случае метод to_proc для каждого элемента массива.

  • Easy Joins
    %w(abc)*"-" аналогично %w(abc).join"-"
    => «Abc»
  • Повторное использование циклов

    Хороший способ избежать использования двух циклов для разных типов объектов — объединить все объекты в один массив и использовать только один итератор, а затем выполнять разные задачи в зависимости от типа объекта.

     ["a","b",2,4].map{|e|(e.to_s==e)?(e.upcase):(e*2)} => ["A", "B", 4, 8] 
  • Типы тестирования

    Если вы хотите проверить, является ли объект строкой, то e.to_s==e короче, чем e.is_a? String e.is_a? String

Есть ли у вас какие-либо другие советы, чтобы снять гандикап? Оставьте свои советы в комментариях.

Почти Синатра

Константин Хассе (Sinatra Jedi Grand Master) выполнил экстремальную форму Ruby Golf, когда он сжал Sinatra (не совсем раздутый с 1646 строками кода) в жалкие 8 строк кода. У него не было той же функциональности, но она была чертовски близка. При этом он использовал несколько замечательных трюков, последние пару советов в приведенном выше списке взяты из кода « Почти Синатра» .

Примерное отверстие

В качестве примера я попытался написать метод, который бы нашел сумму всех кратных данного числа до заданного значения. Например, сумма (5,24) будет вычислять сумму всех кратных от 5 до 24 (то есть 5 + 10 + 15 + 20).

Вот что я в итоге придумал:

 def sum(n,t) n*(1..t/n).to_a.inject(&:+) end 

Я использовал символ для обозначения proc, чтобы использовать метод inject для суммирования целых чисел. Сколько целых чисел было найдено путем деления целых чисел и полагаясь на тот факт, что остатки игнорируются.

Содержит 27 символов (не включая определение метода). Кто-нибудь может победить? Оставьте свой ответ в комментариях, если можете.

Конкуренция

Теперь пришло время узнать, кто такой Тайгер Вудс Рубинового Мира. Ниже приведены пять «лунок», которые составляют поле для гольфа RubySource. Попробуйте свои силы на любом или на всех из них и опубликуйте свои решения в комментариях.

Отверстие 1: Fizz Buzz

Для заданного числа функция возвращает «Fizz», если оно кратно 3, «Buzz», если оно кратно 5, и «FizzBuzz», если оно кратно 15. Если число не кратно 3 или 5 затем число возвращается в виде строки.

Пример:

 fizzbuzz(3) => "Fizz" fizzbuzz(10) => "Buzz" fizzbuzz(45) => "FizzBuzz" fizzbuzz(31) => "31" 

Отверстие 2: Цезарь Шифр

Внедрить шифр Цезаря

Пример:

 caeser("hello",3) => "khoor" 

Вы также должны быть в состоянии произвести отрицательные сдвиги.

Отверстие 3: Камень, Бумага, Ножницы Игра

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

Пример:

 play("Rock") => "Rock,Draw" play("Paper") => "Rock,Win" play("Scissors") => "Rock,Lose" play("Soap") => "Paper,Lose" 

Отверстие 4: Счетчик струн

Напишите метод, который при задании строки и подстроки возвращает количество раз, когда подстрока встречается в этой строке (без учета регистра).

Пример:

 count("Banana","a") => 3 count("RubySource provides advice, tutorials, commentary, and insight into the Ruby and Rails ecosystem","ruby") => 2 

Отверстие 5: функция свингеров

Напишите функцию, которая заменяет «складывание ключей». Аргумент функции — это массив массивов, которые содержат два объекта. Функция возвращает новый массив, в котором пары объектов были перепутаны. Объект не должен заканчиваться своим оригинальным «партнером».

Пример:

 swingers([["Homer","Marge"],["Micky","Minnie"],["Fred","Wilma"],["Peter","Lois"],["George","Judy"]]) => [["Homer","Wilma"],["Micky","Lois"],["Fred","Judy"],["Peter","Marge"],["George","Minnie"]] 

Для входа напишите свой метод в комментариях ниже. Человек, чья запись содержит наименьшее количество символов, выиграет каждую лунку. Для победителя каждой лунки есть книга Sitepoint. Вы можете использовать Ruby 1.8 или 1.9. Крайний срок — 31 декабря 2011 года. Будут засчитаны только символы внутри определения метода, поэтому в приведенном выше примере отверстие будет считаться 27 символами. Не стесняйтесь опубликовать Gist для вашего кода.

FORE!