42 заметки с тегом

99

У американцев есть такая считалочка — «песня о пиве», наверняка её многие слышали в американских фильмах. У меня есть хобби — делать вывод этой считалочки на разных языках программирования. Со временем набралась приличная коллекция.

Позднее Ctrl + ↑

99 бутылок: Эллочка

58. Эллочка. Мне написал автор языка программирования «Эллочка» с предложением написать на нём «99 бутылок…», как вы знаете, у меня есть хобби — писать такие программы на разных языках.

Для этого языка есть единственный, авторский интерпретатор под ДОС (и очень важно использовать в файле программы символы перевода ДОС/Виндоуз, иначе ничего не будет работать), а сам язык напоминает странноватый Бейсик, без поддержки функций и процедур. Их можно эмулировать, используя трюк со специальной переменной «@», которая содержит номер текущей строки.

В языке есть ряд интересных возможностей, но их затмевают недостатки разного калибра, что характерно для языков без сообщества. Даже в таком простом примере мне пришлось побороться за работоспособность программы. Например, перед числами зачем-то всегда выводится символ табуляции (я его срезаю функцией %MID), а когда вывод достигает размера экрана (80×25), то прокрутки не происходит, программа просто жалуется, что «операция не позволяется» (поэтому я просто жду нажатия клавиши после каждой итерации и очищаю экран).

!99 beer song by Evgeny Stepanischev
!Used variables: B, R, $1
B=99
@cycl
    R=@+2 
    goto @beer
    list ' of beer on the wall, '
    R=@+2
    goto @beer
    list '.'\
    list 'Take one down and pass around'\
    decr B
    R=@+2
    goto @beer
    list ' of beer on the wall.'\
    list ''\
    wait
    clsc
esli B >> 0; @cycl
list 'No more bottles of beer on the wall, no more bottles of beer.'\
list 'Go to the store and buy some more, 99 bottles of beer on the wall.'
exit
@beer
esli B >> 0; +3\
list 'No bottles'
goto R
esli B == 1; +5\
$1=B
$1=%MID($1,2,10)
list $1+' bottles'
goto R
list '1 bottle'
goto R

99 бутылок: CMake

57. CMake. Писать «Песни про пиво» на различных языках программирования — давнее моё увлечение, ему столько же лет, сколько этому блогу. В этот раз «поёт» «Си-мэйк».

CMake — автоматизированная система сборки пакетов, имеющая развитый, хотя и несколько уродливый макроязык. Инструкции, большей частью, знакомые, разве что способ возврата значений несколько из макросов и функций несколько странный — через параметры и глобальные переменные.

Никакого ООП, само собой, и всё весьма примитивно по меркам развитых языков.

# 99.cmake
# to run: cmake -P 99.cmake
# Written by Evgeny Stepanischev, 2015

cmake_minimum_required(VERSION 3.0)

macro(bottles beer ret)
    if(${beer} EQUAL 0)
        set(${ret} "No bottles")
    elseif(${beer} EQUAL 1)
        set(${ret} "1 bottle")
    else()
        set(${ret} "${${beer}} bottles")
    endif()
endmacro()

foreach(beer RANGE 99 1 -1)
    bottles(beer bottles)
    math(EXPR beer "${beer}-1")
    bottles(beer bottless)

    message("${bottles} of beer on the wall, ${bottles}.")
    message("Take one down and pass it around, ")
    message("${bottless} of beer on the wall.")
    message("")
endforeach()

message("No more bottles of beer on the wall, no more bottles of beer.")
message("Go to the store and buy some more, 99 bottles of beer on the wall.")

Строка для запуска во второй строке файла.

99 бутылок пива на «Электронике МК85»

«Электроника МК85» и «99 бутылок пива» (86.34КиБ)

56. БЭЙСИК «Электроники МК85». Как я уже сказал, Бейсик (в руководстве он называется «БЭЙСИК») на «МК85» отличается странностями. Например, там фиксированное количество переменных с определёнными (только однобуквенными именами), причём только одна строковая переменная может содержать не более 30 символов (её имя — символ доллара), остальные могут содержать не более семи символов.

Или запись массивов — все числовые переменные, по сути, являют собой один массив. Индекс «один» массива с именем «А» совпадает с переменной «B», а индекс «два» переменной «B» — это переменная «D» и так далее. Так что вы можете использовать что-то одно — либо массив полностью, либо переменные.

Другая неприятная особенность — небольшой максимальный размер строки и программы и весьма ограниченный её размер. Из-за этого принято лепить программу как можно более компактно (что я и сделал).

В общем, представляю вашему вниманию программу «99 бутылок пива на стене», написанную на БЭЙСИКе микрокомпьютера «Электроника МК-85», я запускал, работает:

