Formas lógicas de pontos

12

O jogo

Recentemente, muito do meu tempo foi ocupado por um jogo viciante no meu telefone, chamado Logic Dots, que me inspirou a escrever esse desafio. É mais fácil explicar as regras se eu mostrar a tela do jogo, então aqui está uma captura de tela de um quebra-cabeça não resolvido e resolvido:

Agora aqui, há três coisas principais a serem observadas.

  1. O tabuleiro de jogo (a grade 4x4 de quadrados no centro)
  2. As formas necessárias (os pontos vinculados na segunda barra da parte superior, sob a partitura e o menu etc.), que são todas as linhas ou apor 1 retângulo
  3. Os números nas linhas e colunas, que indicam quantos pontos precisam estar na coluna, para uma solução

O objetivo do jogo é ajustar as formas necessárias na grade. Você pode girar as formas, mas elas não podem entrar na diagonal.

Na solução, observe que todas as formas são criadas exatamente uma vez (porque estão apenas nas formas necessárias uma vez) e, nesse caso, são todas horizontais, mas também podem ser verticais. Os quadrados preenchidos em rosa indicam os quadrados não utilizados.

Aqui está uma grade maior e um pouco mais complicada:

Observe que no quebra-cabeça não resolvido, já existem alguns quadrados preenchidos. Os quadrados acinzentados significam quadrados bloqueados nos quais você NÃO PODE colocar um ponto. Os pontos com rabos informam que um ponto está naquele ponto e se vincula a pelo menos mais um ponto na direção da cauda, ​​mas não em nenhuma outra direção (incluindo a direção oposta).

Notação

No restante deste post, vou me referir ao quadro usando os seguintes símbolos:

  • <,>, ^, v - Significa um ponto pré-colocado com uma cauda estendida na direção do ponto
  • * - significa um ponto. Se fornecido em uma grade não resolvida (entrada), é uma forma individual. Se estiver na saída, ele será conectado aos pontos ao seu redor.
  • # - Significa um quadrado da grade bloqueado (onde você não pode colocar um ponto)
  • -, | (hífen e barra) - significa um ponto com a cauda direita e esquerda e um ponto com a cauda para cima e para baixo, respectivamente
  • ** (caractere de espaço) - ** Significa um espaço vazio

Usando esses símbolos, o último caso de exemplo (não resolvido) pode ser representado da seguinte maneira:

 <    



    # 
 ^ #

E a solução pode ser representada como:

*< * *
   *  
     *
 *   *
 * *#*
 ^ # *

Observe que duas formas não podem tocar na horizontal, na vertical ou na diagonal , portanto, o seguinte caso não é válido:

 *** 
**   
  ** 

Desafio

Seu desafio é resolver qualquer quebra-cabeça de pontos lógicos, de 4x4 a 9x9, inclusive. Você receberá quatro linhas de entrada, depois o tabuleiro do jogo. As linhas serão as seguintes:

  • 1ª linha, Formas - As formas a serem encontradas, cada uma dada na forma sizexquantity(por exemplo, 3x2para duas formas de comprimento três) e separadas por um espaço. Linha de exemplo:3x1 2x1 1x1
  • 2ª linha, Colunas - Uma lista separada por espaços da contagem de pontos necessária para cada coluna. Linha de exemplo:1 1 2 2
  • 3ª linha, Linhas - Uma lista separada por espaços da contagem de pontos necessária para cada linha. Linha de exemplo:3 0 3 0
  • 4ª linha, tamanho da placa - um único número inteiro, o tamanho da placa, B

O quadro é fornecido e são Blinhas de entrada que representam o quadro usando a notação mencionada acima. Por exemplo, a entrada completa para o último caso de exemplo é a seguinte:

4x1 3x1 2x2 1x2
1 4 0 3 0 5
4 1 1 2 3 2
6
 <    



    # 
 ^ #  

Seu programa produzirá a placa resolvida, na mesma notação. A saída correspondente para a entrada acima é a seguinte:

** * *
   *  
     *
 *   *
 * *#*
 * # *

