Programowanie cebuli


22

Używając tylko drukowalnego ASCII (kody szesnastkowe od 20 do 7E), napisz kwadratowy program podstawowy N × N bez komentarzy, który jest otoczony przez kolejne 4 warstwy , tworząc kwadratowy program (N + 8) × (N + 8) (N> 0) . Dla N = 3 układ (który ma zostać zastąpiony rzeczywistym kodem) wygląda następująco:

44444444444
43333333334
43222222234
43211111234
4321CCC1234
4321CCC1234
4321CCC1234
43211111234
43222222234
43333333334
44444444444
  • C reprezentują podstawowy program 3 × 3.
  • Jedynki oznaczają pierwszą warstwę, dwójki oznaczają drugą warstwę itp.

Program zawsze przyjmuje ciąg liczb całkowitych oddzielonych spacjami, na przykład 0 -1 31 -1 2 2 2przez stdin lub podobny (powinny to być zwykłe liczby, bez cudzysłowów, nawiasów itp.). Wynik zależy od tego, które części układu zostały uruchomione.

Istnieje pięć sposobów uruchamiania programu (nowe wiersze są uwzględniane w biegu). Każdy robi coś innego niż lista:

  1. Uruchom tylko rdzeń:

    CCC
    CCC
    CCC
    

    Oblicza to maksymalne wartości bezwzględne elementów listy wejściowej i drukuje COREwiele razy w nowym wierszu. Jeśli maksimum wynosi 0, nic nie jest wyprowadzane (nowa linia jest w porządku).

    • Wyjściem 0 -1 31 -1 2 2 2byłoby

      CORE
      CORE
      ...
      

      31 razy.

  2. Uruchom rdzeń z warstwą 1:

    11111
    1CCC1
    1CCC1
    1CCC1
    11111
    

    Daje to średnią (średnią arytmetyczną ) wartości listy do standardowej precyzji zmiennoprzecinkowej.

    • Wynik 0 -1 31 -1 2 2 2wyniósłby 35/7 = 5( 5.0jest w porządku).
  3. Uruchom rdzeń z warstwami 1 i 2:

    2222222
    2111112
    21CCC12
    21CCC12
    21CCC12
    2111112
    2222222
    

    Powoduje to odwrócenie listy rozdzielonych spacjami listy danych wejściowych.

    • Wyjściem 0 -1 31 -1 2 2 2byłoby 2 2 2 -1 31 -1 0.
  4. Uruchom rdzeń z warstwami 1, 2 i 3 (wzór powinien być oczywisty).
    W ten sposób powstaje rozdzielona spacjami lista posortowanej listy danych wejściowych.

    • Wyjściem 0 -1 31 -1 2 2 2byłoby -1 -1 0 2 2 2 31.
  5. Uruchom rdzeń z warstwami 1, 2, 3 i 4.
    Spowoduje to utworzenie rozdzielonej spacjami listy danych wejściowych z usuniętymi duplikatami, kolejność nie ma znaczenia.

    • Wyjściem dla 0 -1 31 -1 2 2 2może być -1 0 2 31.

Wszystkie dane wyjściowe są w standardowej lub podobnej alternatywie.

Tylko te 5 kombinacji układów ma określone zachowanie.

Notatki

  • Komentarze nie są dozwolone w rdzeniu, warstwach ani ich kombinacjach. Kod, który nie działa ani nie robi nic konstruktywnego, nie jest liczony jako komentarz.
  • Pamiętaj, że rdzeń może mieć dowolne (dodatnie) wymiary N × N, ale warstwy mają grubość tylko jednego znaku.
  • Możesz założyć, że na wejściu nie ma spacji początkowych ani końcowych, a dokładnie jedna spacja między liczbami. Zawsze będzie zawierać co najmniej jedną liczbę. (Listy wyników również powinny być sformatowane w ten sposób.)
  • Możesz założyć, że lista i obliczenia niezbędne do otrzymania danych wyjściowych nie będą miały wartości, które przepełniają (lub zaniżają) liczby całkowite (o ile ich maksymalna wartość jest rozsądna, np. 2 16 ).

Punktacja

Pisanie tego programu normalnie byłoby łatwe. Pisanie z małym rdzeniem jest trudne.

