Сделать симулятор пузырчатой ​​пленки

23

Пузырьковые обертывания - это развлечения на высшем уровне. Каждый может согласиться с этим.

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

Спекуляции

Вам дадут два целых числа, w и h (каждое из них по ширине и высоте)

Ваша программа должна вывести все w * h фазы, ожидая 1 секунду между каждым и завершиться.

Каждая пузырчатая пленка начинается со всех заполненных ячеек.

Например, 4 * 6 пузырчатая пленка начинается как:

O_O_
_O_O
O_O_
_O_O
O_O_
_O_O

И каждая фаза, случайная не вытолкнутая ячейка выталкивается. Например,

O_O_
_O_O
O_X_
_O_O
O_O_
_O_O

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

X_X_
_X_X
X_X_
_X_X
X_X_
_X_X

Примеры

(4,6)
(5,5)
(6,2)
(10,10)
(7,9)
Мэтью Ро
источник
Можем ли мы использовать 1и 0вместо Oи X?
Павел
1
NEEDZ BUBBLEZ пожалуйста, отправьте помощь
Кристофер
3
Допустимо ли, (1,1)чтобы у a не было пузырьков (например, верхняя левая "ячейка" всегда подчеркивание)?
Джонатан Аллан
1
@JonathanAllan Да.
Мэтью Ро
1
@KevinCruijssen Это не обязательно полная программа.
Мэтью Ро

Ответы:

7

C (Windows), 260 248 байт

#import<windows.h>
i,j,l,r;b(w,h){char*s=malloc(l=w*h+h);for(i=h;i--;*s++=10)for(j=w;j--;*s++=i%2^j%2?79:45);*(s-1)=0;s-=l;for(srand(time(0));j>system("cls")+puts(s)-2;j>-1?s[j]=88:0)for(Sleep(1000),r=rand(),j=-2,i=r+l*2;--i-r;j=s[i%l]==79?i%l:j);}

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

Steadybox
источник
Обратите внимание, что в библиотеке потоков есть функция сна, которая включена в C ++ 11.
Мэтью Ро
@ MatthewRoh Да, но это короче, и system("cls")это также зависит от Windows, поэтому код не будет более переносимым с библиотекой потоков. А с C ++ мне бы тоже нужно было включить iostreamили cstdio.
Steadybox
Кстати, вам не нужно перезагружать экран. это сделает его короче.
Мэтью Ро
5

Python 3 , 222 220 байт

Это мой первый ответ, поэтому, пожалуйста, будьте осторожны (и укажите на ошибки, которые я сделал).

