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 |-|, né 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.