Korek uliczny 2D

17

Model ruchu Biham-Middleton-Levine jest samoorganizujące automat komórkowy, że modele uproszczone ruchu.

Składa się z wielu samochodów reprezentowanych przez punkty na kratce z losową pozycją początkową, przy czym każdy samochód może być jednego z dwóch rodzajów: te, które poruszają się tylko w dół (pokazane w tym artykule jako niebieskie) i te, które poruszają się tylko w kierunku prawo (pokazane w tym artykule na czerwono). Dwa rodzaje samochodów poruszają się na zmianę. Podczas każdej tury wszystkie samochody danego typu przechodzą o jeden krok do przodu, jeśli nie są blokowane przez inny samochód.

Twoim zadaniem jest wizualizacja tego modelu jako animacji. Oto kilka dobrych demonstracji.

wprowadź opis zdjęcia tutaj

Wejście

Liczba zmiennoprzecinkowa od 0 do 1 reprezentująca gęstość oraz dwie liczby całkowite reprezentujące wyświetlaną wysokość i szerokość siatki. Załóżmy, że dane wejściowe są prawidłowe, a parametry funkcji lub odczyt z danych wprowadzonych przez użytkownika są w porządku.

Przykład: 0.38 144 89(odpowiada powyższemu obrazowi)

Wynik

Siatka o wymiarach co najmniej 80 x 80, która wyświetla animację uruchomionego modelu. Na początku samochody są losowo umieszczane na siatce, aż siatka osiągnie gęstość wejściową, z połową koloru czerwonego i pół niebieską (to jest gęstość razy całkowita liczba kwadratów siatki, zaokrąglona w dowolny sposób). Gęstość musi mieć tę wartość, co oznacza, że ​​nie można wypełnić każdej komórki gęstością jako prawdopodobieństwa. Na każdym kroku jeden rodzaj samochodu porusza się w dół lub w prawo, owijając się, jeśli minie krawędź. Rodzaj poruszającego się samochodu zmienia się na każdym kroku. Aby animacja była widoczna, pomiędzy każdym krokiem musi być co najmniej 10 ms.

Zasady

  • Samochody mogą być dowolnego koloru lub symbolu, o ile można je odróżnić od siebie i tła, a każdy typ samochodu ma ten sam kolor lub symbol.

  • Konsola i wyjście graficzne są dozwolone. W przypadku danych wyjściowych z konsoli dowolny symbol do wydruku jest w porządku, ale dane wyjściowe muszą być w postaci siatki znaków.

  • Proszę określić, jaki rodzaj produkcji uzyskałeś, jeśli nie masz zrzutu ekranu lub gif.

  • Symulacja musi trwać wiecznie.

Wynik jest nieco złożony, więc jeśli masz jakieś pytania, prosimy o komentarz.

qwr
źródło
Jakieś ograniczenia dotyczące tego, jak wolno lub szybko animacja musi się uruchamiać?
xnor
Być może warto sprecyzować, że rodzaj poruszającego się samochodu zmienia się na każdym kroku.
Greg Martin,
@ xnor Myślałem o co najmniej 5 lub 10 ms na pętlę, ale nie jestem pewien, czy trudno byłoby to zmierzyć.
qwr
3
Czy gęstość oznacza, że ​​gęstość musi być tą wartością, czy tylko że każdy piksel ma prawdopodobieństwo d do wypełnienia? Ponadto, czy musimy przypisywać kolor samochodów losowo, czy nie? Jeśli losowo, czy to w porządku, jeśli mają tylko 50-50 szans na bycie jednym z kolorów?
JAD,
1
@JarkoDubbeldam Gęstość musi być tą wartością. Mają 50-50 szans na bycie każdym kolorem. Jednak odpowiedziałem późno, więc odpowiedzi mogą być inne. Samochody mogą poruszać się w górę lub w lewo.
qwr

Odpowiedzi:

5

R, 350 338 293 291 273 268 264 bajtów

function(d,x,y){f=function(w){v=length(w);for(j in which(w>0&!w[c(2:v,1)]))w[c(j,j%%v+1)]=0:1;w};m=matrix(sample(c(rep(1,q<-floor(d*y*x/2)),rep(-1,q),rep(0,x*y-2*q))),x);p=animation::ani.pause;o=image;a=apply;repeat{o(m<-t(a(m,1,f)));p();o(m<--1*a(-1*m,2,f));p()}}

Nie golfowany:

function(d,x,y){
  q=floor(d*y*x/2)

  m=matrix(sample(c(rep(1,q),rep(-1,q),rep(0,x*y-2*q))),x)

  f=function(w){
    v=length(w)
    for(j in which(w>0&!w[c(2:v,1)])){
      w[c(j,j%%v+1)]=0:1
    }
    w
  }


  library(animation)
  repeat{
    m=t(apply(m,1,f))
    image(m)
    m=-1*apply(-1*t(m),2,f))
    ani.pause()
    image(m)  
    ani.pause()
  }
}