10FOR B=99 TO 1 STEP -1
20A=B:GOSUB90:PRINT" of beer on the wall, ";:GOSUB90:PRINT"."
30PRINT"Take one down and pass it around, ";:A=B-1:GOSUB90
40PRINT" of beer on the wall."
50NEXT B
60PRINT"No more bottles of beer on the wall, no more bottles of beer."
70PRINT"Go to the store and buy some more, 99 bottles of beer on the wall."
80END
90GOTO100*(SGN(A-1)+2)
100PRINT"no bottles";:RETURN
200PRINT"1 bottle";:RETURN
300PRINT A;" bottles";:RETURN

Микрокомпьютер имеет интересную особенность — длинные строки, не помещающиеся на экране, он автоматически прокручивает, а чтобы человек успел прочитать, после каждой строки происходит остановка интерпретатора, для продолжения надо нажать клавишу «EXE». Точка с запятой после оператора «PRINT» говорит интерпретатору, что строка не кончилась, что позволяет печатать длинные строки несколькими операторами.

Ещё одна особенность — программируемый символ. Один символ, имеющий специальный код можно нарисовать попиксельно. Завтра попробую побаловаться.

99 бутылок: 𝄢 Cello

55. 𝄢 Cello. Попробовал попрограммировать с использованием библиотеки «libCello» — это набор макросов к Си, вводящих в язык кучу комплексных типов, простую работу с выделением и освобождением памяти под них, лямбда-функции, классы и так далее.

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

Пример ошибки в документации — функции в «стиле Си» не могут быть заданы внутри функции main, хотя на сайте указан пример, в котором утверждается обратное (и он не компилируется).

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

Если бы её дописать и достойно задокументировать, вышло бы что-то интересное, пока же я пас — надо знать в деталях каждый макрос (а их там очень много) чтобы понять из-за чего скомпилированное в очередной раз упало.

#include "Cello.h"

int main() {
    lambda(bottles, args) {
        var beer = cast(at(args, 0), Int);

        if_eq(beer, $(Int, 0)) {
            print("no bottles");
        } else {
            if_gt(beer, $(Int, 1)) {
                print("%d bottles", beer);
            } else {
                print("1 bottle");
            };			
        }

        return None;
    };

    for (var beer = $(Int, 99); gt(beer, $(Int, 0));) {
        call(bottles, beer);
        print(" on the wall, ");
        call(bottles, beer);
        println(".");

        print("Take one down and pass it around, ");
        sub(beer, $(Int, 1));
        call(bottles, beer);
        println(" of beer on the wall.\n");
    }

    println("No more bottles of beer on the wall, no more bottles of beer.");
    println("Go to the store and buy some more, 99 bottles of beer on the wall.");
}

Судя по репозиторию, автор интерес к своему детищу не потерял, будем надеяться, что когда-нибудь из этого получится что-то вроде гугловского «Гоу».

99 бутылок: Scratch и HQ9+

54. HQ9+ — язык, у которого только четыре оператора. «H» выводит «Hello world», «Q» печатает исходный код программы, 9 выводит «песню о пиве», а «плюс» «увеличивает аккумулятор». Язык, понятное дело, придуман в шутку и у неё есть продолжения — «объектный» «HQ9++», Тюринг-полный «HQ9+B» и так далее.

Так что данная программа на этом языке выглядит вот так:

9


53. Scratch. «Скретч» — язык программирования для школьников младших и средних классов. Интересный класс языков, я никогда им особо не интересовался, а тут возник совершенно профессиональный интерес — как можно дать возможность программировать что-то в нашей системе людям, которые в программировании ничего не понимают.

Я, для интереса, написал на «Скретче» свои «99 бутылок». Программа на скриншоте. В среде редактирования мы управляем лисёнком и всё программирование крутится вокруг него, куча блоков позволяют что-то с ним делать — двигать, вращать, заставляют его что-то говорить и так далее. «Думать» выводит свой аргумент в  «облачке» его мыслей.

Скретч (84.30КиБ)

Программа строится из цветных блоков, цвета кодируют тип блока — «движение», «внешность», «звук», «данные», «управление», «операторы» и так далее. Основные конструкции обычных языков в наличии. Процедур, как таковых, нет, но можно отсылать события другим ээ… подпрограммам и через глобальные переменные получать результат. Есть даже что-то похожее на потоки — передавая события, можно запускать подпрограммы асинхронно.

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

Есть ещё какие-то «Другие блоки», но с ними я не разбирался. Кажется, через них можно как-то расширять язык.

99 бутылок: AppleScript, Applesoft BASIC

