Enfiler un collier de perles

18

Aperçu

Pearls (ou Masyu) est un jeu de logique joué sur une grille. Il y a des perles noires et blanches placées sur la grille. L'objectif est de former une boucle fermée unique qui parcourt chaque perle en utilisant uniquement des segments de ligne droite et des angles droits.

Il existe certaines règles qui régissent la façon dont la boucle interagit avec les perles:

  • Les perles blanches doivent être traversées directement , mais la boucle doit tourner dans la cellule précédente et / ou suivante sur son chemin.
  • Les perles noires doivent être activées , mais la boucle doit traverser directement les cellules suivantes et précédentes sur son chemin.
  • La boucle ne doit pas se croiser ou se recouper d'une autre manière. Toutes les cellules ont exactement zéro ou deux entrées / sorties de boucle.

Un exemple de puzzle de Wikipedia (et sa solution):

entrez la description de l'image ici entrez la description de l'image ici

Votre objectif est de résoudre un puzzle donné. S'il existe plusieurs solutions possibles, peu importe celle que vous proposez.

Contribution

L'entrée sera une grille carrée non résolue . L'exemple ci-dessus ressemblerait à ceci:

..w.w.....
....w...b.
..b.b.w...
...w..w...
b....w...w
..w....w..
..b...w...
w...b....w
......ww..
..b......b

west une perle blanche, best une perle noire et .est une cellule vide.

Supposons que l'entrée est valide. Cela signifie qu'il est bien formé et qu'au moins une solution est possible. Tous les puzzles valides sont au moins 3x3 et contiennent au moins une perle.

Production

La sortie est une chaîne de coordonnées représentant le chemin. Le coin supérieur gauche de la grille est 0 0, en haut à droite est n-1 0, où n est la largeur de la grille.

Un chemin est simplement une série de coordonnées ordonnées:

x1 y1 x2 y2 x3 y3 ...

Le chemin est supposé fermé, vous n'avez donc pas besoin de répéter la première coordonnée à la fin, mais il n'y a aucune pénalité pour cela.

La sortie doit comprendre au moins tous les coins du chemin. Il n'est pas nécessaire de sortir chaque cellule du chemin s'il n'y a pas de tour. Par exemple, la sortie de l'exemple pourrait commencer par:

1 0 5 0 5 1 ...

ou

1 0 2 0 3 0 4 0 5 0 5 1 ...

La sortie ne doit contenir aucune cellule ne se trouvant pas dans le chemin. Vous pouvez commencer à n'importe quelle cellule du chemin.


Fragment

Voici un extrait que vous pouvez utiliser pour visualiser votre solution. Collez simplement la grille sur laquelle vous travaillez et le chemin que vous sortez. Je suis conscient que c'est pénible de regarder mon code, je vous suggère donc de ne pas le faire;)


Cas de test

Ces cas de test montrent une sortie possible pour chaque entrée (sauf la dernière, qui est montrée non résolue). Il peut y avoir d'autres chemins valides, vous pouvez aller CW ou CCW ou commencer à un point différent, etc. Les solutions devraient être capables de résoudre les cas de test en secondes / minutes / heures, pas jours / semaines / éons.

perle-3

...
w..
..b

0 0 1 0 2 0 2 1 2 2 1 2 0 2 0 1

perle-6

.wb..b
......
..b...
w.ww..
......
b....b

0 0 2 0 2 2 4 2 4 1 3 1 3 0 5 0 5 5 3 5 3 4 4 4 4 3 1 3 1 4 2 4 2 5 0 5 0 2 1 2 1 1 0 1

perle-12

