Powiększ diamentową płytkę

27

Każdy regularny sześciokąt może być wyłożony diamentami, na przykład tak:

   ______
  /_/_/\_\
 /_/\_\/\_\
/\_\/_/\/_/\
\/_/\_\/_/\/
 \_\/_/\_\/
  \_\_\/_/

Rozważymy powyższe kafelki wielkości 1(ponieważ boki diamentów są wykonane z jednego /lub \każdego). Ten sam kafelek wielkości 2wyglądałby tak:

      ____________ 
     /   /   /\   \  
    /___/___/  \___\ 
   /   /\   \  /\   \  
  /___/  \___\/  \___\ 
 /\   \  /   /\  /   /\  
/  \___\/___/  \/___/  \ 
\  /   /\   \  /   /\  /
 \/___/  \___\/___/  \/ 
  \   \  /   /\   \  /
   \___\/___/  \___\/ 
    \   \   \  /   /
     \___\___\/___/ 

Twoim zadaniem jest otrzymanie takiego kafelka grafiki ASCII (wielkości 1) jako danych wejściowych, wraz z dodatnią liczbą całkowitą N(w postaci dziesiętnej lub jednostkowej), określającą rozmiar pożądanego wyniku. Następnie powinieneś wypisać skalowaną wersję tego samego kafelka.

Zauważ, że sześciokąt może mieć dowolny rozmiar i tak mały jak 1x1x1 (zawierający trzy diamenty).

Ani dane wejściowe, ani wyjściowe nie mogą zawierać spacji końcowych ani więcej spacji wiodących niż jest to konieczne do wyrównania kształtu sześciokąta. Zarówno wejście, jak i wyjście mogą opcjonalnie zawierać jedną końcową linię nowego wiersza (ten wybór nie musi być taki sam dla wejścia i wyjścia).

Możesz napisać program lub funkcję, pobierając dane wejściowe przez STDIN (lub najbliższą alternatywę), argument wiersza poleceń lub argument funkcji i wypisując wynik przez STDOUT (lub najbliższą alternatywę), wartość zwracaną funkcji lub parametr funkcji (wyjściowej).

To jest kod golfowy, więc wygrywa najkrótsza odpowiedź (w bajtach).

Przykładowe tilings

Oto garść nachyleń wejściowych, których możesz użyć do przetestowania swojego zgłoszenia.

 __
/_/\
\_\/

  ____
 /_/\_\
/\_\/_/\
\/_/\_\/
 \_\/_/

   ______
  /_/_/\_\
 /_/\_\/\_\
/\_\/_/\/_/\
\/_/\_\/_/\/
 \_\/_/\_\/
  \_\_\/_/

    ________
   /_/\_\_\_\
  /\_\/\_\_\_\
 /\/_/\/_/_/\_\
/\/\_\/_/_/\/\_\ 
\/\/_/\_\_\/\/_/
 \/\_\/_/\_\/_/
  \/\_\_\/_/_/
   \/_/_/_/_/

Poniższy fragment kodu zawiera odpowiednie dane wyjściowe dla danych wejściowych N = 1przez N = 6.