import time,random as t
def f(c,r):
 p=print;a='0_'*c;d=((a[:c]+'\n'+a[1:c+1]+'\n')*r)[:-~c*r]
 for i in[1]*((r*c+r%2*c%2)//2):
  p(d);k=1
  while d[k]!='0':k=t.randrange(len(d))
  d=d[:k]+'X'+d[k+1:];time.sleep(1)
 p(d)

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

Как это работает:

  1. Цепь много '0 _' вместе
  2. Разбейте на части '0_0 _... \ n' и '_0_0 ... \ n' и объедините
  3. Генерируйте случайные индексы, пока символ в индексе не станет равным '0'
  4. Создание новой строки с символом в сгенерированном индексе заменяется на 'X' (Черт бы тебя побрал Python для неизменяемых строк!)
  5. Повторите r*c+r%2*c%2время: r*cв шаблоне есть пузырьки, если только r и c нечетны, и в этом случае они есть r*c+1.
Нил
источник
1
Добро пожаловать в PPCG!
AdmBorkBork
1
Это довольно незначительно, но ваша ширина и высота поменялись местами. Отличный ответ, хотя! (Просто измените его на f(c,r)и все будет в порядке).
Расар
@ rassar Woops, спасибо!
Нил,
4

MATL , 37 байт

:!i:+o`T&Xxt3:q'_OX'XEcD2y1=ft&v1Zr(T

Верхний левый угол всегда является подчеркиванием (разрешено вызовом).

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

Программа завершает работу с ошибкой ( разрешенной по умолчанию ) после отображения всех фаз.

Попробуйте это в MATL Online! (Если через пару секунд это не сработает, обновите страницу и попробуйте снова).

Луис Мендо
источник
4

Mathematica (145 байт)

Анонимная функция, имеет высоту и ширину в качестве входных данных (в таком порядке - если это проблема, замените {##}с {#2,#}в середине коды для дополнительного 2 байта).

Код:

Monitor[Do[Pause@1,{i,NestList[RandomChoice@StringReplaceList[#,"O"->"X"]&,""<>Riffle["_"["O"][[Mod[#+#2,2]]]&~Array~{##},"
"],Floor[##/2]]}],i]&

Объяснение:

  • ""<>Riffle[Array["_"["O"][[Mod[#+#2,2]]]&,{##}],"\n"] создает начальную незапертую пузырчатую пленку, создавая массив "_" и "O", а затем StringJoining их между символами новой строки.
  • NestList[RandomChoice@StringReplaceList[#,"O"->"X"]&,..., Floor[##/2]]многократно выбирает одну из «O» для замены на «X» столько раз, сколько существует «O» (это Floor [width * height / 2] - спасибо @JonathanAllan за идею поставить «_» "вместо" O "в верхнем левом углу, иначе это будет Ceilingвместо этого и, следовательно, на 2 байта больше).
  • Monitor[Do[Pause@1,{i,...}],i]заставляет iпринимать значения в списке, который мы только что рассчитали, по 1 секунде каждое и печатает динамически i.

Пример вывода:

GIF Mathematica всплывает пузырчатая пленка

Не дерево
источник
3

Желе , 30 29 байт

=”OTX
+þ⁹++µị⁾_OYµṄœS1”XǦµÐL

Пример запуска

Вызывает ссылку как диаду с аргументами программы, а затем завершает работу с сообщением (код для которого есть çṛ“\'=ṙMḋḌẓ(ėo»)

Нюанс: нижний правый «ячейка» всегда будет пузырь (а не в верхнем левом углу, как , например , в вопросе), это должно гарантировать , что , когда все пузырьки извлекаются случайные возвращается выбор 0 , который будет "X"на конец списка - его замена не приводит к изменению значения и прерывает цикл.

Примечание: не очищает экран (не было указано, и я не уверен, как это сделать).

Как?

=”OTX - Link 1, choose a random O index or 0: string   e.g. "_O_\nX_O"
 ”O   - "O"
=     - equals (vectorises over the string)            e.g. [0,1,0,0,0,0,1]
   T  - truthy indexes                                 e.g. [2,7]
    X - random choice (if empty this returns 0)

+þ⁹++µị⁾_OYµṄœS1”XǦµÐL - Main link: w, h              e.g. 3, 2
                        - left argument (implicit), w  e.g. 3
  ⁹                     - right argument, h            e.g. 2
 þ                      - outer product with
+                       -     addition                 e.g. [[2,3,4],[3,4,5]]
                        - left argument (implicit), w  e.g. 3
   +                    - add                          e.g. [[5,6,7],[6,7,8]]
                        - right argument (implicit), h e.g. 2
    +                   - add                          e.g. [[7,8,9],[8,9,10]]
     µ                  - monadic chain separation
       ⁾_O              - "_O"
      ị                 - index into (1-based & mod)   e.g. [['_','O','_'],['O','_','O']]
                        -     note: the additions above assure the last entry is an 'O'.
          Y             - join with line feeds         e.g. ['_','O','_','\n','O','_','O']
           µ        µ   - monadic chain separations
                     ÐL - loop until the results are no longer unique:
            Ṅ           -     print with a trailing line feed and yield
             œS1        -     sleep for 1 second and yield
                   ¦    -     apply to index
                  Ç     -         given by calling the last link (1) as a monad 
                        -                 (a random O index or 0 if none exists)
                ”X      -         an "X"  (      ... which will be an X already)
Джонатан Аллан
источник
@ ГригорийПерельман написал это.
Джонатан Аллан
2

Scala , 764 байта

object B{
  def main(a: Array[String]):Unit={
    val v=false
    val (m,l,k,r,n)=(()=>print("\033[H\033[2J\n"),a(0)toInt,a(1)toInt,scala.util.Random,print _)
    val e=Seq.fill(k, l)(v)
    m()
    (0 to (l*k)/2-(l*k+1)%2).foldLeft(e){(q,_)=>
      val a=q.zipWithIndex.map(r => r._1.zipWithIndex.filter(c=>
        if(((r._2 % 2) + c._2)%2==0)!c._1 else v)).zipWithIndex.filter(_._1.length > 0)
      val f=r.nextInt(a.length)
      val s=r.nextInt(a(f)._1.length)
      val i=(a(f)._2,a(f)._1(s)._2)
      Thread.sleep(1000)
      m()
      val b=q.updated(i._1, q(i._1).updated(i._2, !v))
      b.zipWithIndex.map{r=>
        r._1.zipWithIndex.map(c=>if(c._1)n("X")else if(((r._2 % 2)+c._2)%2==0)n("O")else n("_"))
        n("\n")
      }
      b
    }
  }
}

Как это работает

Алгоритм сначала заполняет 2D-последовательность ложными значениями. Он определяет, сколько итераций (открытых блоков) существует на основе введенных аргументов командной строки. Он создает сгиб с этим значением в качестве верхней границы. Целочисленное значение сгиба неявно используется только как способ подсчета количества итераций, которые должен выполнить алгоритм. Заполненная последовательность, которую мы создали ранее, является начальной последовательностью для сгиба. Это используется при генерации новой двумерной последовательности ложных значений с соответствующими им единицами.

Например,

[[false, true],
 [true, false],
 [true, true]]

Будет превращен в

[[(false, 0)], [(false, 1)]]

Обратите внимание, что все списки, которые являются полностью истинными (имеют длину 0), исключаются из списка результатов. Затем алгоритм берет этот список и выбирает случайный список во внешнем списке. Случайный список выбирается как случайная строка, которую мы выбираем. Из этой случайной строки мы снова находим случайное число, индекс столбца. Как только мы находим эти два случайных индекса, мы спим в потоке, в котором мы находимся, в течение 1000 миллисекунд.

После того, как мы закончили спать, мы очищаем экран и создаем новую доску со trueзначением, обновленным в случайных индексах, которые мы создали.

Чтобы правильно распечатать это, мы используем mapи заархивируем его индексом карты, чтобы мы имели это в нашем контексте. Мы используем значение истинности последовательности относительно того, должны ли мы печатать Xили или Oили или _. Чтобы выбрать последнее, мы используем значение индекса в качестве руководства.

Интересные вещи на заметку

Чтобы выяснить, следует ли печатать Oили _, используется условное выражение ((r._2 % 2) + c._2) % 2 == 0. r._2ссылается на текущий индекс строки, а c._2ссылается на текущий столбец. Если один находится в нечетной строке, r._2 % 2будет 1, поэтому смещение c._2на 1 в условном выражении. Это гарантирует, что в нечетных строках столбцы перемещаются на 1, как и предполагалось.

Распечатка строки в "\033[H\033[2J\n"соответствии с прочитанным мною ответом Stackoverflow очищает экран. Он пишет байты в терминал и делает что-то напуганное, чего я не очень понимаю. Но я нашел, что это самый простой способ сделать это. Однако он не работает на консольном эмуляторе Intellij IDEA. Вам придется запустить его с помощью обычного терминала.

Другое уравнение можно было бы найти странно видеть , когда первый глядя на этот код (l * k) / 2 - (l * k + 1) % 2. Во-первых, давайте демистифицируем имена переменных. lссылается на первые аргументы, переданные в программу, а kссылается на второй. Для того, чтобы перевести его, (first * second) / 2 - (first * second + 1) % 2. Цель этого уравнения - найти точное количество итераций, необходимое для получения последовательности всех X. В первый раз, когда я сделал это, я просто сделал (first * second) / 2так, чтобы это имело смысл. Для каждого nэлемента в каждом подсписке есть n / 2всплывающие подсказки. Тем не менее, это нарушается при работе с такими ресурсами, как(11 13), Нам нужно вычислить произведение двух чисел, сделать его нечетным, если оно четным, и даже если оно нечетным, и затем принять его значение на 2. Это работает, потому что строки и столбцы, которые являются нечетными, потребуют на одну итерацию меньше чтобы добраться до конечного результата.

mapиспользуется вместо a, forEachпотому что в нем меньше символов.

Вещи, которые можно улучшить

Одна вещь, которая действительно беспокоит меня об этом решении - это частое использование zipWithIndex. Это занимает так много персонажей. Я попытался сделать так, чтобы я мог определить свою собственную односимвольную функцию, которая будет просто выполнять zipWithIndexс переданным значением. Но оказывается, что Scala не позволяет анонимной функции иметь параметры типа. Возможно, есть другой способ сделать то, что я делаю, без использования, zipWithIndexно я не слишком много думал о том, как сделать это умным способом.

В настоящее время код выполняется в два этапа. Первый генерирует новую доску, а второй проход печатает ее. Я думаю, что если объединить эти два прохода в один, это сэкономит пару байтов.

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

Стефан Алексич
источник
1

JavaScript (ES6), 246 229 байт

document.write(`<pre id=o></pre>`)
setInterval(_=>{(a=o.innerHTML.split(/(O)/))[1]?a[Math.random()*~-a.length|1]=`X`:0;o.innerHTML=a.join``},1e3)
f=(w,h)=>o.innerHTML=[...Array(h)].map((_,i)=>`O_`.repeat(w+h).substr(i,w)).join`
`
<div oninput=f(+w.value,+h.value)><input id=w type=number min=1><input id=h type=number min=1>

Нил
источник
Ширина была не в терминах ячеек, а в том числе пустых (подчеркивание) пробелов.
Мэтью Ро
@MatthewRoh Извините, я не забыла исправить его по высоте, но забыла проверить ширину.
Нил
Хм .. не может эта часть: `${`_O`.repeat(w).slice(w)} ${`O_`.repeat(w).slice(w)}как-то сочетается? Возможно, логический флаг, чтобы сначала определить _Oили O_, а затем сделать .repeat(w).slice(w)?
Кевин Круйссен
1
@KevinCruijssen Я потерял 16 байтов из-за быстрого исправления, которое у меня не было времени для игры в гольф в то время. С тех пор я посмотрел еще раз и получил 17-байтовую экономию,
Нил
1

Python - 290 байт

Я никогда не делал ничего подобного раньше, поэтому любая конструктивная критика будет оценена :)

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