.....w.b.w..
ww..b...b...
.w.....b....
...wbww..b.b
....b.......
w.w.........
..w......b.b
.....bb.....
.....b.....w
w.ww..b.....
...w......w.
b..w.....b..
Géobits
la source
Vous n'avez pas mis la solution pour le dernier cas de test ...
mbomb007
2
@ mbomb007 Correct.
Geobits
Il n'y a donc pas de solution?
mbomb007
2
Il y a une solution. Je l'ai laissé ouvert pour que les réponses aient quelque chose à montrer pour leurs efforts. En outre, cela peut aider à résoudre un ou deux casse-tête à la main pour avoir une idée des règles, et c'est difficile à faire si tous les exemples sont pré-résolus.
Geobits
Une grille 2x2 ou plus grande sans perles n'est-elle pas considérée comme valide (la deuxième phrase suggère que non, et le point sur l'entrée étant non résolu (s'il n'y a pas de perles non enfilées, elle doit être résolue))? Si oui, vous attendriez-vous à une boucle, juste sans perles, ou quoi exactement? Vraisemblablement, il n'y a aucune exigence de présence d'une couleur particulière?
VisualMelon

Réponses:

7

C, 590 640 760 880 963 1018

La force brute est assez rapide pour cela. Le test 12x12 s'exécute sous 10 ms. Sachant que cela pourrait opter pour une langue plus appropriée pour le golf.

Je ne suppose pas que le plateau est carré car les puzzles plus gros ont tendance à ne pas être carrés.

La Wdéfinition définit la limite des dimensions de la carte. La limite réelle est plus petite W - 2car j'utilise des lignes supplémentaires pour les bordures pour éviter les vérifications de limites.

#define W 40
int Y,X,T,P,Q[W*W],D[]={-W,-1,1,W};char B[W*W],K[W*W],I[W];
t(x,d,s){for(P=0;B[x];x*=x!=*Q)s-=K[Q[P++]=x]-1,
d=(54202126527627840ll>>2*(d*7+B[x+=D[d]]%8))&3;return x?0:s;}
m(x){int c=K[x],u=B[x-W],U=u&7,l=B[x-1],L=l&7,r=0,
i=U!=3&U!=4&L!=2&L!=4,o=(39>>U)&1?57:70;o&=(52>>L)&1?42:85;
if(x/W>Y+1){for(;P--;)printf("%d %d ",Q[P]%W-1,Q[P]/W-1);exit(0);}
if(u>7)o&=U>4?~64:~6;if(l>7)o&=L>4?~32:~10;
for(o&=c?c>1?c>2?(r=8*i,96):(r=8,i*30):~0:1;o;r++,o/=2)
if(o&1)if(B[x]=r,r%8!=1||!t(x,0,T))m(x+1);B[x]=0;}
main(){for(;gets(I);Y++)for(X=0;I[X];X++)
T+=(K[X+1+Y*W+W]=I[X]/36)-1;m(W);}

Testez- moi .

Voici un cas de test plus difficile:

.b.....b.b.......b..
.....w.....b.w....w.
....w.........w.....
..bb.....w.w.b....b.
.w.....b..b......w..
.....b..............
.b..........b.b..bw.
....w....w....b...w.
.......bb...b...w...
..b.......w.........
....b.w.....w.b...b.
w...b...w..b.w.w....
b.w....w............
...b.w......b..b...b
w......w.b.ww.......
.b....b..........b..
....b....w.bb.w...w.
w..b......w...b.....
b.....w.........w...
...b....w..w..b...w.
...................b
.b..w..bb.b..b..w...
........w......b....
b....w......b..b.b..
...b..bb.w.w........
...b.......w......w.
w...w.b.w.....b....b
............w..ww...
..b.b..b....b.......
....b.........w...b.
.ww.......b.w.w.....
b.....w..w.w...b....
....ww..b.b.w....w.w
.............bb..w..
.b....w.b.b........w
....bw..........b...

J'ai eu de la chance que mon code trouve la solution assez tôt dans la course (<5min), mais la recherche complète prend beaucoup plus de temps (67min).

20x36

nutki
la source
s / La force brute est assez rapide / C est assez rapide /
kirbyfan64sos
9

Python - 1669

