Simplificación de Amidakuji (阿 弥陀 籤)


10

Si alguna vez has tenido alguna exposición a la cultura japonesa o del este asiático, seguramente habrás encontrado el juego Amidakuji:

ingrese la descripción de la imagen aquí

Como explica Wikipedia , es un tipo de lotería dibujada en papel y utilizada para seleccionar aleatoriamente una permutación de N elementos.

Por ejemplo, puede usarse para asignar aleatoriamente una secuencia inicial a N personas, o N premios a N personas, y así sucesivamente.

El truco para comprender por qué el juego representa una permutación es darse cuenta de que cada golpe horizontal (llamado "pierna") intercambia sus dos elementos en su lugar.

La misma página de Wikipedia también explica que cada permutación P de N elementos corresponde a un número infinito de diagramas Amidakuji. Los que tienen el menor número de trazos horizontales (patas) se denominan "primos" de esa permutación particular P.

Su tarea es recibir un diagrama Amidakuji con 2 o más líneas verticales (en este ejemplo son 6) en este formato (menos las letras):

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

Y produzca uno de sus números primos (de nuevo, menos las letras):

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

La primera y la última línea con las letras no forman parte del formato. Los he agregado aquí para mostrar la permutación. También se no requiere que las primeras o últimas líneas no contienen piernas |-|, ni que la salida sea lo más compacto posible.

Este ejemplo de entrada particular es una de las representaciones ASCII (infinitas) del diagrama de Amidakuji en la parte superior de la página de Wikipedia.

Hay una regla no obvia sobre estos diagramas ASCII: las patas adyacentes están prohibidas.

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

Wikipedia explica un procedimiento estándar para obtener un primo de un diagrama, llamado "bubblization", que consiste en aplicar las siguientes simplificaciones una y otra vez:

1) Horquilla derecha a izquierda:

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

2) Eliminación de dobles:

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

No estoy seguro de si esa explicación es inequívoca. Su código puede usar esa técnica o cualquier otro algoritmo que produzca los primos necesarios.

El código más corto gana.

Se aplican reglas estándar y derechos de emisión estándar. (Si la entrada no es válida, su programa puede incendiarse. Los formatos de entrada / salida pueden ser stdin / stdout, argumento de cadena, lista de líneas, matriz de caracteres, lo que sea mejor para usted, etc.)

ingrese la descripción de la imagen aquí


3
Este es un desafío muy interesante. Podría tomarme un tiempo para producir una solución no protegida, je.
JosiahRyanW

¿La salida debe ser lo más compacta posible o se permite una cantidad de espacio vertical siempre que el número de patas sea mínimo?
Laikoni

@Laikoni se permite cualquier cantidad de espacio vertical.
Tobia

¿Las burbujas y la burbuja inversa alcanzan el mismo resultado Amidakuji?
l4m2

@ l4m2, ¿qué es la bubblización inversa?
Tobia

Respuestas:


4

Python 2 , 322 240 bytes

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

Pruébalo en línea!

Una función que toma la cadena en la forma especificada e imprime el Amidakuji reducido también en esa forma.

La idea básica aquí es convertir primero la entrada en una permutación (en el for x in Xbucle); y luego en el whilebucle, realice una especie de burbuja de esa permutación, ya que como señala el artículo de wikipedia, esto resulta en un Amidakuji 'principal'.


Guau. Acabo de pasar mucho tiempo haciendo una versión de Python 3, pero son 526 bytes, je.
JosiahRyanW

¡Acabo de alimentar cientos de diagramas aleatorios a su código y puedo confirmar que genera primos correctos!
Tobia

3

Haskell , 288 bytes

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

Pruébalo en línea!

Explicación

-- 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

¡Buen trabajo! Introduje miles de diagramas aleatorios a su código y los resolvió todos.
Tobia

(_:[])puede ser justo [_]y p?q=(p:fst q,snd q)puede ser p?(f,s)=(p:f,s). En lugar de definir c 0='-';c _=' ';y luego usar c m, " -"!!(0^abs m)debería funcionar.
Laikoni

(g 0)no necesita corchetes y letun protector es más corto que where. Todos juntos 274 bytes: ¡ Pruébelo en línea!
Laikoni

Su función de punto de fijación %se puede alinear con until(\x->g 0 x==x)(g 0).
Laikoni

2

Retina 0.8.2 , 105 bytes

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

Pruébalo en línea! Explicación:

$
¶$%`

Duplicar la última línea.

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

Numera las columnas en la última línea.

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

Mueve los números hacia arriba hasta que lleguen a la primera línea. En cada iteración, solo -1=se mueve el número más a la derecha . Se mueve hacia la derecha a |menos que esté precedido por un -en cuyo caso se mueve a la anterior |. (El rindica que la expresión regular se procesa como si fuera una mirada hacia atrás, lo que hace que sea un poco más fácil hacer coincidir este caso). Esto calcula la permutación que el Amidakuji transforma en orden ordenado.

-
 
1G`

Mantenga solo la lista de números, eliminando los -sy cualquier cosa después de la primera línea.

;{`

Luego, el resto del programa se repite, ordena la lista nuevamente en orden, pero la lista final no se imprime, sin embargo, ya que se necesita una iteración para Retina 0.8.2 para notar que la lista está en orden, una línea sin patas es generado al final, lo que creo que es aceptable.

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

Marque todos los pares disponibles de números adyacentes sin clasificar con -s para las patas.

*`1+
|

Imprime las piernas pero con los números reemplazados por |s.

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

Realmente realiza los intercambios.


¿Tiene algún consejo sobre cómo ejecutar su código con Retina.exe ? Creo que tengo la fuente correcta (105 bytes) pero no genera nada. Probé el Hello World de los ejemplos de Retina y funciona. ¿Puede cargar la fuente en algún lugar, o Base64 codificarlo y ponerlo en un pastebin, en caso de que haya equivocado la codificación?
Tobia

@Tobia Lo siento, pero no recuerdo cómo usar Retina.exe; Creo que podría haberlo usado una o dos veces, pero en estos días solo uso Try It Online.
Neil

LOL soy tonto! Estaba usando una versión de vanguardia en lugar de 0.8.2. Ahora tengo mi arnés para alimentar cientos de diagramas aleatorios a su código y puedo confirmar que siempre genera los primos correctos. ¡Buen trabajo!
Tobia

@Tobia Gracias por probar! Ajustes necesarios para Retina 1: $**; -1=0; 1_; ;.(aproximadamente); **\.
Neil

1

Python 3 , 524 488 486 bytes

-38 bytes gracias a los 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="|")

Pruébalo en línea!

Esto convierte el Amidakuji en una matriz binaria 2D y lo reduce directamente usando las reglas.


Tengo curiosidad acerca de su enfoque; ¡Le daré un vistazo! Mientras tanto, puede guardar algunos bytes reemplazándolos " "+i.replace("|","")+" "con i.split("|")in. la primera línea de tu pfunción ...
Chas Brown

Unos cuantos ajustes de golf de python estándar más para llegar a 479 bytes .
Chas Brown


Yah, no estoy seguro de por qué está sucediendo ...
Chas Brown

No siempre ... a veces la derecha a la izquierda no es factible, pero la izquierda a la derecha sí. En ese caso específico, solo se trata de hacer lo contrario allí. ¿Quizás necesito hacer ambas cosas?
JosiahRyanW

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.