r=range
q=print
import random as n,time
def f(H,W):
    def p(b):
        q("\n".join(["".join(["O"if(i,j)in b else"X"if(i,j)in X else"_"for j in r(H)])for i in r(W)]));time.sleep(1);q()
    b=[(i,h)for h in r(H)for i in r(h%2,W,2)];n.shuffle(b);X=[]
    while len(b)>0:
        p(b);X+=[b.pop()]
    p(b)
Arya
источник
Привет, добро пожаловать в PPCG! Задача состояла в том, чтобы взять wи в hкачестве ввода (через STDIN, как ввод функции или что-то подобное), вместо того, чтобы иметь жестко закодированный H=4 W=6. Кроме того, хотя я никогда не программировал на Python, я думаю, что вы можете использовать некоторые пробелы в своем текущем коде. Также может быть интересно прочитать советы по игре в гольф на Python, чтобы дать вам идеи о том, как играть в гольф дальше. Приятного пребывания! :)
Кевин Круйссен
Кроме того, что касается вашего комментария: « Я мог бы сохранить несколько символов, не имея новой строки между всплывающими окнами, но это выглядит просто уродливо». Независимо от того, насколько уродливым или нереализованным это в реальном программировании, Codegolf о сохранении как как можно больше байтов. Чем короче и страшнее, тем лучше. ;)
Кевин Круйссен
@KevinCruijssen Python3, который находится выше меня, имеет только функцию w, h, это разрешено?
Арья
1
Хорошо, теперь я сделал это функцией H и W
Арья
1