Toujours assez long, mais assez rapide pour exécuter le dernier exemple en moins d'une seconde sur mon ordinateur. Il est probablement possible de raccourcir au prix de la vitesse, mais pour l'instant, il est à peu près équivalent au code non golfé.

Exemple de sortie pour le dernier scénario de test:

0 11 1 11 2 11 3 11 4 11 4 10 3 10 2 10 1 10 1 9 2 9 3 9 4 9 4 8 3 8 3 7 4 7 5 7 5 6 5 5 6 5 6 6 6 7 7 7 8 7 8 8 7 8 6 8 5 8 5 9 5 10 5 11 6 11 6 10 6 9 7 9 8 9 8 10 7 10 7 11 8 11 9 11 9 10 9 9 10 9 10 10 10 11 11 11 11 10 11 9 11 8 11 7 10 7 10 8 9 8 9 7 9 6 10 6 11 6 11 5 11 4 11 3 10 3 9 3 9 4 9 5 8 5 8 4 8 3 8 2 8 1 9 1 10 1 10 0 9 0 8 0 7 0 7 1 7 2 6 2 5 2 5 1 6 1 6 0 5 0 4 0 3 0 2 0 2 1 3 1 4 1 4 2 4 3 5 3 6 3 7 3 7 4 6 4 5 4 4 4 4 5 4 6 3 6 3 5 3 4 3 3 3 2 2 2 2 3 1 3 1 2 1 1 1 0 0 0 0 1 0 2 0 3 0 4 0 5 0 6 1 6 1 5 1 4 2 4 2 5 2 6 2 7 1 7 1 8 0 8 0 9 0 10

entrez la description de l'image ici

Code:

I=raw_input().split('\n');X=len(I[0]);Y=len(I);R=range
def S(g=0,c=0,x=0,y=0):
    if y>=Y:return 0
    if g==0:g=[[-1]*X for i in R(Y)];c=[[-1]*X for i in R(Y)]
    o={'.':set(R(7)),'w':{1,2},'b':{3,4,5,6}}[I[y][x]].copy()
    o&={0,1,3,4}if y<1 or g[y-1][x]in[0,1,5,6]else{2,5,6}
    o&={0,2,4,5}if x<1 or g[y][x-1]in[0,2,3,6]else{1,3,6}
    if y>Y-2:o&={0,1,5,6}
    if x>X-2:o&={0,2,3,6}
    if y>0 and g[y-1][x]in[2,3,4]:
        if'b'==I[y][x]and g[y-1][x]!=2:return 0
        if'b'==I[y-1][x]:o&={2}
        elif'w'==I[y-1][x]and g[y-2][x]==2:o&={5,6}
    if x>0 and g[y][x-1]in[1,4,5]:
        if'b'==I[y][x]and g[y][x-1]!=1:return 0
        if'b'==I[y][x-1]:o&={1}
        elif'w'==I[y][x-1]and g[y][x-2]==1:o&={3,6}
    h=[r[:]for r in c]
    if y>0 and g[y-1][x]in[2,3,4]:
        if x>0 and g[y][x-1]in[1,4,5]:
            if c[y-1][x]==c[y][x-1]:
                if(6 not in o)+any(any(i!=c[y-1][x]and i!=-1 for i in r)for r in c)+any(I[v][u]!='.'and(v>y)+(u>x)for v in R(y,Y)for u in R(X)):return 0
                g[y][x]=6
                for v in R(y,Y):
                    for u in R(X):
                        if v!=y or u>x:g[v][u]=0
                for y in R(Y):
                    for x in R(X):
                        if g[y][x]>0:break
                f=[];d=-1;u,v=p,q=x,y
                while(u,v)!=(p,q)or-1==d:f+=[u,v];d=([0,{0,2},{1,3},{2,3},{0,3},{0,1},{1,2}][g[v][u]]-{(d+2)%4}).pop();i,j={0:(u+1,v),1:(u,v-1),2:(u-1,v),3:(u,v+1)}[d];u,v=i,j
                return f
            else:
                for v in R(y+1):
                    for u in R(X):
                        if h[v][u]==c[y][x-1]:h[v][u]=c[y-1][x]
                h[y][x]=c[y-1][x]
        else:h[y][x]=c[y-1][x]
    elif x>0 and g[y][x-1]in[1,4,5]:h[y][x]=c[y][x-1]
    else:h[y][x]=max(max(r)for r in c)+1
    for n in sorted(list(o))[::-1]:
        if n==0:h[y][x]=-1
        if x>X-2:i,j=0,y+1
        else:i,j=x+1,y
        g[y][x]=n;r=S(g,h,i,j)
        if r!=0:return r
    return 0
