Amidakuji (阿 弥陀 籤) semplificazione


10

Se hai mai avuto esposizione alla cultura giapponese o dell'Asia orientale, avrai sicuramente incontrato il gioco Amidakuji:

inserisci qui la descrizione dell'immagine

Come spiega Wikipedia , è un tipo di lotteria disegnata su carta e utilizzata per selezionare casualmente una permutazione di N oggetti.

Ad esempio, può essere utilizzato per assegnare in modo casuale una sequenza iniziale a N persone, oppure N premi a N persone e così via.

Il trucco per capire perché il gioco rappresenta una permutazione è rendersi conto che ogni colpo orizzontale (chiamato "gamba") scambia i suoi due oggetti in posizione.

La stessa pagina di Wikipedia spiega anche che ogni permutazione P di N elementi corrisponde a un numero infinito di diagrammi di Amidakuji. Quelli con il minor numero di tratti orizzontali (gambe) sono chiamati "numeri primi" di quella particolare permutazione P.

Il tuo compito è quello di ricevere un diagramma Amidakuji con 2 o più linee verticali (in questo esempio sono 6) in questo formato (meno le lettere):

A B C D E F
| | | | | |
|-| |-| |-|
| |-| |-| |
| | | | |-|
| |-| |-| |
| | |-| |-|
| | |-| | |
|-| | |-| |
|-| |-| | |
| |-| | |-|
| | | | | |
B C A D F E

E produce uno dei suoi numeri primi (di nuovo, meno le lettere):

A B C D E F
| | | | | |
|-| | | |-|
| |-| | | |
| | | | | |
B C A D F E

La prima e l'ultima riga con le lettere non fanno parte del formato. Li ho aggiunti qui per mostrare la permutazione. Inoltre, non è necessario che la prima o l'ultima riga non contengano gambe |-|, che l'output sia il più compatto possibile.

Questo particolare esempio di input è una delle (infinite) rappresentazioni ASCII del diagramma di Amidakuji nella parte superiore della pagina di Wikipedia.

C'è una regola non ovvia su questi diagrammi ASCII: le gambe adiacenti sono vietate.

|-|-|  <-  NO, this does not represent a single swap!

Wikipedia spiega una procedura standard per ottenere un numero primo da un diagramma, chiamato "bubblization", che consiste nell'applicare ripetutamente le seguenti semplificazioni:

1) Forcella destra a sinistra:

| |-|      |-| |
|-| |  ->  | |-|
| |-|      |-| |

2) Eliminare i doppi:

|-|        | |
|-|   ->   | |

Non sono sicuro che questa spiegazione sia inequivocabile. Il codice può utilizzare quella tecnica o qualsiasi altro algoritmo che produce i numeri primi richiesti.

Il codice più corto vince.