Древесный уголь , 49 46 39 байт (неконкурентный)

UONNO_¶_OAKAαA№αOβHWψβ«A§α§⌕AαO‽βXA№αOβ

Подробный

Oblong(InputNumber(), InputNumber(), "O_\n_O")
Assign(PeekAll(), a)
Assign(Count(a, "O"), b)
RefreshWhile (k, b) {
    AssignAtIndex(a, AtIndex(FindAll(a, "O"), Random(b)), "X")
    Assign(Count(a, "O"), b)
}
ASCII-только
источник
1

APL (Dyalog) , 61 59 байтов

⎕←m'O_'[2|-/¨⍳⎕]
(b/,m)[?+/b'O'=,m]←'X'
DL 1
2/⍨'O'∊⎕←m

⎕← выведите
m←m , где m - это
'O_'[... ] эти символы, проиндексированные ...
2| делением-остатком-при-делении-на-два
-/¨ разности между каждой из
 всех координат (индексов) в массиве
 числового ввода формы (количество строк и столбцов) )

(... )[... ]←'X' присвоить символ X одному из ...
b/ отфильтрованный в каждом конкретном Ь (должны быть определены)
,m распущенной элементы м, в частности , ...
? случайный элемент (число букв) в диапазоне от одного до
+/ суммы
b←Ь , где Ь является
'O'= булева где буква равна
,mт издал

⎕DL 1Д е л ау один второй

→2 Перейти к строке 2,
/⍨ если (с подсветкой отфильтровано) является
'O'∊ ли буква членом
⎕←m выведенного значения, где выводимое значение равно m

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


С версии 16.0 будет короче:

{0::→⋄'X'@(⊂(?∘≢⊃⊢)⍸'O'=⍵⊣⎕DL 1)⊢⎕←⍵}⍣≡'O_'[2|-/¨⍳⎕]

Адам
источник
1

Python 3, 195 188 байт

import time,random
def f(w,h):
 a=bytearray(b'0-'*w*h);b=[*range(0,w*h,2)];random.shuffle(b);
 while 1:print(*(a.decode()[w*i:w*i+w]for i in range(h)),sep='\n');a[b.pop()]=88;time.sleep(1)