Funkcja, która przyjmuje 3 argumenty: djako gęstość i wymiary x,y. qto liczba samochodów w każdym kolorze. mto matryca z samochodami, która początkowo jest wypełniana przez losowe sortowanie liczby samochodów i pustych miejsc. Samochody są albo, 1albo jest -1puste miejsce 0.

fto funkcja, która przesuwa samochody o jeden rząd, patrząc na samochody oznaczone jako 1. Sprawdza, czy samochód może się poruszać, sprawdzając litery 1s, a następnie 0. Używamy applydo biegania fw każdym rzędzie lub kolumnie, w zależności od tego, jakie samochody.

fobsługuje ruch 1samochodów, aby przenieść -1samochody, transponujemy matrycę, zmieniając kierunek ruchu, mnożąc matrycę -1, dzięki czemu -1samochody stają się 1samochodami, a vv i uzyskana macierz jest ponownie przekształcana.

Służy imagedo tworzenia wykresu przy użyciu 3 domyślnych kolorów dla trzech wartości. Używa animationpakietu do obsługi animacji przy użyciu domyślnych opcji, czyli 1 fps.

0.38, 144, 89:

Link do GIF

0.2, 144, 89:

Link do GIF

0.53, 144, 89:

Link do GIF

JAD
źródło
Twoja animacja wygląda naprawdę fajnie - jakiej gęstości użyłeś? Wygląda na to, że całość szybko się zacięła z dużą ilością pustej przestrzeni
qwr
@qwr to było coś, co mnie niepokoiło. W moim programie całość zacina się przy niższych gęstościach niż w przykładzie, który podłączyłeś. Nie pamiętam jednak dokładnych parametrów użytych w fabule, ale może to być 0.38 144 89przykład z przykładu.
JAD
Bawiąc się kwadratowymi siatkami, uzyskałem gęstość 0,35, aby jam jamondavies.com/bml/#0.35/100/100, ale prawie zawsze jest to jedna gruba linia 45 stopni zamiast cienkich linii ukośnych. Ponieważ twoje linie wyglądają bardziej pionowo, myślę, że coś z dwoma typami samochodów jest wyłączone
qwr
Teraz widzę problem. Cara może awansować tylko wtedy, gdy nie jest zablokowany przez inny samochód. Tak więc w przykładach z Wikipedii wszystkie poruszające się samochody mają przed sobą miejsce. Ale w twojej animacji samochody poruszają się jak linia. Ciekawy.
qwr
Ach, to by wystarczyło.
JAD
5

Mathematica, 237 228 203 198 181 bajtów