Program z najmniejszym rozmiarem rdzenia (najmniejszym N) wygrywa. W przypadku remisów zwycięzcą jest pełny program (kwadrat (N + 8) × (N + 8)) z najmniejszą liczbą wyraźnych znaków (nie licząc nowych linii).

Podaj swoją wartość N na górze swojej odpowiedzi.


1
Pomyślałem, że będzie to również jeden z tych nowych typów
Optimizer

Czy mogę używać języka, który ignoruje wszystko po nowej linii?
isaacg

1
@isaacg Tak (o ile nowa linia nie jest uważana za znak komentarza, co byłoby dziwne).
Calvin's Hobbies

3
@Optimizer Nie kusz mnie ... „ Każda odpowiedź dodaje nową warstwę do cebuli kodu, dzięki czemu robi coś nowego z listą ...
Hobby Calvina

1
@Optimizer Nie (Wiem, że te zasady we / wy są dość surowe, ale w celu zachowania spójności we wszystkich językach).
Calvin's Hobbies

Odpowiedzi:


10

CJam, N = 5, 27 (26) unikalnych znaków

Ma 26 znaków, jeśli nie liczę spacji. Program można tak naprawdę przekonwertować na taki, który nie używa spacji, po prostu wypełniając wszystkie puste spacje brakiem _;operacji (np. Który duplikuje górny element stosu, a następnie odrzuca, lub sortując tablicę raz za razem), ale to oderwałby się od rzeczywistego kodu.

l~]_|S*      
{l~]$S*      
 {l~]W%S*    
  {l~]_,\    
   {l~]{z    
    }%$W=    
    "CORE    
    "*       
         }   
   ;:+d\/ }  
  ;        } 
 ;          }
;            

Sprawdź to tutaj.

Rdzeń jest

l~]{z
}%$W=
"CORE
"*

(Plus pusta linia.)

Jestem całkiem pewien, że N = 4nie da się tego zrobić w CJam (i jestem pewien, że Dennis mnie przekona inaczej: D). Powyższe ma 17 znaków i chociaż może być możliwe sprowadzenie go do 16 (np. Jeśli CJam nie miał błędu do udławienia się :z, co wymaga {z}%lub za pomocą ARGV), nie sądzę, że możesz go dopasować w układzie bez wprowadzania podziału linii CORE.

Wszystkie wdrożenia są bardzo prostymi rozwiązaniami dla danych zadań. Wszystkie zaczynają się od tego, l~]który czyta STDIN, ocenia go i umieszcza w tablicy.

Poprzednia warstwa jest zawsze otoczona {...}, co sprawia, że ​​jest to blok, który nie jest automatycznie wykonywany. I zamiast go wykonać, po prostu odrzucam go ze stosu ;, więc żadna warstwa nie zależy od kodu z poprzedniej warstwy. W Warstwie 1 kod nie mieścił się w pierwszym wierszu, więc kontynuowałem go po odrzuceniu bloku podstawowego.

Teraz rzeczywiste programy:

  • Rdzeń:

    {z}%$W="CORE
    "*
    

    Mapuj absna listę, sortuj, weź ostatni element, powtórz CORE(i podział linii) tyle razy.

  • Warstwa 1:

    _,\:+d\/
    

    Zduplikuj listę, weź długość, zamień elementy stosu, uzyskaj sumę, rzuć na double, zamień elementy stosu, podziel. Myślę, że może to być krótsze, ale nie ma na to zachęty.

  • Warstwa 2:

    W%S*
    

    Odwróć tablicę, riff ze spacjami.

  • Warstwa 3:

    $S*
    

    Posortuj tablicę, riffle ze spacjami.

  • Warstwa 4:

    Duplikuj, weź zestaw zjednoczenia, riffle ze spacjami.

Możliwe są również inne optymalizacje, takie jak ponowne użycie ;i *Swarstwy 2, ale znowu, ale to nie wpływa na wynik.


17

Python 2 - N = 17, 53 znaków

Och, uwielbiam wyzwania związane z układem źródeł w Pythonie ...