Использование bytearrayи decodeкажется короче, чем нарезка и сборка строки а-ля a[:i]+'X'+a[i+1:].

import time,random
def f(w,h):
 x=[*range(1,h*w,2)];random.shuffle(x)
 while 1:
  for i in range(w*h):
   print('-X0'[(i%w%2!=i//w%2)+(i in x)],end='\n'[i%w<w-1:])
  print();time.sleep(1);x.pop()
RootTwo
источник
0

Java 7, 317 байт

void c(int w,int h)throws Exception{String r="";int x=0,j=0,i;for(;j++<h;x^=1,r+="\n")for(i=0;i<w;r+=(i+++x)%2<1?"_":"O");for(System.out.println(r);r.contains("O");System.out.println(r=r.substring(0,x)+'X'+r.substring(x+1))){Thread.sleep(1000);for(x=0;r.charAt(x)!='O';x=new java.util.Random().nextInt(r.length()));}}

Объяснение:

void c(int w, int h) throws Exception{                     // Method with two integer parameters (throws Exception is required for the Thread.sleep)
  String r = "";                                           //  String we build to print
  int x=0, j=0, i;                                         //  Some temp values and indexes we use
  for(; j++<h;                                             //  Loop over the height 
      x^=1,                                                //    After every iteration change the flag `x` every iteration from 0 to 1, or vice-versa
      r += "\n")                                           //    And append the String with a new-line
    for(i=0; i<w;                                          //   Inner loop over the width
        r += (i++ + x)%2 < 1 ? "_" : "O")                  //    Append the String with either '_' or 'O' based on the row and flag-integer
    ;                                                      //   End inner width-loop (implicit / no body)
                                                           //  End height-loop (implicit / single-line body)
  for(                                                     //  Loop
    System.out.println(r);                                 //   Start by printing the starting wrap
    r.contains("O");                                       //   Continue loop as long as the String contains an 'O'
    System.out.println(r=                                  //   Print the changed String after every iteration
        r.substring(0,x)+'X'+r.substring(x+1))){           //    After we've replaced a random 'O' with 'X'
      Thread.sleep(1000);                                  //   Wait 1 second
      for(x=0; r.charAt(x) != 'O';                         //   Loop until we've found a random index containing still containing an 'O'
          x = new java.util.Random().nextInt(r.length()))  //    Select a random index in the String
      ;                                                    //   End loop that determines random index containing 'O' (implicit / no body)
  }                                                        //  End loop
}                                                          // End method

Test gif (4,6)

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

Кевин Круйссен
источник
0

Perl, 148 байт

146 байт кода + -plфлаги.

$_=O x($x=$_+1);s/O\K./_/g;for$i(1..($y=<>)){$b.=($i%2?$_:_.s/.$//r).$/}}print$_="\e[H$b";while(/O/){$r=0|rand$y*$x+3;s/.{$r}\KO/X/s||redo;sleep 1

Чтобы запустить это:

perl -ple '$_=O x($x=$_+1);s/O\K./_/g;for$i(1..($y=<>)){$b.=($i%2?$_:_.s/.$//r).$/}}print$_="\e[H$b";while(/O/){$r=0|rand$y*$x+3;s/.{$r}\KO/X/s||redo;sleep 1' <<< "6
4"
папа
источник
0

MATLAB (R2016b), 172 байта

Код:

x=input('');m=[eye(x(2),x(1)) ''];m(:)='O';m(1:2:end,2:2:end)='_';m(2:2:end,1:2:end)='_';o=find(m=='O');r=o(randperm(nnz(o)));disp(m);for i=r';pause(1);m(i)='X';disp(m);end

Рекомендации всегда приветствуются! Попробуйте онлайн!

Выход программы:

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

Объяснение:

x = input( '' );                    % Input
m = [ eye( x( 2 ), x( 1 ) ) '' ];   % Character Matrix
m( : ) = 'O';                       % Fill Matrix with "Bubbles"

m( 1:2:end, 2:2:end ) = '_';        % Alternate Spaces Between Bubbles (Part 1)
m( 2:2:end, 1:2:end ) = '_';        % Alternate Spaces Between Bubbles (Part 2)

o = find( m == 'O' );               % Index Bubble Locations
r = o( randperm( nnz( o ) ) );      % Randomize Bubble Locations

disp( m );                          % Display Initial Bubble Wrap Phase

for i = r'
    pause( 1 );                     % Pause for 1 Second
    m( i ) = 'X';                   % Pop Bubble
    disp( m );                      % Display Subsequent Bubble Wrap Phase
end
Грант Миллер
источник