(b=RandomSample@ArrayReshape[Table[{0,i=2},##/2],{1##2},1]~Partition~#2;Dynamic@Colorize[i=-i;b=CellularAutomaton[{193973693,{3,{a=0{,,},{3,9,1},a}},{1,1}},b];If[i>0,b,2-b]])&

Dane wyjściowe są dynamiczne Image. Tło jest jasnozielone, a samochody są czarne lub purpurowe, w zależności od ich kierunku.

Wyjaśnienie

b=RandomSample@ArrayReshape[Table[{i=1,2},##/2],{1##2},1]~Partition~#2

Utwórz początkową tablicę:

Table[{0,i=2},##/2]

Ustaw ina 2. Tworzenie Listz {0, 2}, którego długość jest podłoga (gęstość * * wysokość szerokość / 2) (dzieli się przez dwa, ponieważ {0, 2}jest długości 2).

ArrayReshape[ ... ,{1##2},1]

Przekształć powstałe 2-D List(2 x coś) w 1-D List(długość = szerokość * wysokość). Pad, 1jeśli nie ma wystarczających wartości.

RandomSample@ ...

(Pseudo-) losowo sortuje wynik.

... ~Partition~#2

Podział, którego wynikiem jest długość (szerokość).

b= ...

Przechowuj to w b.


Dynamic@Colorize[i=-i;b=CellularAutomaton[{193973693,{3,{a=0{,,},{3,9,1},a}},{1,1}},b];If[i>0,b,2-b]]

Utwórz Dynamic Image:

i=-i;

Odwróć znak i .

b=CellularAutomaton[{193973693,{3,{a=0{,,},{3,9,1},a}},{1,1}},b]

Zastosuj automat komórkowy z regułami 193973693i obciążnikami sąsiadującymi {{0, 0, 0}, {3, 9, 1}, {0, 0, 0}}do btranspozycji. Zestaw brówny.

If[i>0,b,2-b]

Jeśli ijest pozytywny, zostaw w bspokoju. Jeśli nie, transponuj b( 2-jest tam, bo CellularAutomatontrochę grałem w golfa ). Zasadniczo transponuje to bkażdą inną iterację (aby cofnąć transpozycję)

Colorize[ ... ]

Przekształć tablicę w kolorowy Image.

Dynamic@ ...

Zrób wyrażenie Dynamic. tzn. powyższe funkcje są uruchamiane wielokrotnie.

Wynik

Oto przykładowe wyjście (dane wejściowe:) 0.35, 192, 108dla 2000 klatek (powiększenie 2x).

https://i.imgur.com/zmSyRut.mp4

JungHwan Min
źródło
Huh, korzystanie z wbudowanego jest dłuższe niż nieużywanie go ?!
Adám
3

Dyalog APL , 190 108 115 112 bajtów

Rozwiązanie

S←{⍉⍣⍺⊢d[⍺]↑d[⍺]↓⍉↑(⍺⊃'(↓+) ' '(→+) ')⎕R' \1'↓(,⍨,⊢)⍉⍣⍺⍉⎕←⍵⊣⎕DL÷4}
{1S 0S⍵}⍣≡' ↓→'[d⍴{⍵[?⍨⍴⍵]}c1 2⍴⍨⌊⎕×c←×/d←⎕]

TryAPL online (nieco zmodyfikowany z powodu ograniczeń online):

  1. Zestaw ⎕IO←0, określenie funkcji S , a następnie określić, a na losowy 38% 14 x 29 siatki, G .

  2. Zrób jeden ruch w dół.

  3. Wykonaj jeden ruch w prawo.

  4. Przejdź do kroku 2.

    ruch drogowy
    Animacja poprzedniego algorytmu, który nie gwarantował gęstości.

Wyjaśnienie

S←{zdefiniuj funkcję bezpośrednią S (wyjaśnioną tutaj od prawej do lewej):

÷4 odwrotność 4 (0,25)

⎕DL poczekaj tyle sekund (zwraca rzeczywisty czas, który upłynął)

⍵⊣ odrzuć to na korzyść ⍵ (właściwy argument; siatka)

⎕← wydać to

 transponować

⍉⍣⍺ transponuj ponownie, jeśli ⍺ (lewy argument; 0 = w dół, 1 = w prawo)

( zastosuj ciąg funkcji (wyjaśniony tutaj od lewej do prawej):

  ,⍨ argument przyłączył się do siebie

  , dołączone do

   samo

)

 podziel macierz na listę list

( szukaj wyrażenia regularnego (wyjaśnione tutaj od lewej do prawej):

  ⍺⊃ wybierz jeden z dwóch następujących na podstawie ⍺ (0 = w dół / pierwszy, 1 = w prawo / drugi)

  '(↓+) ' '(→+) ' sekwencje strzałek w dół i w lewo, a następnie spacja

)⎕R' \1' zamień na spację, po której następuje znaleziona sekwencja

 zmieszaj listę list w macierz

 transponować

d[⍺]↓ upuść wiersze „wysokość”, jeśli ⍺ (lewy argument) wynosi 0 (w dół) lub „szerokość” wierszy, jeśli ⍺ jest 1 (prawy)

d[⍺]↑ następnie weź tyle wierszy

 przejść przez (służy jako separator)

⍉⍣⍺ transponuj, jeśli ⍺ (lewy argument; 0 = w dół, 1 = w prawo)

}


' ↓→'[ indeksuj ciąg za pomocą (wyjaśnione tutaj od prawej do lewej):

 wprowadzanie numeryczne (wymiary)

d← przypisz to do d

×/ pomnóż wymiary (znajdzie liczbę komórek)

c← przypisz to do c

⎕× pomnóż to przez wprowadzanie numeryczne (gęstość)

 zaokrąglić w dół

1 2⍴⍨ cyklicznie powtarzaj jeden i dwa do tej długości

c↑ przedłuż to do długości c , dopełniając zerami

d⍴ użyj d (wymiary), aby zmienić kształt

{ zastosuj do tego tę anonimową funkcję (wyjaśnioną tutaj od lewej do prawej):

  ⍵[ prawy argument (lista zer, jedynek i dwójek) indeksowany według

   ?⍨ przetasowane wskaźniki do

   ⍴⍵ długość argumentu

  ]

}

]

{ zastosuj następującą anonimową funkcję (wyjaśnioną od prawej do lewej):

0S⍵ zastosuj S z 0 (w dół) jako lewym argumentem, a grid jako prawym argumentem

1S z tym jako prawym argumentem, zastosuj S z 1 (prawym) jako lewym argumentem

}⍣≡ dopóki dwie kolejne iteracje nie będą identyczne (korek drogowy)

Notatki

  1. Wymaga ⎕IO←0, co jest domyślne w wielu systemach.

  2. Monituje o (wysokość, szerokość), a następnie o gęstość.

  3. Nie korzysta z żadnego wbudowanego automatu.

  4. Korzysta z wbudowanej obsługi wyrażeń regularnych.

  5. Zatrzymuje się w przypadku korka (żaden samochód nie może się poruszać).

  6. Generuje macierze znaków, w których reprezentuje samochody poruszające się w prawo, samochody poruszające się w dół, a spacje są pustymi drogami.

  7. Jak wyżej, sygnał wyjściowy jest przesyłany do sesji przy częstotliwości 4 Hz, ale częstotliwość można regulować, zmieniając ÷4; np. ÷3wynosi 3 Hz i .3wynosi ³⁄₁₀ Hz.

  8. Łatwiej jest zobaczyć, co się dzieje, jeśli jest wykonywane ]Box on -s=max -f=onnajpierw.

  9. Wymagana dystrybucja jest teraz gwarantowana, a dwa typy samochodów występują dokładnie w 50-50, z wyjątkiem zaokrąglania.

Adám
źródło
Początkowa generacja płytki nie gwarantuje płyty o gęstości wejściowej. Wydaje mi się, że to wybór OP, czy na to pozwolić, czy nie.
JungHwan Min
Och, @JarkoDubbeldam już o to pytał.
JungHwan Min
@JungHwanMin Jak to zrobić? Niech gęstość będzie d. Każda pozycja otrzymuje wartość od 0 do 1. Jeśli od 0 do ᵈ⁄₂ staje się,, . Jeśli pomiędzy ᵈ⁄₂ id staje się a . Jeśli między d i 1 pozostaje pusty.
Adám
Cóż, skrajnym przypadkiem byłoby: każda pozycja w jakiś sposób otrzymuje wartość 0(ponieważ są (pseudo) losowo generowane (pseudo) niezależnie, bardzo nieprawdopodobne, ale możliwe). Twoja tablica jest pełna s.
JungHwan Min
@JungHwanMin Ah, rozumiem, co masz na myśli.
Adám
1

Java (624 bajtów + 18 bajtów dla Java.awt. * = 642 bajtów)

static void k(double b,final int c,final int d){final int[][]a=new int[c+1][d+1];int i=0,j;for(;i<c;i++){for(j=0;j<d;j++){a[i][j]=Math.random()<b?Math.random()<0.5?1:2:0;}}Frame e=new Frame(){public void paint(Graphics g){setVisible(1>0);int i=0,j;for(;i<c;i++){for(j=0;j<d;j++){g.setColor(a[i][j]==2?Color.BLUE:a[i][j]==1?Color.RED:Color.WHITE);g.drawLine(i,j,i,j);}}for(i=c-1;i>=0;i--){for(j=d-1;j>=0;j--){if(a[i][j]==1&&a[i][(j+1)%d]==0){a[i][(j+1)%d]=1;a[i][j]=0;}else if(a[i][j]>1&&a[(i+1)%c][j]==0){a[(i+1)%c][j]=2;a[i][j]=0;}}}}};e.show();while(1>0){e.setSize(c,d+i++%2);try{Thread.sleep(400L);}catch(Exception f){}}}

Nie golfowany:

static void k(double b,final int c,final int d){
        final int[][]a=new int[c+1][d+1];
        int i=0,j;
        for(;i<c;i++) {
            for(j=0;j<d;j++) {
                a[i][j]=Math.random()<b?Math.random()<0.5?1:2:0;
            }
        }

        Frame e=new Frame(){
            public void paint(Graphics g){
                setVisible(1>0);
                int i=0,j;
                for(;i<c;i++) {
                    for(j=0;j<d;j++) {
                        g.setColor(a[i][j]==2?Color.BLUE:a[i][j]==1?Color.RED:Color.WHITE);
                        g.drawLine(i,j,i,j);
                    }
                }
                for(i=c-1;i>=0;i--) {
                    for(j=d-1;j>=0;j--) {
                        if(a[i][j]==1&&a[i][(j+1)%d]==0){
                            a[i][(j+1)%d]=1;a[i][j]=0;
                        }else if(a[i][j]>1&&a[(i+1)%c][j]==0){
                            a[(i+1)%c][j]=2;a[i][j]=0;
                        }
                    }
                }
            }
        };
        e.show();
        while(1>0){e.setSize(c,d+i++%2);try{Thread.sleep(400L);}catch(Exception f){}}
    }

Obrazek:

wprowadź opis zdjęcia tutaj

Urna Magicznej Ośmiornicy
źródło
Nie znam java, ale czy czerwone, niebieskie i białe to najkrótsze nazwy kolorów, których możesz użyć? (być może szary jest opcją, oszczędzając jeden bajt kontra biały)
JAD
Zrzut ekranu wydaje się pokazywać ten sam problem, co opisałem tutaj codegolf.stackexchange.com/questions/104742/a-2d-traffic-jam/...
qwr