Как здорово было бы стать следующим миллионером AppStore? Очень круто! Но Swift и Rust для меня просто приятные слова. Мне ничего не говорят о кодировании. А Python страшен тем, что наверняка использует какой-то яд для работы :)

Я начал кодировать на BASIC, влюбился в TurboPascal и реализовал свои последние проекты кодирования на C ++. 20 лет назад. С тех пор самым близким к программированию я стал исправлять макросы Excel, записанные на VBA. Это безнадежно. Я никогда не стану миллионером в AppStore. Правильно?

В порядке. Я принимаю это и оставляю детям писать следующий блокбастер для Android и iOS. Но мне все еще не терпится написать код. Что я могу с этим поделать?

Привет, Юля!

Когда вселенная пытается доставить вас в новое место в жизни, она также посылает вам сигналы и сообщения. Так что неудивительно, что две явно неизведанные вещи поставили меня на колени за последние две недели.

Во-первых, рекомендательная машина YouTube показала мне видео, в котором рассказывается о том, как Джулия Лэнг - следующая замечательная вещь для специалистов по обработке данных и программистов на Python. Джулия - идеальное сочетание скорости и красоты программирования.

Во-вторых, я читаю книгу по физике / биологии о том, как живые существа, информационные потоки и квантовая физика каким-то образом взаимосвязаны. В этой книге есть отсылка к игре Conways Game of Life - автоматному алгоритму. Книга Пола Дэвиса называется Демон в машине.

Эй, может я и старая, но я все еще могу соединить две несвязанные друг с другом вещи! Итак, я решил написать «Игру жизни» в Джулии Лэнг.

Насколько это может быть сложно? Верно?

Из Википедии: Вселенная Игры Жизни представляет собой бесконечную двумерную ортогональную сетку из квадратных ячеек , каждая из которых находится в одном из двух возможных состояний, живые или мертвые , (или заселенные и незаселенные соответственно). Каждая ячейка взаимодействует со своими восемью соседями […]

Выживает любая живая клетка с двумя-тремя живыми соседями.

Любая мертвая клетка с тремя живыми соседями становится живой клеткой.

Все остальные живые клетки умирают в следующем поколении. Точно так же все другие мертвые клетки остаются мертвыми.

Будет легко построить матрицу, полную случайных нулей и единиц, прогнать ее несколько раз и изменить значения с 1 на 0 или с 0 на 1.

Итак, давай возьмем Джулию. Это действительно просто. Вы просто следуете правилам и настроены на успех. Я установил его как для своих записных книжек Anaconda, так и для своего текстового редактора Atom, потому что в Atom я не мог понять, в какой части окна мне нужно писать. Я говорил тебе; Я динозавр. Для Anaconda я использовал это пошаговое руководство от Data to Fish.

Вещи, которые я узнал, пытаясь кодировать игру жизни

1. Сообщения об ошибках в Julia загадочны и полезны.

Раньше отладка сводила меня с ума, потому что, как только код принимался компилятором, вы редко знали, с какой проблемой столкнулись, когда код приводил к нежелательному результату. Мне нужно было возиться с «точками останова» или «шаг за шагом» пройти программу. Юля другая. Он запускает код в большинстве случаев и останавливается при возникновении любых ошибок. И, поверьте, мой код произвел больше остановок, чем школьный автобус.

Что мне нравится в ошибках, так это то, что Джулия сообщает вам, в какой строке есть ошибка. Или, по крайней мере, там, где все перестало работать.

Разочаровывает то, что вы получаете множество загадочных, странных комментариев от компьютера. Это почти как пытаться читать между строк кода из «Матрицы» с Киану Ривзом.

Например, в поле ниже я знаю только, что сделал плохие вещи с методом разброса сетки. Наверное что-то к типам данных использовали? Или в диапазоны? Не знаю, но мне кажется, что компьютер пытается что-то объяснить на чужом языке.

e = MethodError(AbstractPlotting.convert_arguments, (AbstractPlotting.PointBased(), 0..1, 0..1, [0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]), 0x0000000000006a68)
    No overload for MeshScatter{...} and also no overload for trait AbstractPlotting.PointBased() found! Arguments:(IntervalSets.Interval{:closed,:closed,Int64}, IntervalSets.Interval{:closed,:closed,Int64}, Array{Int64,2})
    
    Stacktrace:
    [1] error(::String) at ./error.jl:33
    [2] convert_arguments(::Type{MeshScatter{...}}, ::IntervalSets.Interval{:closed,:closed,Int64}, ::Vararg{Any,N} where N; kw::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at/Users/myUserNameisHere/.julia/packages/AbstractPlotting/jOgYQ/src/conversions.jl:54
    [3] convert_arguments(::Type{MeshScatter{...}}, ::IntervalSets.Interval{:closed,:closed,Int64}, ::IntervalSets.Interval{:closed,:closed,Int64}, ::Array{Int64,2}) at/Users/myUserNameisHere/.julia/packages/AbstractPlotting/jOgYQ/src/conversions.jl:48
    [4] plot!(::Scene, ::Type{MeshScatter{...}}, ::Attributes, ::IntervalSets.Interval{:closed,:closed,Int64}, ::Vararg{Any,N} where N; kw_attributes::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at/Users/myUserNameisHere/.julia/packages/AbstractPlotting/jOgYQ/src/interfaces.jl:553
    [5] plot!(::Scene, ::Type{MeshScatter{...}}, ::Attributes, ::IntervalSets.Interval{:closed,:closed,Int64}, ::IntervalSets.Interval{:closed,:closed,Int64}, ::Array{Int64,2}) at/Users/myUserNameisHere/.julia/packages/AbstractPlotting/jOgYQ/src/interfaces.jl:540
    [6] meshscatter(::IntervalSets.Interval{:closed,:closed,Int64}, ::Vararg{Any,N} where N; attributes::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:limits, :marker, :markersize, :light, :color),Tuple{GeometryBasics.HyperRectangle{3,Float32},GeometryBasics.HyperRectangle{3,Float32},Array{Vec{3,Float32},1},Array{Vec{3,Float32},1},Array{Float64,1}}}}) at /Users/myUserNameisHere/.julia/packages/AbstractPlotting/jOgYQ/src/recipes.jl:15
    [7] top-level scope at In[15]:53