Observe que um tabuleiro de jogo pode ter várias soluções. Nesse caso, basta gerar uma solução válida. Além disso, seu programa deve produzir uma solução correta em 10 segundos em um computador de mesa razoável para uma grade 10x10 complicada.

Isso é código de golfe, então o mínimo de bytes vence.


Casos de teste

Entrada 1

3x2 1x4
2 2 3 1 2
4 0 3 0 3
5


    #
  #  
    *

Saída 1

*** *

 ***#
  #  
* * *

Entrada 2

3x1 1x6
2 0 4 0 3
3 1 2 1 2
5
*    


   # 

Saída 2

* * *
  *  
  * *
*  # 
  * *

Entrada 3

5x1 4x1 2x1 1x2
1 2 3 3 2 2
0 5 0 4 0 4
6
#     
  -   


 #    
   <  

Saída 3

#     
 *****

 **** 
 #    
* ** *
globby
fonte
Sim, isso é correto @flawr
globby
@flawr t no two shapes can touch horizontally, vertically or diagonally(isto deve estar no início, não perdeu quase perto do final, mas de qualquer maneira ...)
edc65
@globby Todos os espaços vazios não seriam substituídos por #, suponho que # seja quando você tocar em um espaço vazio no jogo. Quando você termina um nível, ele preenche todas as células vazias.
Teun Pronk
@TeunPronk No. # são espaços pré-determinados que você não pode colocar um ponto no nível, como os quadrados cinza no segundo exemplo.
globby 02/02
2
Melhor do que oferecer uma recompensa, você deve adicionar casos de teste mais interessantes e corrigir os erros em sua pergunta. Por exemplo, a última saída antes de os casos de teste atuais ainda contém <e ^
edc65

Respostas:

3

Python 2: 766 739 696 663 633 bytes

def f(B,S,o=0):
 if[]==S:print'\n'.join(B);exit()
 s=S[0]
 for i in r:
  for j in R(Z-s+1):
   if(B[i][j]in' '+'>v'[o])*(B[i][j+s-1]in' '+'<^'[o])*({' ','-|'[o]}>=set(B[i][j+1:j+s-1]))*all(B[x][y]in'# 'for x,y in [(x,y)for y in R(j-1,j+s+1)for x in i-1,i+1]+[(i,j-1),(i,j+s)]if 0<=x<Z>y>=0):q=B[:];q[i]=q[i][:j]+'*'*s+q[i][j+s:];q=(q,t(q))[o];any((t(q)+q)[k].count('*')>m[k]for k in R(Z+Z))or f(q,S[1:])
 o or f(t(B),S,1)
y=raw_input;S=[];s=str.split
for i in s(y()):u,v=map(int,s(i,'x'));S+=[u]*v
m=map(int,s(y())+s(y()));Z=input();R=range;r=R(Z);B=[y()for _ in r];J=''.join;t=lambda x:map(J,zip(*x))
f(B,S[:len(S)-J(B).count('*')])

Veja-o trabalhando on-line: Ideone.com (a versão on-line pode ser muito lenta para redes grandes e difíceis, off-line deve ficar bem)

A entrada é via stdin, basta copiar e colar as linhas do OP (mas tenha cuidado, a troca de pilhas às vezes exclui espaços ou linhas).

Algumas idéias básicas desse código: Ele usa uma função recursiva f. ftenta colocar uma forma no quadro. Para cada local possível, ele se autodenomina com a placa modificada. Existem 3 loops nele. odetermina a orientação (2 - horizontal, 3 - vertical). Será sempre lugar na horizontal forma, portanto, no final de o=2, ele irá transpor a placa com a função t. ié a linha e jtodas são possíveis colunas iniciais. Em seguida, ocorrem muitas verificações, se as extremidades da forma tiverem caracteres válidos, se o meio da forma tiver caracteres válidos e se o ambiente estiver vazio.

Jakube
fonte
Eu estava lutando para cortar os últimos 6 bytes, quando vi sua última edição (-30) e deu-se ... Você tem o meu voto para que vale a pena
edc65
3

JavaScript (ES6) 661 667 695 702 745 755 786 790 784 798

O trabalho em andamento pode ser reduzido. Provavelmente muito lento em uma grade complexa. Talvez não.