for i in S():print i,

Non golfé:

class Grid:
    def __init__(self,input):
        self.input = input.split('\n')
        self.x = len(self.input[0])
        self.y = len(self.input)
        self.options = {'.':{0,1,2,3,4,5,6},'w':{1,2},'b':{3,4,5,6}}

    def convert(self,grid):
        directions = [None,{0,2},{1,3},{2,3},{0,3},{0,1},{1,2}]

        for y in range(self.y):
            for x in range(self.x):
                if grid[y][x] != 0:
                    break

        chain = []
        start_pos = (x,y)
        dir = -1
        pos = start_pos
        while dir == -1 or pos != start_pos:
            chain.extend(pos)
            x,y = pos
            next_dir = (directions[grid[y][x]]-{(dir+2)%4}).pop()
            if next_dir == 0: nx,ny = x+1,y
            elif next_dir == 1: nx,ny = x,y-1
            elif next_dir == 2: nx,ny = x-1,y
            elif next_dir == 3: nx,ny = x,y+1
            dir = next_dir
            pos = (nx,ny)

        return chain

    def solve(self,grid=None,chain_ids=None,pos=(0,0)):
        x,y = pos
        if y >= self.y:
            return None

        if grid is None:
            grid = [[-1]*self.x for i in range(self.y)]
        if chain_ids is None:
            chain_ids = [[-1]*self.x for i in range(self.y)]

        options = self.options[self.input[y][x]].copy()
        if y == 0 or grid[y-1][x] in [0,1,5,6]:
            options &= {0,1,3,4}
        else:
            options &= {2,5,6}
        if y == self.y-1:
            options &= {0,1,5,6}

        if x == 0 or grid[y][x-1] in [0,2,3,6]:
            options &= {0,2,4,5}
        else:
            options &= {1,3,6}
        if x == self.x-1:
            options &= {0,2,3,6}

        if y != 0 and grid[y-1][x] in [2,3,4]:
            if self.input[y][x] == 'b' and grid[y-1][x] != 2:
                return None
            if self.input[y-1][x] == 'b':
                options &= {2}
            elif self.input[y-1][x] == 'w':
                if grid[y-2][x] == 2:
                    options &= {5,6}
        if x != 0 and grid[y][x-1] in [1,4,5]:
            if self.input[y][x] == 'b' and grid[y][x-1] != 1:
                return None
            if self.input[y][x-1] == 'b':
                options &= {1}
            elif self.input[y][x-1] == 'w':
                if grid[y][x-2] == 1:
                    options &= {3,6}


        new_chain_ids = [[i for i in row] for row in chain_ids]
        if y != 0 and grid[y-1][x] in [2,3,4]:
            if x != 0 and grid[y][x-1] in [1,4,5]:

                if chain_ids[y-1][x] == chain_ids[y][x-1]:
                    if 6 not in options:
                        return None

                    if any(any(i != chain_ids[y-1][x] and i != -1 for i in row) for row in chain_ids) or \
                    any(self.input[v][u] != '.' and (v!=y or u>x) for v in range(y,self.y) for u in range(self.x)):
                        return None

                    grid[y][x] = 6
                    for v in range(y,self.y):
                        for u in range(self.x):
                            if v != y or u > x: 
                                grid[v][u] = 0

                    return self.convert(grid)

                else:
                    for v in range(y+1):
                        for u in range(self.x):
                            if new_chain_ids[v][u] == chain_ids[y][x-1]:
                                new_chain_ids[v][u] = chain_ids[y-1][x]
                    new_chain_ids[y][x] = chain_ids[y-1][x]

            else:
                new_chain_ids[y][x] = chain_ids[y-1][x]
        elif x != 0 and grid[y][x-1] in [1,4,5]:
            new_chain_ids[y][x] = chain_ids[y][x-1]
        else:
            new_chain_ids[y][x] = max(max(row) for row in chain_ids)+1

        for n in sorted(list(options),key=lambda n: -n):
            grid[y][x] = n
            if n == 0:
                new_chain_ids[y][x] = -1

            if x == self.x-1:
                nx,ny = 0,y+1
            else:
                nx,ny = x+1,y

            result = self.solve(grid,new_chain_ids,(nx,ny))
            if result is not None:
                return result