У меня тут мой ноут поперхнулся чаем, так что я неделю был на стареньком компике под Виндой, почувствовал себя себя как без рук. По этой же причине почти не писал ничего в блог, лишь одним вечером на ноуте жены написал очередные две «Песни про пиво» на языках AppleScript и Applesoft BASIC. Первый — современный язык для автоматизации мелочи на «Маках», второй — древний (1977 год) бейсик, когда-то так же использовавшийся на «Маках».

52. AppleScript — встроенный в операционную систему «МакОС» язык программирования, используемый для мелкой автоматизации. По программе этой не очень очевидно, но язык максимально приближен к английскому, причём многие вещи можно формировать разнообразными способами — так же, как бы это сделал носитель английского языка.

В остальном, это обычный динамический интерпретируемый язык со слабой типизацией. Как видно в одном месте мне пришлось сделать преобразование типа. Вообще-то ЭплСкрипт делает это и сам, но в случае присоединения к строке, он число присоединит через запятую.

(* Песня про пиво. Автор — Евгений Степанищев *)
repeat with beer from 99 to 1 by -1
     set b to bottles(beer)
     log b & " on the wall, " & b & "."
     log "Take one down and pass it around, " & bottles(beer - 1) & " of beer on the wall."
     log
end repeat

log "No more bottles of beer on the wall, no more bottles of beer."
log "Go to the store and buy some more, 99 bottles of beer on the wall."

on bottles(beer)
     if beer = 0 then
 	        return "no bottles"
     else if beer > 1 then
 	        return (beer as string) & " bottles"
     else
 	        return "1 bottle"
     end if
end bottle


51. Applesoft BASIC — Бейсик разработанный компанией Майкрософт, использовавшийся в компьютерах фирмы Эпл, начиная с 1977 года. Ничего особо примечательного, вполне полнофункциональный язык, хоть и не без недостатков тех ранних «бейсиков» — вызов функций по номеру строки, параметров нет, локальных переменных нет, в общем, все прелести.

Я специально использовал конструкцию «ON…GOTO», хоть в ней и не было необходимости — хотел показать аналог конструкции switch. SGN тут — встроенная функция нахождения знака выражения.

000 REM Песня про пиво, автор — Евгений Степанищев
001 HOME: TEXT
010 FOR beer = 99 TO 1 STEP -1
020 b = beer: GOSUB 100
030 ? bottles$; " on the wall, "; bottles$; "."
035 b = beer - 1: GOSUB 100
040 ? "Take one down and pass it around, "; bottles$; " of beer on the wall."
050 ?
060 NEXT
070 ? "No more bottles of beer on the wall, no more bottles of beer."
080 ? "Go to the store and buy some more, 99 bottles of beer on the wall."
090 END
099 REM
100 ON SGN(b-1)+2 GOTO 120, 130, 110
110 LET bottles$ = STR$(b) + " bottles": RETURN
120 LET bottles$ = "no bottles": RETURN
130 LET bottles$ = "1 bottle": RETURN

99 бутылок: Batsh, VIM script

Потихоньку возобновил наполнение раздела «99 бутылок пива на стене» — тут я пишу американскую считалочку про пиво на различных языках программирования. Добавились языки VIM script и Batsh. Первый используется в консольном редакторе vim для написания внутренних скриптов, второй — для кроссплатформенного написания шелл-скриптов.

Batsh мне вообще понравился своей идеей — простой Си-подобный язык, который умеет транслироваться и в баш (Линукс, МакОС и так далее) и в бат-файлы (Виндоуз). Не уверен нужно ли это в жизни, но абстрактно идея хороша.

50. Batsh — чрезвычайно лёгкий в освоении язык с Си-подобным синтаксисом, который умеет транслироваться в баш- и бат-скрипты, т. е. скрипты, которые будут без проблем работать и в мире Линукса, и в мире Виндоуз. Язык без особых затей, работает, похоже, железобетонно, но бедноват — даже обычного цикла for в нём нет. В общем набор минимальный (хотя рекурсия есть), но программировать можно.

// Песня о пиве на языке Batsh Степанищева Евгения

function bottles(bottle){
    if (bottle == 0) {
        return "no bottles";
    }
    
    if (bottle == 1) {
        return "1 bottle";
    }
    
    return bottle ++ " bottles";
}

i = 99;
while (i > 0) {
    b = bottles(i) ++ " of beer";

    println(b, "on the wall,", b ++ ".");
    i = i - 1;
    println("Take one down and pass it around,", bottles(i), "of beer on the wall.\n");
};

println("No more bottles of beer on the wall, no more bottles of beer.");
println("Go to the store and buy some more, 99 bottles of beer on the wall.");


