Самая короткая игра жизни


59

Игра жизни Конвея - классический пример клеточной автоматизации. Ячейки образуют квадратную сетку, и у каждого есть два состояния: живое или мертвое. На каждом ходу каждая ячейка одновременно обновляется в соответствии со своим состоянием и состоянием своих восьми соседей:

  • Живая клетка остается живой, если у нее ровно два или три живых соседа
  • Мертвая клетка становится живой, если у нее ровно три живых соседа

Ваша миссия, если вы решите принять ее, - написать самую короткую реализацию Game of Life на вашем любимом языке.

Правила:

  • Сетка должна быть не менее 20х20
  • Сетка должна обернуться вокруг (чтобы сетка была похожа на поверхность Тора)
  • Ваша реализация должна позволять пользователю вводить свои собственные стартовые шаблоны
  • GoL немного бессмысленно, если вы не видите, что происходит, поэтому должен быть визуальный вывод работающего автомата, причем результат каждого хода показывается достаточно долго, чтобы его можно было увидеть!

8
Ранее о переполнении стека: Code Golf: игра жизни Конвея , и обязательно посмотрите ссылку на реализацию APL в комментариях.
dmckee

1
Ах, я этого не видел. Но это немного отличается, нет (спасите меня, удалив работу, соединяющую проблему?
Гриффин

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

@ Гриффин: Вы можете удалить все эти ;до }с. Также vars может быть исключен время от времени (если это не нарушает ваш код). А для однострочных forс, ifs и т.д., вы можете устранить { }полностью: for(...) for(...) dosomething().
pimvdb

@pimvdb, ура, я еще не полностью играл в гольф, не было времени. просто хотел показать, что у меня тоже есть шанс, а не бездельничать, бросая вызов. Будет ли это гольф по максимуму в ближайшее время.
Гриффин

Ответы:


27

HTML5 Canvas с JavaScript, 940 639 586 519 символов

<html><body onload="k=40;g=10;b=[];setInterval(function(){c=[];for(y=k*k;y--;){n=0;for(f=9;f--;)n+=b[(~~(y/k)+k+f%3-1)%k*k+(y+k+~~(f/3)-1)%k];c[y]=n==3||n-b[y]==3;r.fillStyle=b[y]?'red':'tan';r.fillRect(y%k*g,~~(y/k)*g,g-1,g-1)}if(v.nextSibling.checked)b=c},1);v=document.body.firstChild;v.width=v.height=g*k;v.addEventListener('click',function(e){b[~~((e.pageY-v.offsetTop)/g)*k+~~((e.pageX-v.offsetLeft)/g)]^=1},0);r=v.getContext('2d');for(y=k*k;y--;)b[y]=0"><canvas></canvas><input type="checkbox"/>Run</body></html>

Я всегда хотел что-то сделать с помощью canvas, поэтому вот моя попытка (оригинальная версия онлайн ). Вы можете переключать ячейки, нажимая (также возможно в рабочем режиме).

Теперь вы также можете попробовать новую версию здесь .

К сожалению, есть проблема, с которой я еще не мог обойтись. Онлайн-версия на 11 символов длиннее, потому что jsFiddle помещает текстовый узел непосредственно перед холстом (почему?) И, таким образом, холст больше не является первым дочерним элементом.

Редактировать 1: много оптимизаций и реструктуризации.

Редактировать 2: Несколько небольших изменений.

Редактировать 3: встроенный полный блок скрипта плюс незначительные изменения.


Хорошо, но измените задержку интервала так, чтобы 1она была такой же быстрой, как моя, а не медленным шагом. Также, если вы хотите реализовать рисование (вместо того, чтобы нажимать на каждый квадрат), вы можете округлить положение мыши до ближайшего размера блока и заполнить прямоугольник в этой точке. Больше персонажей, но больше очков.
Гриффин

Вы можете заменить new Array('#FFF','#800')на ['#FFF','#800'].
Lowjacker

Хотя я и говорю об рисовании, мой супер-гольф не позволяет рисовать и безобразен как грех. Ха - ха. Вы можете установить два цвета в sмассиве, tanи redтак как они являются двумя цветами с кратчайшими представлениями - экономит два символа. Также, если возможно, поместите буквенную версию jв интервал. Я уверен, что есть еще много, чтобы выжать тоже.
Гриффин

@ Гриффин и Лоуджеккер: большое спасибо. Я также уверен, что вы можете играть в гольф намного больше (и у вас уже есть некоторые идеи). К сожалению, я не нашел времени для этого. Завтра появится лучшая версия игры в гольф - надеюсь ...
Говард

2
Вы можете удалить теги html и body. Он будет функционировать так же
arodebaugh

32

Питон, 219 символов

Я пошел на максимальный гольф, с достаточно интерфейсом, чтобы удовлетворить вопрос.

import time
P=input()
N=range(20)
while 1:
 for i in N:print''.join(' *'[i*20+j in P]for j in N)
 time.sleep(.1);Q=[(p+d)%400 for d in(-21,-20,-19,-1,1,19,20,21)for p in P];P=set(p for p in Q if 2-(p in P)<Q.count(p)<4)

Вы запускаете это так:

echo "[8,29,47,48,49]" | ./life.py

Числа в списке представляют координаты начальных ячеек. Первый ряд 0-19, второй ряд 20-39 и т. Д.

Запустите его в терминале с 21 строкой, и это выглядит довольно привлекательно.


1
Это полностью должно было победить. Я полагаю, «легкость ввода» была достаточно высокой.
Примо

@ primo Я бы даже сказал, что у ммы должен быть отдельный конкурс.
Люсер Дрог

2
Так что же это за Жизнь Пи?
Кристофер Вирт

Вы всегда можете сохранить еще один символ ... 2-(p in P)== 2-({p}<P). Но тогда вам придется изменить свой ввод на {8,29,47,48,49}:)
JBernardo

21

TI-BASIC, 96 байт (87 для неконкурентной записи)

Для вашего графического калькулятора серии TI-84 (!). Это было довольно сложной задачей, так как не существует простой способ , чтобы написать буферную графическую рутину (определенно ничего не встроенное), и на экране графика имеет только четыре соответствующих графические команды: Pxl-On(), Pxl-Off(), Pxl-Change(), и pxl-Test().

Использует каждый доступный пиксель на экране и корректно переносится. Каждая ячейка составляет один пиксель, и программа обновляет построчно по горизонтали вправо по экрану. Поскольку в калькуляторах используется только процессор Z80 с частотой 15 МГц, а BASIC - это медленный интерпретируемый язык, код получает только один кадр каждые пять минут.

Пользовательский ввод очень прост: перед запуском программы используйте инструмент «Перо», чтобы нарисовать фигуру на экране графика.

Адаптировано из моей заявки на участие в соревновании по коду в гольф на форуме калькулятора Omnimaga .