Martin Ender
źródło
20
Widzę, że interesują Cię diamenty, skoro masz je obok swojej nazwy użytkownika.
użytkownik12205
3
@ace: Wiesz, co mówią: diamenty są najlepszym przyjacielem moderatora.
Alex A.,
Myślę, że znam odpowiedź, ale mam nadzieję, że się mylę: wiodące puste linie byłyby liczone jako wiodące miejsce, które zadeklarowałeś jako nielegalne? Moje początkowe rozwiązanie ma N-1wiodące puste linie. :(
Reto Koradi
@RetoKoradi Rzeczywiście, brak wiodących nowych linii. Przepraszam.
Martin Ender
1
Pomyślałem. Kosztowało mnie około 10 bajtów. Nie tak źle, jak wyglądało, kiedy po raz pierwszy rozpoznałem problem.
Reto Koradi

Odpowiedzi:

8

CJam, 85 79 76 72 bajtów

li:Tlf*NqN/T,f{ff{"_/"2$#_1<@+*~ST*@t}:+z{S+e`);e~{"_ "/"__"*W%}T2**N}/}

Rozmiar powinien znajdować się w pierwszej linii. I następuje diament.

Niezbyt dobrze grał w golfa ... A połowa postaci pochodziła ze szczegółów.

Objaśnienia (poprzedniej wersji)

li:T            e# Read the size and save to T.
qN/             e# Read and split to lines.
\,fm*           e# Convert each character X to [X 0] [X 1]... [X T(]
{~              e# For each [X I] in each line:
    ST*         e# T spaces.
    \           e# I.
    "_\\"3$#    e# If X is '_, '\ or '/, return Y = 0, 1, -1 respectively.
    _W>@+       e# If it was '_ or '\, increase I by one.
    *(          e# I * Y - 1.
    @t          e# Set the character at that position to X.
}f%
:z:+            e# Make the returned lists from each iteration across T lines.
{S+e`);e~N+}%   e# Boring details to remove trailing spaces and append a newline.
T(>(\s          e# Boring details to extract the first line and only work on others.
{_{"_ "/"__"*W%}2*_@=!}g
                e# Boring details to make underlines expand left and right.
jimmy23013
źródło
10

Python 2, 164

def g(s,n,j=1):
 for W in s.split("\n"):exec"O=p='';d=0\nfor c in W:q=' _'[j*'_'in p+c];e=[n-j,j-1][c=='/'];O+=q*(e+d)+[c,q][c>'^'];p=c;d=n+~e\nprint O;j-=1;"*j;j=n

Dane wyjściowe dotyczące przypadków testowych.

Co się tu dzieje?

Główną ideą jest to, że każda postać w oryginale wysadza się w n*nblok. Na przykład dla n = 4 /może być

   /
  /
 /
/___

Oryginalny znak pojawia się raz w każdej linii, a po obu stronach jest dopełnienie. Tutaj jest po lewej i _po prawej stronie. Tylko dolny rząd może być wypełniony '_'; reszta jest zawsze ' '.

Główną trudnością jest to, że wypełnienie po prawej stronie może zależeć od nadchodzącego symbolu. W szczególności '/ 'ma inną wyściółkę niż '/_', więc potrzebujemy trochę przyszłości. Co więcej, aby uniknąć spacji, musimy pamiętać, że jesteśmy przy ostatnim symbolu i powstrzymujemy się od dopełniania po prawej stronie.

Rozwiązujemy oba te problemy, wypełniając tylko lewą stronę aktualnej postaci. Kiedy to robimy, wykonujemy również prawe dopełnienie od poprzedniego znaku, używając bieżącego symbolu dopełniania. Tak więc wypisujemy prawe dopełnienie należne z poprzedniego znaku, lewe dopełnienie z bieżącego znaku, a następnie bieżący znak. Przechowujemy także kwotę „długu” wypełniającego, którą następny znak będzie musiał zapłacić.

Teraz przejdźmy do kodu.

def g(s,n,j=1):
    for W in s.split("\n"):
        while j:
            O=p='';d=0
            for c in W:
                q=' _'[j*'_'in p+c]
                e=[n-j,j-1][c=='/']
                O+=q*(e+d)+[c,q][c>'^']
                p=c
                d=n+~e
            print O;j-=1;
        j=n

Ciąg wejściowy to, sa współczynnik skali to n. Przechodzimy linia po linii, drukując nlinie dla każdej linii wejściowej W, z kopiami indeksowanymi j=n,n-1,...,2,1. Pierwszy wiersz jest kopiowany tylko raz, co osiągamy poprzez inicjalizację jna 1, ale zmianę na nkażdą pętlę.

Iterujemy przez linię wejściową, kumulując linię do wydrukowania O. Najpierw ustalamy odpowiedni znak wypełniający q, który jest podkreśleniem, jeśli znajdujemy się w dolnej linii, a albo obecny, albo poprzedni znak jest znakiem podkreślenia, a w przeciwnym razie spacją.

Następnie decydujemy o ilości wypełnienia po lewej ( e). W przypadku /, to jest j-1(maleje wraz ze spadkiem liczby kopii linia) i komplementarnych n-jdo \. Inne postacie traktujemy w ten sam sposób. Na przykład, chociaż _wydaje się, że daje rząd nznaków podkreślenia, w rzeczywistości daje pojedynczy znak podkreślenia, wypełniony znakami podkreślenia po lewej i prawej stronie. To wydaje się nieefektywne, ale pozwala nam pracuje _i na tej samej podstawie, jak /i \The położenia „centralnej” podkreślenia nie ma znaczenia, więc to i guzek z \; ten wybór sprawia, że ​​górny rząd działa bez specjalnej obudowy.

Następnie dodajemy do ciągu wyjściowego. Ustaliliśmy symbol dopełnienia qi bieżącą ilość dopełnienia e, ale musimy także pamiętać o długu dopełniania dz poprzedniego symbolu. Tak więc dodajemy q*(e+d). Następnie dodajemy bieżący symbol c, z tym wyjątkiem, że musimy unikać znaków podkreślenia w wierszu innym niż dolny, co naprawiamy, przekształcając znaki podkreślenia na symbol wypełnienia.

Na koniec rejestrujemy kwotę zadłużenia uzupełniającego, która stanowi uzupełnienie n+~dbieżącej kwoty marginesu uzupełniającego. Nagrywamy również bieżący symbol p, aby później dowiedzieć się, czy był to poprzedni symbol _.

xnor
źródło
3

JavaScript ( ES6 ) 274 281 289 338

// GOLFED
F=(b,n)=>{
b=b[R='replace'](/ |_/g,c=>c[T='repeat'](n))[R](/_(?=[\\\/])/g,'_'[T](n))[R](/\/\\/g,`/${'  '[T](n-1)}\\`)
.split('\n');
for(i=l=b.length*n-n+1;--i;)
b[i]=i%n?b[i+1][R](/_/g,' ')[R](/\/ ?/g,' /')[R](/ \\(.)?/g,'\\$1$1')
:' '[T](i>l/2?n-1:0)+b[i/n];
return b.join('\n')}


// UNGOLFED
U=(b,n)=>{
  b=b
  .replace(/ |_/g,c=>c.repeat(n))
  .replace(/_(?=[\/\\])/g,'_'.repeat(n))
  .replace(/\/\\/g,`/${'  '.repeat(n-1)}\\`)
  .split('\n');
  for(i=l=b.length*n-n+1;--i;)
  {
    if(i%n)
     b[i]=b[i+1]
     .replace(/_/g,' ')
     .replace(/\/ ?/g,' /')
     .replace(/ \\/g,'\\ ').replace(/ +$/,'')
     .replace(/ \\(.)?/g,'\\$1$1')
    else {
      b[i]=b[i/n]
      if(i>l/2)b[i]=' '.repeat(n-1)+b[i];
    }
  }
  return b.join('\n')
}

//TEST

test=[
' __\n/_/\\\n\\_\\/',
'  ____\n /_/\\_\\\n/\\_\\/_/\\\n\\/_/\\_\\/\n \\_\\/_/',
'   ______\n  /_/_/\\_\\\n /_/\\_\\/\\_\\\n/\\_\\/_/\\/_/\\\n\\/_/\\_\\/_/\\/\n \\_\\/_/\\_\\/\n  \\_\\_\\/_/',
'    ________\n   /_/\\_\\_\\_\\\n  /\\_\\/\\_\\_\\_\\\n /\\/_/\\/_/_/\\_\\\n/\\/\\_\\/_/_/\\/\\_\\\n\\/\\/_/\\_\\_\\/\\/_/\n \\/\\_\\/_/\\_\\/_/\n  \\/\\_\\_\\/_/_/\n   \\/_/_/_/_/'
]

test.forEach(t=>{
  var row = '<td>'+t+'<td>'
  for(rr=2;rr<5;rr++)
    row += '<td>'+F(t,rr)+'</td>'
  OUT.innerHTML += '<tr>'+row+'</tr>'
})
td {
  font-family: monospace;
  white-space: pre;
}
(better full page)
<table id=OUT></table>

edc65
źródło
3

Python 2, 217 211 195 194 190

b,f,s='\/ '
R=str.replace
def m(g,n,z=1):
 for d in g.split('\n'):
    for i in range(z):a=z+~i;print[i,a][d[-1]>f]*s+R(R(R(R(d,s,s*n),'_','_ '[i<z-1]*(z+n-1)),f+b,f+s*2*i+b),b+f,b+s*2*a+f);z=n

6 bajtów dzięki Sp3000.

Wywołaj mz pierwszym argumentem będącym diamentem jako łańcuchem, a drugim argumentem numerem powtórzenia.

Jest to oparte na 3-etapowej sekwencji zamiany łańcucha:

  • Najpierw zamień podkreślenia na spacje 2n-1 lub podkreślenia, w zależności od linii.
  • Po drugie, należy wymienić /\w / \, wraz z liczbą miejsc odstępie, począwszy od 2 do 2 * (N-1) w linii.
  • Trzecie zastąpienie \/w \ /, wraz z liczbą miejsc odstępie, począwszy od 2 x (n-1) na 2 po liniach.

Następnie istnieje wiele sposobów na poprawienie wiodących pól i poprawienie pierwszej linii.

Zauważ, że ostatni wiersz programu powinien być tabulatorem, a nie 4 spacjami. Markdown nie obsługuje kart.

isaacg
źródło
Dwa pola golfowe: (i+(n-i+~i)*(d[-1]>f)) --> [i,n+~i][d[-1]>f]i używasz tylko '_'raz, więc marnujesz bajt na ich zdefiniowanie.
Sp3000
3

Python, 272 238 228 243 bajtów

Zaktualizowana wersja, teraz pobiera pojedynczy ciąg jako dane wejściowe, zamiast sekwencji ciągów. Usuwa również końcowe białe znaki, które były obecne we wcześniejszej wersji. Niestety zmiany te zwiększają rozmiar.

s,u,f,b=' _/\\'
r=str.replace
def d(t,n,j=1):
 for p in t.split('\n'):
  for k in range(n-j,n):m,v=n+~k,'_ '[k<n-1];print r(r(r(r(r(r(r(r(p,f+u,'(_'),u+b,'_)'),s,s*n),u,v*n),f,s*m+f+s*k),'(',v*m+f+v*k),b,s*k+b+s*m),')',v*k+b+v*m).rstrip();j=n

Wersja z białymi znakami i instrukcje podzielone na mniejsze jednostki dla czytelności:

s, u, f, b = ' ', '_', '/', '\\'
def d(t, n):
    j = n - 1
    for p in t:
        for k in range(j, n):
            m, v = n - 1 - k, '_ '[k < n - 1]
            q = p[:-1]
            q = q.replace(f + u, '(_')
            q = q.replace(u + b, '_)')
            q = q.replace(s, s * n)
            q = q.replace(u, v * n)
            q = q.replace(f, s * m + f + s * k)
            q = q.replace('(', v * m + f + v * k)
            q = q.replace(b, s * k + b + s * m)
            q = q.replace(')', v * k + b + v * m)
            print q
            j = 0

Podstawowe podejście tutaj:

  1. Zapętlaj wszystkie linie na wejściu.
  2. Dla każdej linii zapętlaj rozmiar wyjściowy N, generując linię wyjściową w każdej iteracji pętli. Istnieje specjalny przypadek dla pierwszego wiersza, w którym generowana jest tylko ostatnia linia wyjściowa, aby uniknąć generowania pustych linii na początku wyniku.
  3. Zastąp każdy znak w wierszu Nznakami, gdzie:
    • Każde miejsce jest zastępowane Nspacjami.
    • Każdy znak podkreślenia jest zastępowany Nspacjami dla pierwszej N -1iteracji pętli i Nznakami podkreślenia dla ostatniej iteracji pętli.
    • Cięcia i ukośniki odwrotne są wypełnione N - 1spacjami lub podkreślnikami.

Najtrudniejszą częścią jest to, że wypełnianie dla ukośników / ukośników używa spacji lub znaków podkreślenia w zależności od następnego (dla ukośników) lub poprzedniego (dla ukośnika) znaku wejściowego. Nie pasowało to do strategii zastępowania ciągów.

To, co zrobiłem, aby rozwiązać ten problem, polega na tym, że najpierw zastępuję niektóre dwie kombinacje postaci różnymi postaciami, aby móc traktować je inaczej podczas faktycznej zamiany. Na przykład /_jest zastąpiony przez (_. Po tym (następuje „ukośnik, po którym następuje podkreślenie”, które można następnie odpowiednio zastąpić.

Główny program używany do testowania funkcji:

import sys
import Golf

n = int(sys.argv[1])
t = ''.join(sys.stdin).rstrip()

Golf.d(t, n)
Reto Koradi
źródło
1
n-1-kjestn+~k
rekurencyjny
W trosce o pełne ujawnienie: właśnie odkryłem, że moje rozwiązanie generuje spacje końcowe. Ponieważ nie jest to dozwolone w definicji wyjściowej, nie spełnia wymagań. W najgorszym przypadku będę musiał dodać jeszcze .rstrip()9 znaków. Mam nadzieję, że poradzę sobie lepiej, a także znalazłem sposób na wycięcie 5 postaci.
Reto Koradi
Wygląda na to, że Twój format wejściowy jest niedozwolony. sys.stdinnie jest dopuszczalnym parametrem wejściowym - musisz manipulować samym łańcuchem.
isaacg
Dobrze można użyć sys.stdini int(sys.argv[1]), ale nie dostaniesz je za darmo przez spodziewałem się, że być przekazany jako zmiennych (czy to uczciwa gra, to można również oczekiwać aliasy rangei replace` i co tam jeszcze trzeba być predefine) .
Martin Ender
@ MartinBüttner Mówi, że mogę wziąć dane wejściowe jako argument funkcji. Czy to nie to, co tutaj robię? I tak zamierzałem zmienić argument funkcji na listę ciągów. Czy to będzie ok? Nie jest to bardzo różne, ponieważ zarówno stdinlista , jak i lista ciągów są ciągami znaków.
Reto Koradi
1

Perl, 132

#!perl -p
INIT{$f=pop}s!.!$&x$f!ge;s! $!! while s!\\+\K\\|/(/)! $1!;
for$x(2..m!/!*$f){print y!_! !r;s!\\.?! \\!g;s!./(.)?!/$1$1!g;s!_ !__!g}

Połączone wejście STDIN i ARGV. Przykład:

$ perl ~/hex.pl <~/hex.txt 3
         __________________
        /     /     /\     \
       /     /     /  \     \
      /_____/_____/    \_____\
     /     /\     \    /\     \
    /     /  \     \  /  \     \
   /_____/    \_____\/    \_____\
  /\     \    /     /\    /     /\
 /  \     \  /     /  \  /     /  \
/    \_____\/_____/    \/_____/    \
\    /     /\     \    /     /\    /
 \  /     /  \     \  /     /  \  /
  \/_____/    \_____\/_____/    \/
   \     \    /     /\     \    /
    \     \  /     /  \     \  /
     \_____\/_____/    \_____\/
      \     \     \    /     /
       \     \     \  /     /
        \_____\_____\/_____/
nutki
źródło
1

Rubinowy 236 237

->i,z{i.split(?\n).map{|l|z.times.map{|y|l.size.times.map{|i|z.times.map{|x|c=l[i]
z<y+2&&(l[i-1..i]=='_\\'||l[i..i+1]=='/_')&&o=?_
(c<?!||(x==y&&c==?\\)||(z==y+1&&c>?^)||(x+y+1==z&&c==?/))&&o=c
o||' '}.join}.join.rstrip}-['']}.join ?\n}

Test online: http://ideone.com/e6XakQ

Oto kod przed golfem:

-> diamond, zoom {
  diamond.split(?\n).map do |l|
    zoom.times.map do |y|
      l.size.times.map do |i|
        zoom.times.map do |x|
          out_char = crt_char = l[i]

          out_char = ' '

          # _ has to be continued under / or \
          if zoom == y+1 && l[i-1..i]=='_\\'
            out_char = ?_
          end
          if zoom == y+1 && l[i..i+1]=='/_'
            out_char = ?_
          end

          # logic to "zoom" \, / and _ characters 
          out_char = crt_char if crt_char == ' '
          out_char = crt_char if x==y && crt_char == ?\\  
          out_char = crt_char if zoom==y+1 && crt_char == ?_
          out_char = crt_char if x+y+1==zoom && crt_char == ?/

          out_char
        end.join
      end.join.rstrip
    end - ['']
  end.join ?\n
}
Cristian Lupascu
źródło