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.