49. VIM Script — встроенный скриптовый язык программирования консольного редактора VIM. Синтаксис довольно обычен, учится легко. Мощный для своего класса — обилие встроенных функций, довольно согласованный синтаксис, различные типы массивов. Есть интересные особенности, например, возможность явного переопределения функций, префиксы переменных для явного определения зоны видимости (например, префикс «a:» у меня в функции — это аргументы) или функции, которые могут принимать что-то вроде примитивного итератора.

" написал Евгений Степанищев bolknote.ru"

:function Bottles(bottle)
:    return get(["no bottles", "1 bottle"], a:bottle, a:bottle . " bottles")
:endfunction

:for beer in range(99, 1, -1)
:   let b =  Bottles(beer) . " of beer"
:   echo b "on the wall," b . "."
:   echo "Take one down and pass it around, " . Bottles(beer-1) . " of beer on the wall.\n"
:endfor

:echo "No more bottles of beer on the wall, no more bottles of beer."
:echo "Go to the store and buy some more, 99 bottles of beer on the wall."

99 бутылок: Go

48. Go — язык программирования, придуманный в «Гугле». Я на нём программирую, время от времени, и довольно неплохо его уже знаю. Замечательный, на мой взгляд, язык. Этакий «Си с человеческим лицом». Особенно интересно добавлено туда ООП, да и параллельные вычисления сделаны хорошо. Единственно — не нравится реализация обработки ошибок через panic/defer.

Язык статический, строгой типизации, компилируемый. Кстати, одна из особенностей языка — исключительно быстрая компиляция.

Некоторые ребята считают, что он похож на «Паскаль». Думаю это из-за конструкции «:=», которая означает в Гоу «создать локальную переменную с типом присваемого результата», а эти ребята ничего кроме этой конструкции из «Паскаля» не помнят.

package main
import "strconv"

func main() {
    for i := 99; i>0; i-- {
        b := bottles(i) + " of beer"

        println(b + " on the wall, " + b + ".")
        println("Take one down and pass it around, " + bottles(i-1) + " of beer on the wall.\n")
    }

    println("No more bottles of beer on the wall, no more bottles of beer.")
    println("Go to the store and buy some more, 99 bottles of beer on the wall.")
}

func bottles(beer int) string {
    switch (beer) {
        case 0:
            return "no bottles"
        case 1:
            return "1 bottle"
    }

    return strconv.Itoa(beer) + " bottles"
}

99 бутылок: КуМир

47. КуМир — очередной неинтересный язык программирования «Комплект учебных Миров или Миры Кушниренко».

В 1995 году «КуМир» (о ужас!) был рекомендован Министерством образования РФ в качестве основного учебного материала по курсу «Основы информатики и вычислительной техники» на основе учебника А. Г. Кушниренко, Г. В. Лебедева и Р. А. Свореня.

Совершенно неинтересно про него рассказывать, если честно, хотя среда разработки очень неплоха в плане диагностики ошибок.

| написал Евгений Степанищев bolknote.ru

алг песня про пиво
нач
    цел пиво
    нц для пиво от 99 до 1 шаг -1
        вывод сколько пива(пиво), ' on the wall, ', нс
        вывод 'Take one and pass around,', нс
        вывод сколько пива(пиво-1), ' on the wall.', нс, нс
    кц
    вывод "No more bottles of beer...", нс
    вывод "Go to the store and buy some more...", нс
    вывод "99 bottles of beer."
кон

алг лит сколько пива(цел пиво)
нач
    если пиво = 0 то
        знач:="No"
    иначе
        знач:=цел_в_лит(пиво)
    все

    знач:=знач + ' bottle'

    если пиво <> 1 то
        знач:=знач+'s'
    все
кон

99 бутылок: gnuplot

46. gnuplot — программа для построение графиков, имеющая довольно развитый язык программирования. Основная особенность — отсутствие циклов, хотя доступна их эмуляция — через команду перезагрузки файла (reread).

Программа, выводящая песню о пиве (beer.gp)

# Написал Евгений Степанищев

bottles(beer) = beer == 1 ? '1 bottle' : beer ? sprintf('%d bottles', beer) : 'no bottles'

if (!exists("beer")) beer=99
print bottles(beer), " of beer on the wall, ", bottles(beer)," of beer\n",\
      "Take one and pass it around,"

beer=beer-1

print bottles(beer)," of beer on the wall.\n"

if (beer>0) reread

print "No more bottles of beer on the wall, no more bottles of beer.\n", \
"Go to the store and buy some more, 99 bottles of beer on the wall."
Ранее Ctrl + ↓