input = """

.....w.b.w..
ww..b...b...
.w.....b....
...wbww..b.b
....b.......
w.w.........
..w......b.b
.....bb.....
.....b.....w
w.ww..b.....
...w......w.
b..w.....b..

""".strip()

def print_grid(grid):
    for y,row in enumerate(grid):
        s = ""
        for i in row:
            s += {-1:'xxx',0:'   ',1:'   ',2:' | ',3:'   ',4:'   ',5:' | ',6:' | '}[i]
        s += '\n'
        for x,i in enumerate(row):
            s += {-1:'x%sx',0:' %s ',1:'-%s-',2:' %s ',3:'-%s ',4:' %s-',5:' %s-',6:'-%s '}[i] % input.split('\n')[y][x]
        s += '\n'
        for i in row:
            s += {-1:'xxx',0:'   ',1:'   ',2:' | ',3:' | ',4:' | ',5:'   ',6:'   '}[i]
        s += '\n'
        print s

result = Grid(input).solve()
print result
KSab
la source
@Geobits Oh, il semble que je n'ai pas lu les règles assez attentivement. Réponse mise à jour avec ce que je crois être correct maintenant
KSab
Le nouveau chemin me semble bien! +1
Geobits
1

Lua, 830 810 765 752 739 729 710

Fonctionne très bien sur board1 et board2, mais prend du temps à bord3.

Il pourrait économiser 9 octets en générant chaque chemin au lieu du seul premier ...

b={}s={0,0,0}R=table.insert Z=unpack for l in io.lines()do w=#l for i=1,w do
c=({b=1,w=2,['.']=3})[l:sub(i,i)]R(b,c)s[c]=s[c]+1 end end h=#b/w for e=0,w*h-1
do function g(p,d,X,t)local function G(I,r)T={Z(t)}a=b[I+1]T[a]=T[a]+1
P={Z(p)}D={Z(d)}R(P,I%w)R(P,I/w-I/w%1)R(D,r)l=#D for U=2,#p,2 do if
I==p[U-1]+w*p[U]then return end end if I==e then if T[1]==s[1]and T[2]==s[2]then
for k=1,l do K=D[k]M=D[(k-2)%l+1]N=D[k%l+1]O=D[(k+1)%l+1]if({K==N or K~=M or
N~=O,K~=N or(K==M and N==O)})[b[1+P[2*k-1]+w*P[2*k]]]then return end end
os.exit(print(table.concat(P,' ')))end else g(P,D,I,T)end end _=X%w<w-1 and
G(X+1,1)_=X/w-X/w%1<h-1 and G(X+w,2)_=X%w>0 and G(X-1,3)_=X/w-X/w%1>0 and
G(X-w,4)end g({},{},e,{0,0,0})end
l'umbumbine
la source