0
While 1
For(X,0,94
Ans/7+49seq(pxl-Test(remainder(Y,63),remainder(X+1,95)),Y,62,123
For(Y,0,62
If 1=pxl-Test(Y,X)+int(3fPart(3cosh(fPart(6ֿ¹iPart(sum(Ans,Y+1,Y+3
Pxl-Change(Y,X
End
End
End

Версия Omnimaga (87 байт)

Этот код имеет дополнительную функцию: он определяет, запускается ли он в первый раз, и случайным образом ли отображает состояние экрана. При последующих запусках он автоматически продолжает симуляцию, если остановлен после завершения кадра. Тем не менее, это не конкурирующая запись, потому что она не переносит экран; ячейки на внешней границе всегда будут считаться мертвыми, если предварительно очистить экран графика.

0
While 1
For(X,0,93
Ans/7+49seq(pxl-Test(Y,X+1),Y,0,62
For(Y,1,61
If 2rand>isClockOn=pxl-Test(Y,X)+int(3fPart(3cosh(fPart(6ֿ¹iPart(sum(Ans,Y,Y+2
Pxl-Change(Y,X
End
End
ClockOff
End

Эта версия, пожалуй, самый удачный код из всех, что я когда-либо писал, и содержит некоторые по-настоящему противные и запутанные оптимизации:

  • Я использую состояние часов в качестве флага. При запуске программы часы даты / времени включены, и я использую значение глобального флага isClockOn, чтобы определить, является ли это первой итерацией. После того, как первый кадр нарисован, я выключаю часы. Сохраняет один байт по кратчайшему другому методу и около четырех по очевидному методу.

  • Я сохраняю состояния трех столбцов рядом с обновляемым в массиве из 63 элементов, состоящем из 7 цифр. 49-е место содержит столбец справа, 7-е место - средний столбец, а единица измерения - левый столбец - 1 для живой ячейки и 0 для мертвой ячейки. Затем я беру оставшийся мод 6 от суммы трех чисел вокруг модифицируемой ячейки, чтобы найти общее количество живых соседних ячеек (это как деление на 9 трюков - в базе 7, оставшийся мод 6 равен сумме цифры). Сохраняет около 10 байтов отдельно и дает возможность использовать следующие две оптимизации. Пример диаграммы (скажем, есть планер с центром в некотором столбце при Y = 45:

    Row # | Cell State       | Stored number | Mod 6 = cell count
    ...
    44      Live, Live, Live   49+7+1 = 57     3
    45      Dead, Dead, Live   49+0+0 = 49     1
    46      Dead, Live, Dead   0+7+0  = 7      1
    ...
    

    Центральная клетка останется мертвой, потому что она окружена ровно пятью живыми клетками.

  • После завершения каждой строки числа в массиве обновляются путем деления существующих чисел на 7, отбрасывания десятичной части и добавления 49-кратного значения ячеек в новом столбце. Хранение всех трех столбцов каждый раз будет гораздо медленнее и менее изящным, займет не менее 20 байтов и будет использовать три списка, а не один, потому что значения ячеек в каждой строке должны храниться до обновления ячеек. На сегодняшний день это самый маленький способ хранения позиций в ячейках.

  • Фрагмент int(3fPart(3cosh(дает, 1когда входное значение равно 3/6, 2когда оно равно 4/6 и 0когда оно равно 0, 1/6, 2/6 или 5/6. Сохраняет около 6 байтов.


19

Mathematica - 333

Функции:

  • Интерактивный интерфейс: нажмите на ячейки, чтобы сделать ваши шаблоны

  • Хорошая сетка

  • Кнопки: RUN, PAUSE, CLEAR

Код ниже.

Manipulate[x=Switch[run,1,x,2,CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},{2,2,2}}},
{1,1}},x],3,Table[0,{k,40},{j,40}]];EventHandler[Dynamic[tds=Reverse[Transpose[x]];
ArrayPlot[tds,Mesh->True]],{"MouseClicked":>(pos=Ceiling[MousePosition["Graphics"]];
x=ReplacePart[x,pos->1-x[[Sequence@@pos]]];)}],{{run,3,""},{1->"||",2->">",3->"X"}}]

введите описание изображения здесь

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


2
+1, хороший, чтобы пойти. Да, это проблема с этим сайтом, есть тонны старых вопросов, которые можно пропустить.
Гриффин

@Griffin спасибо, что вообще это заметили;)
Виталий Кауров

15

C 1063 символов

В качестве проблемы я сделал это в C, используя недружественный к гольфу Windows API для ввода-вывода в реальном времени. Если capslock включен, симуляция будет запущена. Он останется на месте, если выключен колпачок. Рисовать узоры с помощью мыши; щелчок левой кнопкой мыши оживляет ячейки, а щелчок правой кнопкой мыши убивает ячейки.

#include <windows.h>
#include<process.h>
#define K ][(x+80)%20+(y+80)%20*20]
#define H R.Event.MouseEvent.dwMousePosition
#define J R.Event.MouseEvent.dwButtonState
HANDLE Q,W;char*E[3],O;Y(x,y){return E[0 K;}U(x,y,l,v){E[l K=v;}I(){E[2]=E[1];E[1]=*E;*E=E[2];memset(E[1],0,400);}A(i,j,k,l,P){while(1){Sleep(16);for(i=0;i<20;++i)for(j=0;j<20;++j){COORD a={i,j};SetConsoleCursorPosition(Q,a);putchar(E[0][i+j*20]==1?'0':' ');}if(O){for(i=0;i<20;++i)for(j=0;j<20;++j){for(k=i-1,P=0;k<i+2;++k)for(l=j-1;l<j+2;++l){P+=Y(k,l);}U(i,j,1,P==3?1:Y(i,j)==1&&P==4?1:0);}I();}}}main(T,x,y,F,D){for(x=0;x<21;++x)puts("#####################");E[0]=malloc(800);E[1]=E[0]+400;I();I();W=GetStdHandle(-10);Q=GetStdHandle(-11);SetConsoleMode(W,24);INPUT_RECORD R;F=D=O=0;COORD size={80,25};SetConsoleScreenBufferSize(Q,size);_beginthread(A,99,0);while(1){ReadConsoleInput(W,&R,1,&T);switch(R.EventType){case 1:O=R.Event.KeyEvent.dwControlKeyState&128;break;case 2:switch(R.Event.MouseEvent.dwEventFlags){case 1:x=H.X;y=H.Y;case 0:F=J&1;D=J&2;}if(F)U(x,y,0,1);if(D)U(x,y,0,0);}}}

Скомпилированный EXE можно найти здесь

Изменить: я прокомментировал источник. Это доступно здесь


Я хотел бы видеть прокомментированную версию этого!
luser droog 21.12.12

1
Конечно, если я могу вспомнить, о чем я думал ... = p
Kaslai 22.12.12

1
@luserdroog Вот это pastebin.com/BrX6wgUj
Каслай

Это просто потрясающе.
rayryeng - Восстановить Монику

12

J (39 символов)

l=:[:+/(3 4=/[:+/(,/,"0/~i:1)|.])*.1,:]

На основе этой версии APL (тот же алгоритм, тороидальная свертка).

Пример использования:

   r =: (i.3 3) e. 1 2 3 5 8
   r
0 1 1          NB. A glider!
1 0 1
0 0 1

   R =: _1 _2 |. 5 7 {. r
   R
0 0 0 0 0 0 0  NB. Test board
0 0 0 1 1 0 0
0 0 1 0 1 0 0
0 0 0 0 1 0 0
0 0 0 0 0 0 0

   l R
0 0 0 0 0 0 0  NB. Single step
0 0 0 1 1 0 0
0 0 0 0 1 1 0
0 0 0 1 0 0 0
0 0 0 0 0 0 0

10

Mathematica, 123 символа

Очень элементарная реализация, в которой не используется встроенная в Mathematica функция CellularAutomaton.

ListAnimate@NestList[ImageFilter[If[3<=Total@Flatten@#<=3+#[[2]][[2]],1,0]&,#,1]&,Image[Round/@RandomReal[1,{200,200}]],99]

8

Ruby 1.9 + SDL (380 325 314)

РЕДАКТИРОВАТЬ : 314 символов, и исправлена ​​ошибка с появлением дополнительных клеток в первой итерации. Увеличен размер сетки до 56, поскольку подпрограмма цвета смотрит только на младшие 8 бит.

РЕДАКТИРОВАТЬ : Гольф до 325 символов. Ширина / высота сетки теперь составляет 28, поскольку 28 * 9 - это наибольшее значение, которое вы можете иметь, но при этом значение используется в качестве цвета фона. Он также обрабатывает только одно событие SDL за каждую итерацию, что полностью устраняет внутренний цикл. Я думаю, довольно туго!

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

Упаковка немного шаткая.

require'sdl'
SDL.init W=56
R=0..T=W*W
b=[]
s=SDL::Screen.open S=W*9,S,0,0
loop{r="#{e=SDL::Event.poll}"
r['yU']?$_^=1:r[?Q]?exit: r['nU']?b[e.y/9*W+e.x/9]^=1:0
b=R.map{|i|v=[~W,-W,-55,-1,1,55,W,57].select{|f|b[(i+f)%T]}.size;v==3||v==2&&b[i]}if$_
R.map{|i|s.fillRect i%W*9,i/W*9,9,9,[b[i]?0:S]*3}
s.flip
sleep 0.1}

Выглядит так:

Снимок экрана приложения в действии

Веселый вызов! Я приветствую любые улучшения, которые кто-либо может увидеть.


Хорошая попытка, но я сразу вижу, что ты ошибся. Вы не можете иметь такой шаблон в GoL. Еще раз прочитайте правила: en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules
Гриффин

@ Гриффин Я думаю, что снимок экрана был сделан после того, как я сделал паузу и переключил некоторые ячейки вручную - хотя я проверю правила еще раз. Спасибо!
Пол Престиж

7
@ Гриффин не может быть шаблон семени в любой возможной конфигурации?
ardnew

7

Scala, 1181 1158 1128 1063 1018 1003 999 992 987 знаков

import swing._
import event._
object L extends SimpleSwingApplication{import java.awt.event._
import javax.swing._
var(w,h,c,d,r)=(20,20,20,0,false)
var x=Array.fill(w,h)(0)
def n(y:Int,z:Int)=for(b<-z-1 to z+1;a<-y-1 to y+1 if(!(a==y&&b==z)))d+=x((a+w)%w)((b+h)%h)
def top=new MainFrame with ActionListener{preferredSize=new Dimension(500,500)
menuBar=new MenuBar{contents+=new Menu("C"){contents+={new MenuItem("Go/Stop"){listenTo(this)
reactions+={case ButtonClicked(c)=>r= !r}}}}}
contents=new Component{listenTo(mouse.clicks)
reactions+={case e:MouseClicked=>var p=e.point
x(p.x/c)(p.y/c)^=1
repaint}
override def paint(g:Graphics2D){for(j<-0 to h-1;i<-0 to w-1){var r=new Rectangle(i*c,j*c,c,c)
x(i)(j)match{case 0=>g draw r
case 1=>g fill r}}}}
def actionPerformed(e:ActionEvent){if(r){var t=x.map(_.clone)
for(j<-0 to h-1;i<-0 to w-1){d=0
n(i,j)
x(i)(j)match{case 0=>if(d==3)t(i)(j)=1
case 1=>if(d<2||d>3)t(i)(j)=0}}
x=t.map(_.clone)
repaint}}
val t=new Timer(200,this)
t.start}}

Ungolfed:

import swing._
import event._

object Life extends SimpleSwingApplication
{
    import java.awt.event._
    import javax.swing._
    var(w,h,c,d,run)=(20,20,20,0,false)
    var x=Array.fill(w,h)(0)
    def n(y:Int,z:Int)=for(b<-z-1 to z+1;a<-y-1 to y+1 if(!(a==y&&b==z)))d+=x((a+w)%w)((b+h)%h)
    def top=new MainFrame with ActionListener
    {
        title="Life"
        preferredSize=new Dimension(500,500)
        menuBar=new MenuBar
        {
            contents+=new Menu("Control")
            {
                contents+={new MenuItem("Start/Stop")
                {
                    listenTo(this)
                    reactions+=
                    {
                        case ButtonClicked(c)=>run= !run
                    }
                }}
            }
        }
        contents=new Component
        {
            listenTo(mouse.clicks)
            reactions+=
            {
                case e:MouseClicked=>
                    var p=e.point
                    if(p.x<w*c)
                    {
                        x(p.x/c)(p.y/c)^=1
                        repaint
                    }
            }
            override def paint(g:Graphics2D)
            {
                for(j<-0 to h-1;i<-0 to w-1)
                {
                    var r=new Rectangle(i*c,j*c,c,c)
                    x(i)(j) match
                    {
                        case 0=>g draw r
                        case 1=>g fill r
                    }
                }
            }
        }
        def actionPerformed(e:ActionEvent)
        {
            if(run)
            {
                var t=x.map(_.clone)
                for(j<-0 to h-1;i<-0 to w-1)
                {
                    d=0
                    n(i,j)
                    x(i)(j) match
                    {
                        case 0=>if(d==3)t(i)(j)=1
                        case 1=>if(d<2||d>3)t(i)(j)=0
                    }
                }
                x=t.map(_.clone)
                repaint
            }
        }
        val timer=new Timer(200,this)
        timer.start
    }
}

Большая часть кода здесь - это Swing GUI. Сама игра заключается в actionPerformedметоде, который вызывается Timerвспомогательной функцией и nподсчетом соседей.

Использование:

Скомпилируйте его, scalac filenameа затем запустите scala L.
Щелчок по квадрату переворачивает его с живого на мертвый, и пункт меню запускает и останавливает игру. Если вы хотите изменить размер сетки, измените первые три значения в строке: var(w,h,c,d,r)=(20,20,20,0,false)это ширина, высота и размер ячейки (в пикселях) соответственно.


Я нашел 2 гольф-улучшения: import java.awt.event._и contents+=m("Go",true)+=m("Stop",false)}}, что приводит к 1093 символов.
пользователь неизвестен

@ пользователь неизвестен Спасибо. Я нашел несколько улучшений сам - до 1063 сейчас.
Гарет

Черт, ты был занят. Так держать! Я буду проверять ответы, когда их опубликуют еще несколько человек.
Гриффин

7

Чистый Баш, 244 байта

Работает в тороидальной оболочке 36x24:

mapfile a
for e in {0..863};{
for i in {0..8};{
[ "${a[(e/36+i/3-1)%24]:(e+i%3-1)%36:1}" == O ]&&((n++))
}
d=\ 
c=${a[e/36]:e%36:1}
[ "$c" == O ]&&((--n==2))&&d=O
((n-3))||d=O
b[e/36]+=$d
n=
}
printf -vo %s\\n "${b[@]}"
echo "$o"
exec $0<<<"$o"

Поскольку это сценарий оболочки, метод ввода совпадает с другими командами оболочки, то есть из stdin:

$ ./conway.sh << EOF

   O 
    O 
  OOO 

EOF


  O O                                                       
   OO                                                       
   O                                                        

















    O                                                       
  O O                                                       
   OO                                                       

... и т.д

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

man tr | tr [:alnum:] O | ./conway.sh

6

JavaScript, 130

Не полностью отвечая на вызов, но для записи, вот движок Game of Life в 130 байтов, сделанный Subzey и мной в 2013 году.

http://xem.github.io/miniGameOfLife/

/* Fill an array with 0's and 1's, and call g(array, width, height) to iterate */
g=function(f,c,g,d,e,b,h){g=[];e=[c+1,c,c-1,1];for(b=c*c;b--;g[b]=3==d||f[b]&&2==d,d=0)for(h in e)d+=f[b+e[h]]+f[b-e[h]];return g}

Похоже, у этого есть некоторые проблемы с первым рядом. Например, настройка @@\n@@(2 на 2 квадрата в верхнем левом углу) или .@\n.@\n.@. (1 на 3 столбца)
Аннан

5

C # - 675 символов

Я всегда хотел написать версию этой программы. Никогда не знал, что это займет всего полчаса для быстрой и грязной версии. (Гольф, конечно, занимает гораздо больше времени.)

using System.Windows.Forms;class G:Form{static void Main(){new G(25).ShowDialog();}
public G(int z){var g=new Panel[z,z];var n=new int [z,z];int x,y,t;for(int i=0;i<z;
i++)for(int j=0;j<z;j++){var p=new Panel{Width=9,Height=9,Left=i*9,Top=j*9,BackColor
=System.Drawing.Color.Tan};p.Click+=(s,a)=>p.Visible=!p.Visible;Controls.Add(g[i,j]=
p);}KeyUp+=(s,_)=>{for(int i=0;i<99;i++){for(x=0;x<z;x++)for(y=0;y<z;y++){t=0;for(int 
c=-1;c<2;c++)for(int d=-1;d<2;d++)if(c!=0||d!=0){int a=x+c,b=y+d;a=a<0?24:a>24?0:a;b=
b<0?24:b>24?0:b;t+=g[a,b].Visible?0:1;}if(t==3||t>1&&!g[x,y].Visible)n[x,y]=1;if(t<2
||t>3)n[x,y]=0;}for(x=0;x<z;x++)for(y=0;y<z;y++)g[x,y].Visible=n[x,y]<1;Update();}};}}

использование

  • Введите начальный шаблон, щелкая ячейки, чтобы включить их (вживую).
  • Запустите игру, нажав любую клавишу клавиатуры.
  • Игра запускается 99 поколений каждый раз, когда нажимается клавиша (я мог бы сделать 9, чтобы сохранить символ, но это выглядело слишком неубедительно).

Гольф компромиссы

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

5

GW-BASIC, 1086 1035 байт (токенизирован)

В токенизированной форме это 1035 байтов. (Форма ASCII, конечно, немного длиннее.) Вы получаете токенизированную форму, используя SAVE"lifeкоманду без добавления ",aв интерпретатор.

10 DEFINT A-Z:DEF SEG=&HB800:KEY OFF:COLOR 7,0:CLS:DEF FNP(X,Y)=PEEK((((Y+25)MOD 25)*80+((X+80)MOD 80))*2)
20 X=0:Y=0
30 LOCATE Y+1,X+1,1
40 S$=INKEY$:IF S$=""GOTO 40
50 IF S$=CHR$(13)GOTO 150
60 IF S$=" "GOTO 130
70 IF S$=CHR$(0)+CHR$(&H48)THEN Y=(Y-1+25)MOD 25:GOTO 30
80 IF S$=CHR$(0)+CHR$(&H50)THEN Y=(Y+1)MOD 25:GOTO 30
90 IF S$=CHR$(0)+CHR$(&H4B)THEN X=(X-1+80)MOD 80:GOTO 30
100 IF S$=CHR$(0)+CHR$(&H4D)THEN X=(X+1)MOD 80:GOTO 30
110 IF S$="c"THEN CLS:GOTO 20
120 GOTO 40
130 Z=PEEK((Y*80+X)*2):IF Z=42 THEN Z=32ELSE Z=42
140 POKE(Y*80+X)*2,Z:GOTO 40
150 LOCATE 1,1,0:ON KEY(1)GOSUB 320:KEY(1) ON
160 V!=TIMER+.5:FOR Y=0 TO 24:FOR X=0 TO 79:N=0
170 Z=FNP(X-1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
180 Z=FNP(X,Y-1):IF Z=42 OR Z=46 THEN N=N+1
190 Z=FNP(X+1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
200 Z=FNP(X-1,Y):IF Z=42 OR Z=46 THEN N=N+1
210 Z=FNP(X+1,Y):IF Z=42 OR Z=46 THEN N=N+1
220 Z=FNP(X-1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
230 Z=FNP(X,Y+1):IF Z=42 OR Z=46 THEN N=N+1
240 Z=FNP(X+1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
250 Z=PEEK((Y*80+X)*2):IF Z=32 THEN IF N=3 THEN Z=43
260 IF Z=42 THEN IF N<2 OR N>3 THEN Z=46
270 POKE(Y*80+X)*2,Z:NEXT:NEXT:FOR Y=0 TO 24:FOR X=0 TO 79:Z=PEEK((Y*80+X)*2):IF Z=46 THEN Z=32
280 IF Z=43 THEN Z=42
290 POKE(Y*80+X)*2,Z:NEXT:NEXT
300 IF TIMER<V!GOTO 300
310 IF INKEY$=""GOTO 160
320 SYSTEM

Это максимальная версия для игры в гольф, но она по-прежнему интересна: при запуске вы получаете редактор, в котором вы можете перемещаться с помощью клавиш курсора; пробел включает / выключает бактерии на текущем поле, cочищает экран, Return запускает режим игры.

Ниже следует менее запутанная версия, которая также устанавливает начальную игровую доску с двумя структурами (вращающаяся по кругу вещь и планер):

1000 REM Conway's Game of Life
1001 REM -
1002 REM Copyright (c) 2012 Thorsten "mirabilos" Glaser
1003 REM All rights reserved. Published under The MirOS Licence.
1004 REM -
1005 DEFINT A-Z:DEF SEG=&hB800
1006 KEY OFF:COLOR 7,0:CLS
1007 DEF FNP(X,Y)=PEEK((((Y+25) MOD 25)*80+((X+80) MOD 80))*2)
1010 PRINT "Initial setting mode, press SPACE to toggle, RETURN to continue"
1020 PRINT "Press C to clear the board, R to reset. OK? Press a key then."
1030 WHILE INKEY$="":WEND
1050 CLS
1065 DATA 3,3,4,3,5,3,6,3,7,3,8,3,3,4,4,4,5,4,6,4,7,4,8,4
1066 DATA 10,3,10,4,10,5,10,6,10,7,10,8,11,3,11,4,11,5,11,6,11,7,11,8
1067 DATA 11,10,10,10,9,10,8,10,7,10,6,10,11,11,10,11,9,11,8,11,7,11,6,11
1068 DATA 4,11,4,10,4,9,4,8,4,7,4,6,3,11,3,10,3,9,3,8,3,7,3,6
1069 DATA 21,0,22,1,22,2,21,2,20,2,-1,-1
1070 RESTORE 1065
1080 READ X,Y
1090 IF X=-1 GOTO 1120
1100 POKE (Y*80+X)*2,42
1110 GOTO 1080
1120 X=0:Y=0
1125 LOCATE Y+1,X+1,1
1130 S$=INKEY$
1140 IF S$="" GOTO 1130
1150 IF S$=CHR$(13) GOTO 1804
1160 IF S$=" " GOTO 1240
1170 IF S$=CHR$(0)+CHR$(&h48) THEN Y=(Y-1+25) MOD 25:GOTO 1125
1180 IF S$=CHR$(0)+CHR$(&h50) THEN Y=(Y+1) MOD 25:GOTO 1125
1190 IF S$=CHR$(0)+CHR$(&h4B) THEN X=(X-1+80) MOD 80:GOTO 1125
1200 IF S$=CHR$(0)+CHR$(&h4D) THEN X=(X+1) MOD 80:GOTO 1125
1210 IF S$="c" THEN CLS:GOTO 1120
1220 IF S$="r" GOTO 1050
1225 IF S$=CHR$(27) THEN END
1230 GOTO 1130
1240 Z=PEEK((Y*80+X)*2)
1250 IF Z=42 THEN Z=32 ELSE Z=42
1260 POKE (Y*80+X)*2,Z
1270 GOTO 1130
1804 LOCATE 1,1,0
1900 ON KEY(1) GOSUB 2300
1910 KEY(1) ON
2000 V!=TIMER+.5
2010 FOR Y=0 TO 24
2020  FOR X=0 TO 79
2030   N=0
2040   Z=FNP(X-1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2050   Z=FNP(X  ,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2060   Z=FNP(X+1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2070   Z=FNP(X-1,Y  ):IF Z=42 OR Z=46 THEN N=N+1
2080   Z=FNP(X+1,Y  ):IF Z=42 OR Z=46 THEN N=N+1
2090   Z=FNP(X-1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2100   Z=FNP(X  ,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2110   Z=FNP(X+1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2120   Z=PEEK((Y*80+X)*2)
2130   IF Z=32 THEN IF N=3 THEN Z=43
2140   IF Z=42 THEN IF N<2 OR N>3 THEN Z=46
2150   POKE (Y*80+X)*2,Z
2160  NEXT X
2170 NEXT Y
2200 FOR Y=0 TO 24
2210  FOR X=0 TO 79
2220   Z=PEEK((Y*80+X)*2)
2230   IF Z=46 THEN Z=32
2240   IF Z=43 THEN Z=42
2250   POKE (Y*80+X)*2,Z
2260  NEXT X
2270 NEXT Y
2280 IF TIMER<V! GOTO 2280
2290 IF INKEY$="" GOTO 2000
2300 SYSTEM

Я написал это за 15 минут, скучая и ожидая друга, который одновременно занимался игрой в гольф со своим «учеником» для «Игры жизни» Конвея.

Он работает следующим образом: он сразу использует экранный буфер текстового режима 80x25 (измените исходное значение, DEF SEGчтобы использовать его, &hB000если вы используете видеокарту Hercules; эти настройки работают с Qemu и (более медленным) dosbox). Звездочка *- это бактерия.

Он работает в два прохода: во-первых, места рождения помечены, +а смерть помечает цели .. Во втором проходе +и .заменяются на *и соответственно.

Дело в TIMERтом, чтобы заставить его ждать полсекунды после каждого раунда, если ваш хост Qemu работает очень быстро very

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


Учитывая, что вы увеличили свои метки на 1 для версии без гольфа, возможно ли сделать то же самое на версии для гольфа? (то есть 1, 2, 3и т.д.) Или номера строк не рассчитывать?
Захари

Номера строк, если они токенизированы, считаются словом (16 бит), если я не полностью ошибаюсь
mirabilos

Хорошо, тогда, наверное, я думал о каком-то другом БАЗОВОМ диалекте.
Захари

@ Zacharý Нажмите «Формат программы GW-BASIC tokenised», а затем «Формат программы» здесь, чтобы увидеть, что номера строк действительно составляют два байта, и для более подробной информации о формате токена.
Мирабилось

5

Mathematica, 115 байт

Вот легкая справка с этим:

ListAnimate[ArrayPlot/@CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},
{2,2,2}}},{1,1}},{RandomInteger[1,{9,9}],0},90]]

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

«Ввод» в Mathematica происходит главным образом через интерфейс ноутбука, поэтому я не думаю, что «взаимодействие с пользователем» действительно возможно. Вы просто заменяете аргумент RandomInteger на функцию CellularAutomaton чем угодно, и переоцениваете код.
JeremyKun

3
Возможно взаимодействие с пользователем. Самый простой способ, о котором я могу думать прямо сейчас, - это набор кнопок. Давай, мужик.
Гриффин

4

Java (OpenJDK 8) - 400 388 367 байт

Второе и (вероятно) заключительное редактирование: удалось найти в игре дополнительные 21 байт после обнаружения этих (imo) золотых приисков - определенно рекомендую новым людям прочитать их (особенно, если вы собираетесь попробовать некоторые из этих испытаний с использованием Java).

Результирующий код (вероятно, в конечном итоге закончится игрой в гольф, если я узнаю, как сократить эти двойные гнезда для петель ...):

u->{int w=u.length,h=u[0].length,x,y,i,j,n;Stack<Point>r=new Stack<Point>();for(;;){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x)for(y=0;y<h;++y){boolean o=u[x][y]>0;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]>0)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]+(y>h-2?"\n":""));}for(int[]t:u)Arrays.fill(t,0);}}

Попробуйте онлайн!

(Оригинальный пост начинается здесь.)

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

На самом деле в этом нет ничего особенного - базовое объяснение следующее (без присмотра):

/*
 * Explanation of each variable's usage:
 * w=height* of array
 * h=width* of array
 * x=y* coord of point in array
 * y=x* coord of point in array
 * i and j are counters for calculating the neighbours around a point in the array
 * n=neighbour counter
 * r=temporary array to store the cells from the current generation
 * u=the 2d array used for all the calculations (parameter from lambda expression)
 * c=temporary variable used to help populate the 2d array
 * o=boolean variable that stores the value of whether the cell is alive or not
 */
u-> // start of lambda statement with u as parameter (no need for brackets as it's only one parameter being passed)
{
    int w=u.length,h=u[0].length,x,y,i,j,n; // defines all the necessary integer variables;
    Stack<Point>r=new Stack<Point>(); // same with the only array list needed (note how I only use two data structures);
    for(;;) // notice how this is still an infinite loop but using a for loop;
    {
        for(Point c:r)u[c.x][c.y]=1; //for every point in the "previous" generation, add that to the 2D array as a live (evil?) cell;
        r.clear(); // clears the array list to be populated later on
        for(x=0;x<w;++x) // a pair of nested for loops to iterate over every cell of the 2D array;
        {
            for(y=0;y<h;++y)
            {
                // sets o to be the presence of a live cell at (x,y) then uses said value in initialising the neighbour counter;
                boolean o=u[x][y]>1;n=o?-1:0;
                for(i=-2;++i<2;) // another pair of nested for loops - this one iterates over a 3x3 grid around *each* cell of the 2D array;
                {                // this includes wrap-around (note the modulus sign in the if statement below);
                    for(j=-2;++j<2;)
                    {
                        if(u[(w+x+i)%w][(h+y+j)%h]>0)++n; // this is where the first interesting thing lies - the bit which makes wrap-around a reality;
                    }
                }
                if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y)); // this is the second interesting bit of my code - perhaps more so as I use bitwise operators to calculate the number of neighbours (x,y) has;
                                                            // (since I'm technically dealing with 0s and 1s, it's not a total misuse of them imo);
                System.out.print(u[x][y]+(y>h-2?"\n":""));  // that extra part of the print statement adds a newline if we reached the end of the current 'line';
            }
        }
        // since the information about the new generation is now in the array list, this array can be emptied out, ready to receive said info on the new generation;
        for(int[]t:u)Arrays.fill(t,0);
    }
} // end of lambda statement

(больше информации о лямбда-выражениях в Java 8 здесь )

Да, с моим подходом есть загвоздка.

Как многие из вас, вероятно, заметили, мой гольф-код в его нынешнем виде будет работать вечно. Чтобы предотвратить это, счетчик можно ввести сверху и использовать в цикле while, чтобы отображать n(в данном случае 5) итераций следующим образом (обратите внимание на bдобавленную новую переменную):

u->{int b=0,w=u.length,h=u[0].length,x,y,i,j,n;Stack<Point>r=new Stack<Point>();for(;++b<6;){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x)for(y=0;y<h;++y){boolean o=u[x][y]>0;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]>0)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]+(y>h-2?"\n":""));}for(int[]t:u)Arrays.fill(t,0);}}

Дополнительно стоит отметить несколько моментов. Эта программа не проверяет правильность ввода и, следовательно, потерпит неудачу с (скорее всего) an ArrayOutOfBoundsException; поэтому убедитесь, что входные данные действительны, полностью заполнив часть массива (асимметричные массивы вызовут исключение, упомянутое выше). Кроме того, плата в ее нынешнем виде выглядит «текучей», то есть нет разделения между одним поколением и следующим. Если вы хотите добавить это, чтобы еще раз проверить, действительно ли производимые поколения действительно действительны, System.out.println();нужно добавить еще один элемент for(int[]t:u)Arrays.fill(t,0);(см. Этот раздел «Попробуйте онлайн!» Для ясности). И наконец, что не менее важно, учитывая, что это мой первый кодовый гольф, любая обратная связь очень ценится :)

Старый код из предыдущего 388-байтового ответа:

u->{int w=u.length,h=u[0].length,x,y,i,j,n;ArrayList<Point>r=new ArrayList<Point>();while(true){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x){for(y=0;y<h;++y){boolean o=u[x][y]==1;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]==1)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]);}System.out.println();}for(int[]t:u)Arrays.fill(t,0);}}

И из первоначального 400-байтового ответа:

int w=35,h=20,x,y,i,j,n;ArrayList<Point>l=new ArrayList<Point>(),r;while(true){int[][]u=new int[w][h];for(Point c:l)u[c.x][c.y]=1;r=new ArrayList<Point>();for(x=0;x<w;++x){for(y=0;y<h;++y){boolean o=u[x][y]==1;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]==1)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]);}System.out.println();}l.clear();l.addAll(r);}

Удивительный первый пост, добро пожаловать в PPCG!
Захари

Спасибо, я определенно собираюсь делать больше из них - они забавные :)
NotBaal

Присоединяйтесь к нам, у нас есть Денис. Кроме того, это не полная программа и не функция, которой она должна быть, IIRC.
Захари

Ах да, забыл часть «программа»: P Немного отредактирую это.
NotBaal

Это может быть просто функция тоже.
Захари

4

Трафарет , 6 байтов

Не мой любимый язык, но это короткий ...

4 байта кода плюс флаги nlist и Torus.

3me

Попробуйте онлайн!

Является ли ...
3 3
 членом
m в м oore-окрестностях отсчета с себя или
e остромордыми й -окрестностями отсчетом без себя
...?


3

Скала - 799 символов

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

import java.awt.Color._
import swing._
import event._
import actors.Actor._
new SimpleSwingApplication{var(y,r,b)=(200,false,Array.fill(20,20)(false))
lazy val u=new Panel{actor{loop{if(r){b=Array.tabulate(20,20){(i,j)=>def^(i:Int)= -19*(i min 0)+(i max 0)%20
var(c,n,r)=(0,b(i)(j),-1 to 1)
for(x<-r;y<-r;if x!=0||y!=0){if(b(^(i+x))(^(j+y)))c+=1}
if(n&&(c<2||c>3))false else if(!n&&c==3)true else n}};repaint;Thread.sleep(y)}}
focusable=true
preferredSize=new Dimension(y,y)
listenTo(mouse.clicks,keys)
reactions+={case e:MouseClicked=>val(i,j)=(e.point.x/10,e.point.y/10);b(i)(j)= !b(i)(j)case _:KeyTyped=>r= !r}
override def paintComponent(g:Graphics2D){g.clearRect(0,0,y,y);g.setColor(red)
for(x<-0 to 19;y<-0 to 19 if b(x)(y))g.fillRect(x*10,y*10,9,9)}}
def top=new Frame{contents=u}}.main(null)

3

J, 45

Я думал, что попробую J. Пока еще не очень хорошо, но я попробую еще раз.

(]+.&(3&=)+)+/((4&{.,(_4&{.))(>,{,~<i:1))&|.

Пример:

   f =: 5 5 $ 0 1 0 0 0   0 0 1 0 0   1 1 1 0 0   0 0 0 0 0    0 0 0 0 0
   f
0 1 0 0 0
0 0 1 0 0
1 1 1 0 0
0 0 0 0 0
0 0 0 0 0
   f (]+.&(3&=)+)+/((4&{.,(_4&{.))(>,{,~<i:1))&|. f
0 0 0 0 0
1 0 1 0 0
0 1 1 0 0
0 1 0 0 0
0 0 0 0 0

3

Обработка 536 532

int h=22,t=24,i,j;int[][]w=new int[t][t],b=new int[t][t];int[]q={1,0,-1};void draw(){if(t<9){clear();for(i=2;i<h;i++){for(j=2;j<h;j++)w[i][j]=b[i][j];w[i][1]=w[i][21];w[i][h]=w[i][2];w[1][i]=w[21][i];w[h][i]=w[2][i];}for(i=1;i<23;i++)for(j=1;j<23;j++){t=-w[i][j];for(int s:q)for(int d:q)t+=w[i+s][j+d];b[i][j]=w[i][j]>0&(t<2|t>3)?0:t==3?1:b[i][j];}a();}}void keyPressed(){t=0;}void mousePressed(){int i=mouseX/5+2,j=mouseY/5+2;w[i][j]=b[i][j]=1;a();}void a(){for(i=0;i<h-2;i++)for(j=0;j<h-2;j++)if(w[i+2][j+2]==1)rect(i*5,j*5,5,5);}

Я считаю, что это удовлетворяет всем требованиям.

Ungolfed:

int h=22,t=24,i,j;
int[][]w=new int[t][t],b=new int[t][t];
int[]q={1,0,-1};
void draw(){
  if(t<9){
  clear();
  for(i=2;i<h;i++){
    for(j=2;j<h;j++)
      w[i][j]=b[i][j];  
    w[i][1]=w[i][21];
    w[i][h]=w[i][2];
    w[1][i]=w[21][i];
    w[h][i]=w[2][i];
  }
  for(i=1;i<23;i++)
    for(j=1;j<23;j++){
      t=-w[i][j];
      for(int s:q)
        for(int d:q)
          t+=w[i+s][j+d];        
      b[i][j]=w[i][j]>0&(t<2|t>3)?0:t==3?1:b[i][j];  
  }
  a();
}
}
void keyPressed(){
  t=0;
}
void mousePressed(){
  int i=mouseX/5+2,j=mouseY/5+2;
  w[i][j]=b[i][j]=1;
  a();
}
void a(){
  for(i=0;i<h-2;i++)
    for(j=0;j<h-2;j++)
      if(w[i+2][j+2]==1)
        rect(i*5,j*5,5,5);
  }  

3

Матлаб (152)

b=uint8(rand(20)<0.2)
s=@(m)imfilter(m,[1 1 1;1 0 1;1 1 1],'circular')
p=@(m,n)uint8((n==3)|(m&(n==2)))
while 1
imshow(b)
drawnow
b=p(b,s(b))
end

У меня сейчас не установлен Matlab, чтобы протестировать его, я просто использовал код, который написал несколько лет назад.
Ungolfed:

%% initialize
Bsize = 20;
nsteps = 100;
board = uint8(rand(Bsize)<0.2); % fill 20% of the board
boardsum = @(im) imfilter(im,[1 1 1; 1 0 1; 1 1 1], 'circular');
step = @(im, sumim) uint8((sumim==3) | (im & (sumim==2)) );

%% run
for i = 1:nsteps
    imshow(kron(board,uint8(ones(4))), [])
    drawnow
    ss(p,i) = sum(board(:));
    board = step(board, boardsum(board));
end
  • Boardsize жестко закодирован, но может быть чем угодно
  • обвивает
  • для пользовательского ввода можно изменить исходную плату либо путем жесткого кодирования другой матрицы, либо с помощью редактора переменных. Не красиво, но это работает
  • 20 символов могут быть сохранены, если графический вывод пропущен, доска будет по-прежнему печататься в виде текста на каждой итерации. Однопиксельные ячейки, которые меняются каждую миллисекунду, в любом случае не очень полезны

работает в R2014a, только что протестировал
masterX244

3

Perl, 218 216 211 202 байта

$,=$/;$~=AX3AAAx76;$b=pack('(A79)23',<>)x6;{print unpack'(a79)23a0',$b;select$v,$v,$v,0.1;$b=pack'(A)*',unpack'((x7a/(x13)X4Ax!18)1817@0)4',pack'((a*)17xx!18)*',unpack"x1737(AA$~Ax$~AA$~@)2222",$b;redo}

(В конце этого кода нет новой строки.)

Считывает начальный шаблон из стандартного ввода в виде текстового файла, где живые ячейки представлены в виде 1, мертвые ячейки представлены в виде пробела, строки разделяются новой строкой. На входе не должно быть символов, отличных от этих. Линии могут иметь переменную длину и будут дополнены или усечены до ширины ровно 79. Пример ввода - планерная пушка:

                                  1
                                1 1
                      11      11            11
                     1   1    11            11
          11        1     1   11
          11        1   1 11    1 1
                    1     1       1
                     1   1
                      11









                                         11
                                         1
                                          111
                                            1

Когда программа запускает Game of Life, каждое состояние выводится на стандартный вывод в формате, аналогичном вводу, затем задерживается на 0,1 секунды. Задержку можно настроить, изменив четвертый аргумент вызова select.

Доска для игр жестко запрограммирована на размер 79х23. Он завернут в тор: если вы оставите доску внизу, вы окажетесь наверху; если вы уйдете с правой стороны, вы окажетесь на левой стороне, но сместитесь на один ряд вниз.

Вот альтернативная версия, которая не читает никаких входных данных и начинается со случайной доски:

$,=$/;$/=AX3AAAx76;$b=pack("(A)*",map{rand 3<1}0..1816)x6;{print unpack'(a79)23a0',$b;select$v,$v,$v,0.1;$b=pack'(A)*',unpack'((x7a/(x13)X4Ax!18)1817@0)4',pack'((a*)17xx!18)*',unpack"x1737(AA$/Ax$/AA$/@)2222",$b;redo}

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

Вероятно, это не самый короткий способ реализации Game of Life на Perl, но это один из менее понятных способов.

Доска хранится в $bвиде строки '1'и ' ', по одному для каждой ячейки, только все это повторяется по меньшей мере три раза. Третий вызов распаковки извлекает 17 значений для каждой ячейки: есть одно для самой ячейки и два для каждой из восьми соседних ячеек в произвольном порядке, и каждое значение является '1'пустой строкой. Ячейка должна быть активной в следующей итерации, если число '1'значений среди этих 17 значений равно 5, 6 или 7. Третий вызов пакета объединяет эти 17 значений в поле шириной 18 символов, выровненное по левому краю и дополненное нулевыми байтами справа , Второй вызов unpack занимает такое поле шириной 18, отправляет символ в позиции 7, распаковывает пространство из позиции 17, если это'1'или распаковывает символ из позиции 4 в противном случае. Этот результат - именно то значение, которое должна иметь ячейка в следующем поколении.


2

Python, 589 байт

Кнопки мыши: слева - поставить ячейку, справа - удалить ячейку, посередине - начать / остановить.

от Ткинтер импорт *
импортировать копию
г = диапазон
F = 50
Т = Тк ()
S = 9
f = [F * [0] для i in'7 '* F]
Холст с = (Т, ширина = S * F, высота = S * F)
c.pack ()
def p (x, y, a): f [y] [x] = f [y] [x] или c.create_oval (x * S, y * S, x * S + S, y * S + S) если еще c.delete (f [y] [x])
г = 1
def R (e): глобальный r; r = 1-r
exec ("c.bind ('<Button-% i>', лямбда-е: p (ex / S, ey / S,% i));" * 2% (1,1,3,0))
c.bind ( '<Button-2>', R)
def L ():
 T.after (99, л)
 если г: возврат
 г = copy.deepcopy (е)
 для y в z (F):
	для х в г (F):
	 п = 8
	 для j в z (-1,2):
		для i в z (-1,2):
		 если я или j: n- = не g [(y + j)% F] [(x + i)% F]
	 если 1 <n <4:
		если n == 3, а не g [y] [x]: p (x, y, 1)
	 остальное: р (х, у, 0)
L ()
T.mainloop ()

И вот версия, где вы можете перетащить мышь, чтобы нарисовать. Графика немного приятнее.

from Tkinter import*
import copy
z=range
F=50
T=Tk()
S=9
f=[F*[0]for i in'7'*F]
c=Canvas(T,bg='white',width=S*F,height=S*F)
c.pack()
def p(x,y,a):f[y][x]=f[y][x]or c.create_rectangle(x*S,y*S,x*S+S,y*S+S,fill='gray')if a else c.delete(f[y][x])
r=1
def R(e):global r;r=1-r
exec("c.bind('<Button-%i>',lambda e:p(e.x/S,e.y/S,%i));c.bind('<B%i-Motion>',lambda e:p(e.x/S,e.y/S,%i));"*2%(1,1,1,1,3,0,3,0))
c.bind('<Button-2>',R)
def L():
 T.after(99,L)
 if r:return
 g=copy.deepcopy(f)
 for y in z(F):
  for x in z(F):
   n=8
   for j in z(-1,2):
    for i in z(-1,2):
     if i or j:n-=not g[(y+j)%F][(x+i)%F]
   if 1<n<4:
    if n==3and not g[y][x]:p(x,y,1)
   else:p(x,y,0)
L()
T.mainloop()

Это не соответствует правилам игры жизни.
Стивен Румбальски

1
@StevenRumbalski: Да действительно?
Олег Припин

2
действительно. У вас есть ошибка отступа во второй версии. Раздел, начинающийся с, if 1<n<4:должен иметь отступ на том же уровне, что иfor j in z(-1,2):
Стивен Румбальски

2

Python 2, 456 байт

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

Golf.py

import time,itertools as w,sys;t,q=map(lambda x:list(x[:-1]),sys.stdin.readlines()),list(w.product(range(-1,2),range(-1,2)));del q[4];n=map(lambda x:x[:],t[:])
while time.sleep(0.1)==None:
 for j in range(1,len(t)-1):
  for i in range(1,len(t[j])-1):x=sum(map(lambda s:1 if t[j+s[0]][i+s[1]]in'@'else 0,q));f=t[j][i];n[j][i]='@'if(f=='@'and(x==3 or x==2))or(f==' 'and x==3)else' '
 t=map(lambda x:x[:],n[:]);print'\n'.join(list(map(lambda x:''.join(x),t)))

Input.txt (обратите внимание на дополнительный пробел в последней строке)

+----------------------------------------+
|                    @                   |
|                     @                  |
|                   @@@                  |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
+----------------------------------------+ 

Как запустить

python Golf.py < input.txt

time.sleep(0.1)==None=> not time.sleep(.1), (f=='@'and(x==3 or x==2)) или (f == '' и x == 3) =>x==3or f=='@'and x==2
CalculatorFeline

^, Вы забыли один, 1 if=> 1if.
Захари

2

обработка 270261 249 байт

Сетка - это экран размером 100 * 100 пикселей, ввод осуществляется в виде картинки в формате png.

void setup(){image(loadImage("g.png"),0,0);}void draw(){loadPixels();int n,i=0,j,l=10000;int[]a=new int[l],p=pixels;for(;i<l;a[i]=n==5?-1<<24:n==6?p[i]:-1,i++)for(j=n=0;j<9;j++)n+=j!=4?p[(i+l-1+j%3+100*(j/3-1))%l]&1:0;arrayCopy(a,p);updatePixels();}

Ungolfed

void setup() {
  image(loadImage("g.png"), 0, 0);
}
void draw() {
  loadPixels();
  int c=100, i=0, n, l=c*c, b=color(0);
  int[]a=new int[l], p=pixels;
  for (; i<l; i++) {
    n=p[(i+l-101)%l]&1;
    n+=p[(i+l-100)%l]&1;
    n+=p[(i+l-99)%l]&1;
    n+=p[(i+l-1)%l]&1;
    n+=p[(i+1)%l]&1;
    n+=p[(i+99)%l]&1;
    n+=p[(i+100)%l]&1;
    n+=p[(i+101)%l]&1;
    a[i]=n==5?b:p[i]==b&&n==6?b:-1;
  }
  arrayCopy(a, pixels, l);
  updatePixels();
}

Скриншот


2

Lua + LÖVE / Love2D , 653 байта

l=love f=math.floor t={}s=25 w=20 S=1 for i=1,w do t[i]={}for j=1,w do t[i][j]=0 end end e=0 F=function(f)loadstring("for i=1,#t do for j=1,#t[i]do "..f.." end end")()end function l.update(d)if S>0 then return end e=e+d if e>.2 then e=0 F("c=0 for a=-1,1 do for b=-1,1 do if not(a==0 and b==0)then c=c+(t[((i+a-1)%w)+1][((j+b-1)%w)+1]>0 and 1 or 0)end end end g=t[i][j]t[i][j]=(c==3 or(c==2 and g==1))and(g==1 and 5 or-1)or(g==1 and 4 or 0)")F("t[i][j]=t[i][j]%2")end end function l.draw()F("l.graphics.rectangle(t[i][j]==1 and'fill'or'line',i*s,j*s,s,s)")end function l.mousepressed(x,y)S=0 o,p=f(x/s),f(y/s)if t[o]and t[o][p]then t[o][p]=1 S=1 end end

или разнесены:

l=love
f=math.floor
t={}s=25
w=20
S=1
for i=1,w do
    t[i]={}
    for j=1,w do
        t[i][j]=0
    end
end
e=0
F=function(f)
    loadstring("for i=1,#t do for j=1,#t[i] do  "..f.." end end")()
end
function l.update(d)
    if S>0 then
        return
    end
    e=e+d
    if e>.2 then
        e=0
        F([[
        c=0
        for a=-1,1 do
            for b=-1,1 do
                if not(a==0 and b==0)then
                    c=c+(t[((i+a-1)%w)+1][((j+b-1)%w)+1]>0 and 1 or 0)
                end
            end
        end
        g=t[i][j]
        t[i][j]=(c==3 or(c==2 and g==1))and(g==1 and 5 or-1) or (g==1 and 4 or 0)]])
        F("t[i][j]=t[i][j]%2")
    end
end
function l.draw()
    F("l.graphics.rectangle(t[i][j]==1 and'fill'or'line',i*s,j*s,s,s)") end
function l.mousepressed(x,y)
    S=0
    o,p=f(x/s),f(y/s)
    if t[o]and t[o][p] then
        t[o][p]=1
        S=1
    end
end

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

Попробуйте онлайн!

введите описание изображения здесь


1

постскриптум 529 515

Начал с примера из Rosetta Code . Вызвать аргумент имени файла ( gs -- gol.ps pulsar), файл, содержащий 20 * 20 двоичных чисел (разделенных пробелом). Бесконечный цикл: нарисуйте доску, дождитесь ввода, рассчитайте следующее поколение.

[/f ARGUMENTS 0 get(r)file/n 20>>begin[/m
n 1 sub/b[n{[n{f token pop}repeat]}repeat]/c 400
n div/F{dup 0 lt{n add}if dup n ge{n sub}if}>>begin{0
1 m{dup 0 1 m{2 copy b exch get exch get 1 xor setgray
c mul exch c mul c c rectfill dup}for pop pop}for
showpage/b[0 1 m{/x exch def[0 1 m{/y exch def 0
y 1 sub 1 y 1 add{F dup x 1 sub 1 x
1 add{F b exch get exch get 3 2 roll add exch
dup}for pop pop}for b x get y get sub b x get y get
0 eq{3 eq{1}{0}ifelse}{dup 2 eq exch 3 eq
or{1}{0}ifelse}ifelse}for]}for]def}loop

Разнесенный, с несколькими комментариями стека (только те, которые мне нужны).

[
/f ARGUMENTS 0 get(r)file
/n 20
/sz 400
%/r{rand 2147483647 div}
>>begin
[
/m n 1 sub
/b[
%n{[n{r .15 le{1}{0}ifelse}repeat]}repeat
 n{[n{f token pop}repeat]}repeat
]
/c sz n div
/F{dup 0 lt{n add}if dup n ge{n sub}if}
>>begin
{
    0 1 m{dup % y y
    0 1 m{ % y y x
        2 copy b exch get exch get 1 xor setgray
        c mul exch c mul c c rectfill
        dup 
    }for pop pop}for
    pstack
    showpage
    /b[0 1 m{/x exch def
      [0 1 m{/y exch def
          0   
          y 1 sub 1 y 1 add{F dup %s y y
          x 1 sub 1 x 1 add{F %s y y x
              b exch get exch get %s y bxy
              3 2 roll add exch %s+bxy y
              dup %s y y
          }for pop pop}for
          b x get y get sub
          b x get y get
          0 eq{3 eq{1}{0}ifelse}{dup 2 eq exch 3 eq or{1}{0}ifelse}ifelse
      }for]
      }for]def
}loop

файл данных пульсара:

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 1 1 1 0 0 0 1 1 1 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 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 1 1 0 0 0 1 1 1 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 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 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 1 1 1 0 0 0 1 1 1 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

1

JavaScript 676

Извините, Гриффин, я просто не мог посмотреть на ваш код и не переписать его немного ... пришлось сбрить два символа, но это того стоило!

b=[];r=c=s=20;U=document;onload=function(){for(z=E=0;z<c;++z)for(b.push(t=[]),j=0;j<r;j++)with(U.body.appendChild(U.createElement("button")))t.push(0),id=z+"_"+j,style.position="absolute",style.left=s*j+"px",style.top=s*z+"px",onclick=a}; ondblclick=function(){A=E=E?clearInterval(A):setInterval(function(){Q=[];for(z=0;z<c;++z){R=[];for(j=0;j<r;)W=(c+z-1)%c,X=(c+z+1)%c,Y=(r+j-1)%r,Z=(r+j+1)%r,n=b[W][Y]+b[z][Y]+b[X][Y]+b[W][j]+b[X][j]+b[W][Z]+b[z][Z]+b[X][Z],R.push(b[z][j++]?4>n&&1<n:3==n);Q.push(R)}b=Q.slice();d()})};function a(e){E?0:P=e.target.id.split("_");b[P[0]][P[1]]^=1;d()}function d(){for(z=0;z<c;++z)for(j=0;j<r;)U.getElementById(z+"_"+j).innerHTML=b[z][j++]-0}

Но, как говорится, проще просить прощения, чем разрешения ...;)


1

Октава (153)

так же, как Matlab от DenDenDo в Shortest Game of Life , но пришлось изменить imshow на imagesc:

b=uint8(rand(20)<0.2)
s=@(m)imfilter(m,[1 1 1;1 0 1;1 1 1],'circular')
p=@(m,n)uint8((n==3)|(m&(n==2)))
while 1
imagesc(b)
drawnow
b=p(b,s(b))
end

1

Python 2: 334 байта

Только 6 лет с опозданием.

import time
s='';s=map(list,iter(raw_input,s));k=len(s);l=(-1,0,1);n=int;z=range
while 1:
 r=[[0]*k for i in z(k)]
 for i in z(k*k):
  a,b=i//k,i%k
  m,g=sum([n(s[(a+c)%k][(b+d)%k])for c in l for d in l if c|d]),n(s[a][b])
  r[a][b]=n((m==2)&g or m==3)
  print'*'if r[a][b]else' ',
  if b-k+1==0:print
 s=r;time.sleep(.2);print"\033c"

Вы можете запустить его как:

python gol.py
0000000
0001000
0000100
0011100
0000000
0000000
0000000

Там, где 0 и 1 представляют мертвые и живые клетки, в конце начинается дополнительная новая строка в конце.

Сетки должны быть квадратными.

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

Это также на 100 байт больше, так что это так.


0

PHP, 201 байт (не проверено)

for($s=file(f);print"\n";$s=$t)foreach($s as$y=>$r)for($x=-print"
";"
"<$c=$s[$y][++$x];print$t[$y][$x]=" X"[$n<4&$n>2-$a])for($n=-$a=$c>A,$i=$x-!!$x-1;$i++<=$x;)for($k=$y-2;$k++<=$y;)$n+=$s[$k][$i]>A;

Беги с -nr.

сломать

for($s=file(f);                         # import input from file "f"
    print"\n";                              # infinite loop: 1. print newline
    $s=$t)                                  # 3. copy target to source, next iteration
    foreach($s as$y=>$r)                    # 2. loop through lines
        for($x=-print"\n";"\n"<$c=$s[$y][++$x]; # print newline, loop $x/$c through line characters (before line break)
            print                                   # 5. print new cell
                $t[$y][$x]=" X"[$n>2-$a&$n<4])      # 4. new cell is alive if neighbour count<4 and >2 (>1 if alive)
            for($n=-                                # 2. init neighbour count: exclude self
                $a=$c>A,                            # 1. $a=cell is alife
                $i=$x-!!$x-1;$i++<=$x;)             # 3. loop $i from one left to one right of current position
                for($k=$y-2;$k++<=$y;)                  # loop $k from one above to one below current position
                    $n+=$s[$k][$i]>A;                       # increase neighbor count if neighbour is alife
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.