i=4                     ;
ii=3                    ;
iii=2                   ;
iiii=1                  ;
iiiii=0;R=raw_input     ;
iiiii;w=R().split()     ;
iiiii;n=map(int,w)      ;
iiiii;S=set(n);M=max    ;
iiiii;s=sorted(n)       ;
iiiii;J="\n".join       ;
iiiii;j=" ".join        ;
iiiii;k=M(map(abs,n))   ;
iiiii;A=J(["CORE"]*k)   ;
iiiii;B=sum(n)/len(n)   ;
iiiii;C=j(w[::-1])      ;
iiiii;D=j(map(str,s))   ;
iiiii;E=j(map(str,S))   ;
iiiii;P=A,B,C,D,E       ;
iiiii;print P[i]        ;
iiiii;" /__----__\  "   ;
iiiii;"|/ (')(') \| "   ;
iiii;"  \   __   /  "   ;
iii;"   ,'--__--'.   "  ;
ii;"   /    :|    \   " ;
i;"   (_)   :|   (_)   ";

Wciąż jednak jest trochę niewykorzystanych białych znaków.

Nadal mógłbym poprawić unikalną liczbę postaci, ale pozostanę przy lepszej czytelności - jeśli w ogóle istnieje.

Edycja: Och, to znowu Stan !


Prawdopodobnie możesz zapisać niektóre wiersze, aliasingując druk zamiast i=*sztuczki
M.Herzkamp

@ M.Herzkamp: Aliasing printnie jest możliwy w Pythonie 2. Ale na pewno jest miejsce na ulepszenia - być może przy użyciu Pythona 3.
Falko

Nie znam Pythona, ale nie brakuje tej wartości bezwzględnej w wynikowym kodzie wyjściowym -c*max(n)
nutki

@nutki: Masz rację! Nie czytałem uważnie. Ale udało mi się to naprawić.
Falko

6

Python 3: N = 11, 40 różnych znaków

if 1:              
 if 1:             
  if 1:            
   if 1:           
    p=print;R=0    
    a=input()      
    b=a.split()    
    m=map;a=abs    
    E=max;l=len    
    n=m(int,b);    
    C=['CORE']     
   "R=E(m(a,n))"   
   OO=C*R;s=sum    
   "x='\n'.join"   
   "p(x(O))    "   
  "p(s(n)/l(b)) "  
 "p(*b[::-1])    " 
"p(*sorted(n))    "
p(*set(n))         

Dzięki @Falko za bycie moją muzą. Działa to, ponieważ Python nie tworzy nowego zakresu dla każdej instrukcji if, więc zmienne pozostają w instrukcjach zewnętrznych print. Jedną irytującą rzeczą było to, że mapobiekt (w naszym przypadku n) może być użyty tylko raz. Konieczne było więc wykreślenie R=E(...)linii, ale Rnie zostało to zdefiniowane. Dlatego miałem szczęście, że w pierwszym wierszu pozostały cztery miejsca!

Dane wyjściowe można rozwiązać, udostępniając wiele elementów *b[::-1]zamiast listy. Alternatywa ' '.join(...)byłaby zbyt długa.


Piękny! Miło widzieć alternatywne podejście do radzenia sobie ze zmiennymi początkami linii w pythonie. Kilka krótkich instrukcji if i wszystkie te spacje są w porządku. :)
Falko

