Simplificação de Amidakuji (阿 弥陀 籤)


10

Se você já teve alguma exposição à cultura japonesa ou do leste asiático, certamente encontrará o jogo Amidakuji:

insira a descrição da imagem aqui

Como a Wikipedia explica , é um tipo de loteria desenhada no papel e usada para selecionar aleatoriamente uma permutação de N itens.

Por exemplo, pode ser usado para atribuir aleatoriamente uma sequência inicial a N pessoas, ou N prêmios a N pessoas, e assim por diante.

O truque para entender por que o jogo representa uma permutação é perceber que todo golpe horizontal (chamado de "perna") troca seus dois itens no lugar.

A mesma página da Wikipedia também explica que cada item de permutação P de N corresponde a um número infinito de diagramas de Amidakuji. Aqueles com o menor número de traços horizontais (pernas) são chamados de "primos" dessa permutação específica P.

Sua tarefa é receber um diagrama Amidakuji com 2 ou mais linhas verticais (neste exemplo, são 6) neste formato (menos as letras):

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

E produza um de seus primos (novamente, menos as letras):

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

A primeira e a última linha com as letras não fazem parte do formato. Eu os adicionei aqui para mostrar a permutação. Também não é necessário que a primeira ou a última linha não contenha pernas |-|, nem que a saída seja o mais compacta possível.

Este exemplo de entrada específico é uma das representações (infinitas) ASCII do diagrama Amidakuji na parte superior da página da Wikipedia.

Há uma regra não óbvia sobre esses diagramas ASCII: pernas adjacentes são proibidas.

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

A Wikipedia explica um procedimento padrão para obter um primo de um diagrama, chamado "bubblization", que consiste em aplicar as seguintes simplificações repetidamente:

1) Forquilha direita para forquilha esquerda:

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

2) Eliminando duplas:

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

Não tenho certeza se essa explicação é inequívoca. Seu código pode usar essa técnica ou qualquer outro algoritmo que produza os números primos necessários.

O menor código vence.

Regras e subsídios padrão se aplicam. (Se a entrada não for válida, seu programa poderá pegar fogo. Os formatos de entrada / saída podem ser stdin / stdout, argumento de string, lista de linhas, matriz de caracteres, o que for melhor para você etc.)

insira a descrição da imagem aqui


3
Este é um desafio muito interessante. Eu posso demorar um pouco produzindo uma solução não destruída, heh.
JosiahRyanW

A saída precisa ser o mais compacta possível ou é permitido algum espaço vertical, desde que o número de pernas seja mínimo?
Laikoni

@Laikoni qualquer quantidade de espaço vertical é permitida.
Tobia 07/10

Bubblização e bubblização inversa atingem todos os mesmos resultados Amidakuji?
L4m2 22/10

@ l4m2 o que é bubblização inversa?
24518 Tobia

Respostas:


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

Experimente online!

Uma função que pega a string no formulário especificado e imprime também o Amidakuji reduzido nesse formulário.

A idéia básica aqui é primeiro converter a entrada em uma permutação (no for x in Xloop); e depois, no whileloop, execute uma espécie de bolha dessa permutação, pois, como observa o artigo da Wikipedia, isso resulta em um Amidakuji "principal".


Uau. Passei muito tempo criando uma versão Python 3, mas são 526 bytes, heh.
JoshRyanW

Acabei de alimentar centenas de diagramas aleatórios para o seu código e posso confirmar que ele gera números primos corretos!
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

Experimente online!

Explicação

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

Bom trabalho! Alimentei milhares de diagramas aleatórios no seu código e ele resolveu todos eles.
10248 Tobia

(_:[])pode ser justo [_]e p?q=(p:fst q,snd q)pode ser p?(f,s)=(p:f,s). Em vez de definir c 0='-';c _=' ';e depois usar c m, " -"!!(0^abs m)deve funcionar.
Laikoni

(g 0)não precisa de suportes e um letem uma guarda é menor que where. Todos juntos 274 bytes: Experimente online!
Laikoni

Sua função de ponto de fixação %pode ser incorporada com 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

Experimente online! Explicação:

$
¶$%`

Duplique a última linha.

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

Numere as colunas na última linha.

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

Mova os números para cima até chegarem à primeira linha. A cada iteração, apenas o número mais à direita -1=é movido. Ele é movido para a direita, a |menos que seja precedido por um e -, nesse caso, é movido para o anterior |. (Or Indica que o regex é processado como se fosse um lookback, o que facilita marginalmente a correspondência com este caso.) Isso calcula a permutação que o Amidakuji transforma em ordem classificada.

-
 
1G`

Mantenha apenas a lista de números, excluindo -ose qualquer coisa após a primeira linha.

;{`

O restante do programa é então repetido, classificando a lista novamente em ordem, mas a lista final não é impressa, no entanto, uma vez que é necessária uma iteração para o Retina 0.8.2, observe que a lista está em ordem, uma linha sem pernas é gerado no final, o que acredito ser aceitável.

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

Marque todos os pares disponíveis de números adjacentes não classificados com -s para as pernas.

*`1+
|

Imprima as pernas, mas com os números substituídos por |s.

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

Realize as trocas.


Você tem algum conselho sobre como executar seu código com o Retina.exe ? Eu acho que tenho a fonte correta (105 bytes), mas ele não produz nada. Eu tentei o Hello World nos exemplos da Retina e funciona. Você pode carregar a fonte em algum lugar ou a Base64 codificá-la e colocá-la em uma pastabin, caso eu tenha entendido errado a codificação?
Tobia

@Tobia Desculpe, mas não me lembro como usar o Retina.exe; Acho que posso tê-lo usado uma ou duas vezes, mas atualmente uso o Try It Online.
Neil

LOL eu sou burra! Eu estava usando uma versão de ponta em vez do 0.8.2. Agora, eu tenho o meu equipamento para alimentar centenas de diagramas aleatórios no seu código e posso confirmar que ele sempre gera os números corretos. Bom trabalho!
Tobia

@Tobia Obrigado por testar! Ajustes necessários para a Retina 1: $**; -1=0; 1_; ;.(aproximadamente); **\.
1018 Neil

1

Python 3 , 524 488 486 bytes

-38 bytes graças a 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="|")

Experimente online!

Isso converte o Amidakuji em um array binário 2D e o reduz diretamente usando as regras.


Estou curioso sobre a sua abordagem; Vou dar uma olhada! Enquanto isso, você pode salvar alguns bytes substituindo " "+i.replace("|","")+" "por i.split("|")in. a primeira linha de sua pfunção ...
Chas Brown

Mais alguns ajustes padrão no golfe em python para chegar a 479 bytes .
Chas Brown


Yah, não sei por que está acontecendo ...
Chas Brown

Nem sempre ... às vezes, da direita para a esquerda não é possível, mas da esquerda para a direita é. Nesse caso específico, é apenas uma questão de fazer o contrário lá. Talvez eu precise fazer as duas coisas?
precisa saber é o seguinte

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.