2. Юля похожа на мебель ИКЕА. Сборка своими руками.

Когда у меня, наконец, был запущен базовый код и я правильно все рассчитал, я захотел увидеть доску моей Игры Жизни. Но Юля не умела рисовать. Я зашел в Интернет и установил Makie, программу, которая подключается к Джулии и учит ее рисовать.

Для моего мозга динозавра это в основном концепция «единиц» из Паскаля. Единственная большая разница в том, что кодировщику необходимо установить его, прежде чем «использовать» в Юлии. Тот факт, что вам также нужно выбрать, какую часть пазла загружать, усложняет задачу. Маки лучше, чем Сюжеты? Какой я использую? Я вижу старый пост, где планировалось объединить два «юнита». Они слились? Все эти простые и детские вопросы пришли мне в голову до того, как я установил Makie, который работает прилично. Но Маки также отлично справляется с выводом загадочных сообщений об ошибках, даже когда я пытаюсь запустить код из официального репозитория примеров.

3. Юля сначала тормозит

Когда я впервые запустил первую успешную итерацию кода, я провел вычисления для 10 массивов по 100 элементов в каждом. Для конкретности: у меня была доска 10х10 с автоматами и рандом 10 поколений. Я нажал «запустить» и подождал около 5 секунд, пока что-то не произойдет.

Мой код на Паскале работал быстрее! Это та скорость, о которой они говорили?

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

4. Индексирование 2D-массивов - это странно.

Что меня больше всего озадачило, так это то, как Джулия приняла мои ссылки на отдельные элементы в 2D-массиве для моей платы.

В моей юности как динозавра доступ к элементу 2D-матрицы выполнялся как

NameofMatrix [строка, столбец] {или аналогичный}

Но Джулия приняла только новую форму индексации (по крайней мере, новую для меня), где первый элемент в верхнем левом углу матрицы - это элемент 1, а нижний правый элемент - это элемент [rows x columns] th.

Возьмем матрицу 3x3:

MatrixName = 
[10 11 12
 13 14 15
 16 17 18]

Чтобы сказать Джулии изменить средний элемент MatrixName с 14 на 41, вам нужно написать

​
 MatrixName[5]=41

Раньше это было бы что-то вроде

MatrixName[2,2]=41 {or [1,1] for posh languages which start at 0’}

В документации Джулии признается «декартово индексирование», но я понятия не имею, что мне нужно сделать, чтобы он заработал.

5. Выучить Юлию непросто, потому что…

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

Документация обычно выглядит так:

Функция X делает это. Вот пример. Это аргументы.

На кривую обучения также влияет тот факт, что в сообществе Джулии полно специалистов по данным, покидающих Python и Matlab. У всех есть опыт работы с «современными» языками программирования, а у динозавров - нет.

Итак, давайте посмотрим код

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

Последний рабочий код - это

using Makie
using AbstractPlotting
println(“How many generations would you like to see?”)
g=parse(Int,readline())
#readline() reads the keyboard and parse(Int,variable/value) transforms it into an integer
println(“How many columns /rows would you like to see?”)
size=parse(Int,readline())
Life =round.(rand(size,size))
Life=[zeros(size)’;Life;zeros(size)’]
Life=[zeros(size+2) Life zeros(size+2)]
scena=heatmap!(Life,colormap=:binary)
st = Stepper(scena, “generation”)
step!(st)
function generation(Lifein)
 #initialize
 NewLifein=zeros(size+2,size+2)
 #Loops to apply conway’s rules
 for colJump in size+4:size+2:(size+2)*(size+2)-(size+2)-size
 for rowWalk in 0:size-1
 i=colJump+rowWalk
 sum=0
 sum=Lifein[i-8]+Lifein[i+8]+Lifein[i+7]+Lifein[i-7]+Lifein[i+6]+Lifein[i-6]+Lifein[i-1]+Lifein[i+1]
 if Lifein[i]==1.0&&1<sum<4 
 NewLifein[i]=1.0
 elseif Lifein[i]==0&&sum==3.0 
 NewLifein[i]=1.0
 end
 
 end
 end
 return NewLifein 
end
for counter in 1:g
 Life=generation(Life) #this generates new generation
 scena.clear #this clears the board
 scena=heatmap!(Life,colormap=:binary) # this generates new picture
 scena.strokewidth=20
 step!(st) # this saves new picture with increment name
end