@Falko: Minusem jest: nie ma miejsca dla Stana :(
M.Herzkamp

2

C (gcc) , N = 15, 47 unikalnych znaków

Zakłada sizeof(int) == 4i sizeof(int*) >= sizeof(int).

;                     ;
 ;                   ; 
  ;                 ;  
   ;           float   
    s;c(a,b)int*a,*    
    b;{b=*b-*a;}i,n    
    ,*f;*q,*R,C,E ;    
    main(a){for(;0<    
    scanf("%i",&a);    
    i=i<abs(a)?a:i,    
    s+=f[n-!0]=a)f=    
    realloc(f,++n*4    
    );qsort(f,n*C,4    
    ,c);for(i=q?R?n    
    :!0:i;i--;a=f[i    
    ])!E|n-i<2|a!=f    
    [i]&&printf(q?R    
    ?R:q:"CORE\n",!    
    q+R?f[i]:s/n);}    
   ;*q="%f";       ;   
  ;*R="%.0f ";      ;  
 ;C=!0;              ; 
;E=!0;                ;

4 warstwy

3 warstwy

2 warstwy

1 warstwa

Rdzeń


0

Runiczne Zaklęcia , N = 9 N = 8, 38 znaków

/ o/\  \     \S\
" //RiU\      \}
@            q "
"        }+1\r @
}   ^U \    {q "
     \{\?)}\+  }
  o\/'|A:{:/R' S
 //r/Ril2=?\?R :
   ,A~/"OC"/=? {
   @| \"RE"\3= =
 D$\' /rqka/l2S?
    i \*@   il\/
   'R1i     Ui ~
 R$/Rak      U \
 ?!D  Rlril1-{=
R   R: }S:{=?\~

Wypróbuj online!

Okazuje się, że się myliłem , zapomniałem już mieć jawne opolecenie s rt, ponieważ wcześniej napotkałem problem z „sortowaniem listy”. Ogranicza to jednak rozmiar danych wejściowych, które może przyjąć program końcowy (8 wartości) z powodu wewnętrznych kosztów polecenia sortowania. Niewielkie ulepszenie może zwiększyć rozmiar wejściowy do 13 kosztem 1 unikalnego znaku lub do 19 dla dwóch unikalnych znaków (wszystkie dodatkowe znaki znajdują się w Warstwie 1 i są dodawane w tym samym czasie, ale zwiększona pojemność stosu IP nie jest potrzebne do Warstwy 3, ponieważ C, L1 i L2 mogą wykonywać swoje obliczenia bez przechowywania całego wejścia w pamięci).

Rdzeń: Wypróbuj online!

Warstwa 1: Wypróbuj online!

Warstwa 2: Wypróbuj online!

Warstwa 3: Wypróbuj online!

Warstwa 4: Wypróbuj online!

Dalsza kompresja jest wysoce nieprawdopodobna, ze względu na mniejszą przestrzeń wymagającą zwiększenia liczby znaków kontroli przepływu. Znalazłem układ, który dał 9 pustych miejsc w programie podstawowym, ale to nie wystarczy, ponieważ potrzebujemy (poprawnie ułożonego) 15.

Wyjaśnienie działania któregokolwiek z tych programów jest trudne bez wizualnej mapy ścieżki IP, co jest uciążliwe i czasochłonne w budowie. Początkowym punktem wejścia jest lewy górny róg programu podstawowego ( ^), który pozwala na spójną kontrolę przepływu w miarę dodawania nowych warstw, ponieważ każda warstwa ma możliwość przechwycenia nowo dodanej linii u góry lub u dołu.

Warstwy 1 i 2 przechwytują na dole (tak, że górna linia pozostaje pusta dla przyszłych warstw), a następnie wykonują operacje wzdłuż prawej krawędzi (pętla ułożona pionowo). Warstwa 1 jest nieco za długa i zajmuje również 3 znaki wzdłuż górnej krawędzi, ale diagonalny odbłyśnik ( \) w prawym górnym rogu wyrównuje adres IP z następną iteracją następnej pętli.

Warstwa 3 przechwytuje wzdłuż górnej krawędzi w celu pobrania pierwszej wartości wejściowej przed przekierowaniem do dolnej krawędzi (warstwa 4 pozostawia NOP w tej kolumnie w dolnej linii) i odczytuje pełne dane wejściowe za pomocą pętli dolnej krawędzi, przekierowując w dół polecenie ( D) w lewym dolnym rogu. Stamtąd IP odbija się kilka razy, zanim kończy się w $pętli output ( ) w lewym dolnym rogu w celu rozdzielenia wartości między spacjami.

Warstwa 4 wykorzystuje całą funkcjonalność warstwy 3 (stąd puste miejsce), ale przechwytuje własną nową górną krawędź (lewy górny róg), aby wykonać swoją własną funkcjonalność na końcu przetwarzania warstwy 3. Lewy górny róg wstawia ciąg znaków, "@"który służy do oznaczenia końca tablicy przed wejściem do pętli przetwarzania wzdłuż dolnej krawędzi . Jeśli zostanie znaleziona zduplikowana wartość, jest ona wyskakiwana (w ~prawym dolnym rogu), w przeciwnym razie brana jest gałąź, która zużywa nową prawą krawędź. Ta gałąź boczna sprawdza, czy osiągnięto koniec tablicy, a jeśli tak, wyjdź i przejdź do tej samej rozdzielonej spacjami pętli wyjściowej z warstwy 3. W przeciwnym razie użyj pustego miejsca na warstwie 3, aby powrócić do głównej pętla.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.