Si applicano le norme e le indennità standard. (Se l'input non è valido, il programma potrebbe prendere fuoco. I formati di input / output possono essere stdin / stdout, argomento stringa, elenco di righe, matrice di caratteri, qualunque cosa funzioni meglio per te, ecc.)

inserisci qui la descrizione dell'immagine


3
Questa è una sfida molto interessante. Potrei impiegare un po 'a produrre una soluzione non golfata, eh.
JosiahRyanW,

L'output deve essere il più compatto possibile o è consentita una quantità di spazio verticale purché il numero di gambe sia minimo?
Laikoni,

@Laikoni è ammessa qualsiasi quantità di spazio verticale.
Tobia,

La bubblization e la bubblization inversa raggiungono lo stesso risultato Amidakuji?
l4m2

@ l4m2 che cos'è la bubblization inversa?
Tobia,

Risposte:


4

Python 2 , 322 240 byte

def f(X):
 X=[[c>' 'for c in s.split('|')]for s in X.split('\n')];h=L=len(X[0])-1;p=range(L)
 for x in X:p=[a-x[a]+x[a+1]for a in p]
 while h:h=i=0;exec"if p[i]>p[i+1]:print'|'+i*' |'+'-|'+(L-i-2)*' |';h=p[i],p[i+1]=p[i+1],p[i]\ni+=1\n"*~-L

Provalo online!

Una funzione che accetta la stringa nella forma specificata e stampa anche l'Amidakuji ridotto in quella forma.

L'idea di base qui è di convertire prima l'input in una permutazione (nel for x in Xloop); e poi nel whileciclo, esegui una sorta di bolla di quella permutazione, poiché, come osserva l'articolo di Wikipedia, questo si traduce in un Amidakuji "principale".


Wow. Ho appena trascorso molto tempo a creare una versione di Python 3, ma sono 526 byte, eh.
JosiahRyanW,

Ho appena inserito centinaia di diagrammi casuali nel tuo codice e posso confermare che genera numeri primi corretti!
Tobia,

3

Haskell , 288 byte

p x(_:[])=x
p(x:y:z)(_:b:c)|b=='-'=y:p(x:z)c|0<1=x:p(y:z)c
c 0='-'
c _=' '
_#1="|"
m#n='|':c m:(m-1)#(n-1)
p?q=(p:fst q,snd q)
f%b|b==f b=b|0<1=f%f b
f l=reverse$snd$(g 0)%(foldl p[1..n]l,[])where n=1+div(length$l!!0)2;g b((x:y:z),a)|x>y=y?g(b+1)(x:z,a++[b#n])|0<1=x?g(b+1)(y:z,a);g _ x=x

Provalo online!

Spiegazione

-- the function p performs the permutation of a list
-- according to a single line from amidakuji board
p x (_:[]) = x
p (x:y:z) (_:b:c)
    | b == '-' = y : p (x : z) c
    | otherwise = x : p (y : z) c

-- helper to select either leg '-' or empty cell
c 0 = '-'
c _ = ' '

-- the # operator generates an amidakuji line containing one leg
-- which corresponds to one swap during bubble sort

-- terminal case, just one edge left
_ # 1 = "|"
-- each cell contains an edge '|' and either space or a '-' for the "active" cell
m # n = '|' : c m : (m - 1) # (n - 1)

-- helper to find the limit value of a function iteration
f % b
    | b == f b = b  -- return the value if it is unchanged by the function application 
    | otherwise = f % f b -- otherwise repeat

-- helper to appropriately combine q which is the result of invocation of 
-- the function g (see below), and a character p
p ? q = (p : fst q, snd q)

-- the function that does the work
f l = reverse $ snd $ (g 0) % (foldl p [1..n] l, []) where
    -- number of lines on the board
    n = 1 + div (length $ l !! 0) 2
    -- apply one iteration of bubble sort yielding (X, Y)
    -- where X is partially sorted list and Y is the output amidakuji
    g b ((x:y:z), a)
        -- if we need to swap two elements, do it and add a line to our board
        | x > y = y ? g (b + 1) (x:z, a ++ [b # n])
        -- if we don't need to, just proceed further
        | otherwise = x ? g (b + 1) (y:z, a)
    -- terminal case when there is only one element in the list
    g _ x = x

Buon lavoro! Ho fornito migliaia di diagrammi casuali al tuo codice e li ho risolti tutti.
Tobia,

(_:[])può essere giusto [_]e p?q=(p:fst q,snd q)può essere p?(f,s)=(p:f,s). Invece di definire c 0='-';c _=' ';e quindi utilizzare c m, " -"!!(0^abs m)dovrebbe funzionare.
Laikoni,

(g 0)non ha bisogno di parentesi e a letin a guard è più corto di where. Tutti insieme 274 byte: provalo online!
Laikoni,

La funzione fixpoint %può essere integrata con until(\x->g 0 x==x)(g 0).
Laikoni,

2

Retina 0.8.2 , 105 byte

$
¶$%`
r`.?.\G
 1$.'$*
+r-1=`\|(-?.?[- 1]*¶.*)(1+)
$2$1
-
 
1G`
;{`\b(1+) \1
$1-$1
*`1+
|
(1+)-(1+)
$2 $1

Provalo online! Spiegazione:

$
¶$%`

Duplica l'ultima riga.

r`.?.\G
 1$.'$*

Numero le colonne nell'ultima riga.

+r-1=`\|(-?.?[- 1]*¶.*)(1+)
$2$1

Sposta i numeri verso l'alto fino a quando non arrivano alla prima riga. Ad ogni iterazione, -1=viene spostato solo il numero più a destra . Viene spostato all'estrema destra, a |meno che non sia preceduto da a, -nel qual caso viene spostato al precedente |. ( rIndica che la regex viene elaborata come se fosse un lookbehind, il che rende marginalmente più facile abbinare questo caso.) Questo calcola la permutazione che l'Amidakuji trasforma in ordine ordinato.

-
 
1G`

Mantieni solo l'elenco dei numeri, eliminando se -e qualsiasi cosa dopo la prima riga.

;{`

Il resto del programma viene quindi ripetuto riordinando l'elenco in ordine, ma l'elenco finale non viene stampato, tuttavia poiché ci vuole un'iterazione per Retina 0.8.2 per notare che l'elenco è in ordine, una linea senza legami è generato alla fine, che credo sia accettabile.

\b(1+) \1
$1-$1

Contrassegna tutte le coppie disponibili di numeri non ordinati adiacenti con -s per le gambe.

*`1+
|

Stampa le gambe ma con i numeri sostituiti con |s.

(1+)-(1+)
$2 $1

Effettuare effettivamente gli swap.


Hai qualche consiglio su come eseguire il tuo codice con Retina.exe ? Penso di avere la fonte corretta (105 byte) ma non produce nulla. Ho provato Hello World dagli esempi Retina e funziona. Puoi caricare il sorgente da qualche parte, o Base64 codificarlo e metterlo in un pastebin, nel caso in cui ho sbagliato la codifica?
Tobia,

@Tobia Siamo spiacenti, ma non ricordo come usare Retina.exe; Penso che avrei potuto usarlo una o due volte, ma in questi giorni uso solo Provalo online.
Neil,

LOL Sono stupido! Stavo usando una versione all'avanguardia invece di 0.8.2. Ora ho il mio cablaggio per alimentare centinaia di diagrammi casuali al tuo codice e posso confermare che restituisce sempre i numeri primi corretti. Buon lavoro!
Tobia,

@Tobia Grazie per il test! Modifiche necessarie per Retina 1: $**; -1=0; 1_; ;.(approssimativamente); **\.
Neil,

1

Python 3 , 524 488 486 byte

-38 byte grazie agli ovs!

from numpy import*
A=array;E=array_equal
K=[0]
def r(a,m,n):
	X=len(m);Y=len(m[0]);W,H=a.shape
	for x in range(W-X+1):
		for y in range(H-Y+1):
			if E(a[x:x+X,y:y+Y],A(m)):a[x:x+X,y:y+Y]=A(n)
	return a
def p(a):
	b=A([[j>" "for j in i]for i in[i.split("|")for i in a.split("\n")]])
	while E(a,b)<1:a=b;Z=K*3;O=[0,1,0];T=[K+O,O+K]*2;D=[O,O],[Z,Z];P=[Z,O],[O,Z];*R,_=T;_,*L=T;b=r(r(r(r(r(r(a[any(a,1)],R,L),*D),*P),L,R),*D),*P)
	for i in a:print("",*[" -"[j]for j in i[1:-1]],"",sep="|")

Provalo online!

Questo converte l'Amidakuji in un array binario 2D e lo riduce direttamente usando le regole.


Sono curioso del tuo approccio; Darò un'occhiata! Nel frattempo, è possibile salvare alcuni byte sostituendoli " "+i.replace("|","")+" "con i.split("|")in. la tua prima rigap funzione ...
Chas Brown,

Qualche altra modifica standard al golf in pitone per arrivare a 479 byte .
Chas Brown,


Yah, non sono sicuro del perché stia succedendo ...
Chas Brown,

Non sempre ... a volte dalla forcella destra alla forcella sinistra non è possibile, ma dalla forcella sinistra alla forcella destra lo è. In quel caso specifico, è solo una questione di fare il contrario lì. Forse devo fare entrambe le cose?
JosiahRyanW,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.