Editar Um pouco mais, muito mais rápido.
Editar 2 Correção de bug, verificação de colunas / linhas. Aliás, agora é mais rápido

A função M é a principal. O parâmetro w é uma cadeia de linhas múltiplas com toda a entrada. A função analisa a entrada e prepara um quadro de partida. Os caracteres <>^v|-*no quadro de partida são substituídos por ,, cada um ,deve ser substituído *na solução correta.

A função R tenta recursivamente colocar todas as formas no quadro. Quando uma forma é colocada, ela se chama passando por uma lista mais curta de formas e o quadro modificado. Quando todas as formas são colocadas, uma solução ainda pode ser inválida se não for ,substituída por *.

A função P testa se uma forma pode ser colocada em uma determinada posição e orientação. Ele verifica todas as costrains (dentro do quadro, sem sobreposição, sem toque, contagem válida de linhas e colunas)

M=w=>(
  [x,c,r,z]=w=w[S='split'](n='\n'),
  (b=[...w.slice(4).join(n)])
  .map((c,p)=>~(k='*<>-*^v|'.indexOf(c))&&[(q=k>3?z:1,0),k&1&&-q,k&2&&q].map(o=>b[p+o]=0),
    c=c[S](e=' '),r=r[S](e),w=z++,f='*',s='',x[S](e).map(v=>s+=v[0].repeat(v[2]))),
  R=(s,b,x=0,y=0,n=s[0],V=i=>b[i]>'#',
    P=(p,o,q,t,g,l,d=[...b])=>{
        if(l<z-n&!V(p+o*l-o)&!V(p+o*l+o*n))
        {
          for(i=-1;v=d[p],++i<w;p+=o,t-=v==f)
            if(i>=l&i-n<l)
              for(v!=e&v!=0|[q,w,~z].some(w=>V(p+w)|V(p-w))?t=0:d[p]=f,j=o*i,u=k=0;
                  ++k<z;(u+=d[j]==f)>g[i]?t=0:j+=q);
          return t>=n&&d.join('')
        }
    })=>{
    if(b){
      if(!n)return~b.search(0)?0:b;
      for(s=s.slice(1);y<w||(y=0,++x<w);++y)
        if(h=R(s,P(y*z,1,z,r[y],c,x))||n>1&&R(s,P(x,z,1,c[x],r,y)))return h
    }
  })(s,b)

Teste no console do FireFox / FireBug

;['3x2 1x4\n2 2 3 1 2\n4 0 3 0 3\n5\n     \n     \n    #\n  #  \n    *\n'
,'3x1 1x6\n2 0 4 0 3\n3 1 2 1 2\n5\n*    \n     \n     \n   # \n     \n'
,'5x1 4x1 2x1 1x2\n1 2 3 3 2 2\n0 5 0 4 0 4\n6\n#     \n  -   \n      \n      \n #    \n   <  \n'
,'4x1 3x1 2x2 1x2\n1 4 0 3 0 5\n4 1 1 2 3 2\n6\n <    \n      \n      \n      \n    # \n ^ #  \n']
.forEach(x=>console.log(x,M(x).replace(/ /g,'`'))) // space replaced with ` for clarity

Saída (tempo total de execução <1s)

3x2 1x4
2 2 3 1 2
4 0 3 0 3
5


    #
  #  
    *

***`*
`````
`***#
``#``
*`*`*

3x1 1x6
2 0 4 0 3
3 1 2 1 2
5
*    


   # 


*`*`*
``*``
``*`*
*``#`
``*`*

5x1 4x1 2x1 1x2
1 2 3 3 2 2
0 5 0 4 0 4
6
#     
  -   


 #    
   <  

#`````
`*****
``````
`****`
`#````
*`**`*

4x1 3x1 2x2 1x2
1 4 0 3 0 5
4 1 1 2 3 2
6
 <    



    # 
 ^ #  

**`*`*
```*``
`````*
`*```*
`*`*#*
`*`#`*
edc65
fonte
Parece que o @globby esqueceu essa recompensa. Enfim, nos divertimos muito nesta corrida.
Jakube