Vamos jogar Peg Solitaire

8

Peg solitaire é um jogo popular geralmente jogado sozinho. O jogo consiste em algum número de pinos e um tabuleiro dividido em uma grade - geralmente o tabuleiro não é retangular, mas para esse desafio, assumiremos isso.

Cada jogada válida permite remover um único pino e o objetivo é jogar de uma maneira, de modo que exista um único pino. Agora, um movimento válido deve estar em uma única direção (norte, leste, sul ou leste) e pular sobre uma estaca que pode ser removida.

Exemplos

Sejam .espaços vazios no quadro e os números são pinos, o movimento a seguir se moverá 1um para a direita e será removido 2do quadro:

.....     .....
.12..  -> ...1.
.....     .....

Uma jogada sempre terá que pular um único pino, portanto o seguinte não é válido:

......    ......
.123.. -> ....1.
......    ......

Aqui estão algumas configurações válidas após um movimento cada:

...1...        ...1...        ..71...        ..71...
.2.34.5  --->  .24...5  --->  .2....5  --->  ......5
.678...  (4W)  .678...  (7N)  .6.8...  (2S)  ...8...
.......        .......        .......        .2.....

Desafio

Dada uma configuração inicial da placa e alguma outra configuração, verifique se a outra configuração pode ser alcançada movendo os pinos sucessivamente, como descrito acima.

Regras

  • A entrada será uma matriz n×m / lista de listas / ... de valores indicando um espaço vazio (por exemplo, zero ou falso) ou pegs (por exemplo, diferente de zero ou verdadeiro)
    • você pode assumir que n3 e m3
    • você pode usar true / diferente de zero para indicar espaços vazios e vice-versa, se isso ajudar
  • Saída será duas distinta (um dos valores pode ser diferente) valores que indicam se a configuração final pode ser atingido (por exemplo. Falsas / truthy , []/ [list of moves]..)

Casos de teste

initial  goal -> output
[[1,0,0],[1,1,0],[0,1,0]]  [[0,0,0],[0,1,0],[1,1,0]] -> True
[[1,0,0],[1,1,0],[0,1,0]]  [[0,0,1],[0,1,1],[0,0,0]] -> False
[[0,0,0],[1,0,0],[0,0,0]]  [[0,0,0],[0,0,1],[0,0,0]] -> False
[[0,0,0],[1,1,0],[0,0,0]]  [[0,0,0],[0,1,1],[0,0,0]] -> False
[[0,0,0,0],[1,1,1,0],[0,0,0,0]]  [[0,0,0,0],[0,0,0,1],[0,0,0,0]] -> False
[[1,0,0],[1,1,0],[1,1,1],[1,1,1]]  [[0,0,1],[0,1,0],[1,0,0],[0,0,1]] -> True
[[1,0,0],[1,1,0],[1,1,1],[1,1,1]]  [[1,0,0],[0,0,0],[0,0,0],[0,0,0]] -> False
[[1,0,1,1],[1,1,0,0],[1,1,1,0],[1,0,1,0]]  [[0,0,1,0],[1,0,0,0],[1,0,1,0],[1,0,0,1]] -> True
[[1,0,1,1],[1,1,0,0],[1,1,1,0],[1,0,1,0]]  [[0,0,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,0]] -> False
[[1,0,0,0],[1,1,0,0],[1,1,1,0],[1,0,1,0]]  [[0,0,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,0]] -> True
[[0,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,0]]  [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]] -> False
[[0,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,0]]  [[1,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]] -> False
[[0,0,0,1,0,0,0],[0,1,0,1,1,0,1],[0,1,1,1,0,0,0],[0,0,0,0,0,0,0]]  [[0,0,0,1,0,0,0],[0,1,0,1,1,0,1],[0,1,1,1,0,0,0],[0,0,0,0,0,0,0]] -> True
[[0,0,0,1,0,0,0],[0,1,0,1,1,0,1],[0,1,1,1,0,0,0],[0,0,0,0,0,0,0]]  [[0,0,0,1,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]] -> True
[[0,0,1,1,1,0,0],[0,0,1,1,1,0,0],[1,1,1,1,1,1,1],[1,1,1,0,1,1,1],[1,1,1,1,1,1,1],[0,0,1,1,1,0,0],[0,0,1,1,1,0,0]]  [[0,0,1,1,1,0,0],[0,0,1,1,1,0,0],[1,1,1,1,1,1,1],[1,1,1,1,0,0,1],[1,1,1,1,1,1,1],[0,0,1,1,1,0,0],[0,0,1,1,1,0,0]] -> True
[[0,0,1,1,1,0,0],[0,0,1,1,1,0,0],[1,1,1,1,1,1,1],[1,1,1,0,1,1,1],[1,1,1,1,1,1,1],[0,0,1,1,1,0,0],[0,0,1,1,1,0,0]]  [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,1,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]] -> True
ბიმო
fonte
1
O que aconteceu com o peg 7no seu exemplo? Por que desaparece depois de 2se mudar para o sul?
Οurous 29/11
@ Ourous: Isso foi apenas um erro de digitação, corrigido.
ბიმო

Respostas:

2

JavaScript (ES6),  184 178  173 bytes

(initial_board)(target_board)0 01

a=>g=b=>a+''==b|a.some((r,y)=>r.some((v,x,A,X,R)=>[-1,0,1,2].some(h=>(A=a[y+(R=~-h%2)]||0)[X=x+(h%=2)]&v>(R=a[y+R*2]||0)[h+=x+h]&&g(b,A[X]=r[x]=R[h]++)&(A[X]=r[x]=R[h]--))))

Experimente online!

(removeu os dois últimos casos de teste que levam muito tempo para o TIO)

Comentado

a =>                             // main function taking the initial board a[]
  g = b =>                       // g = recursive function taking the target board b[]
    a + '' == b |                // yield a truthy result if a[] is matching b[]
    a.some((r, y) =>             // for each row r[] at position y in a[]:
      r.some((v, x, A, X, R) =>  //   for each value v at position x in r[]:
        [-1, 0, 1, 2]            //     list of directions (West, North, East, South)
        .some(h =>               //     for each direction h:
          ( A =                  //       A = a[y + dy]
            a[y + (R = ~-h % 2)] //       R = dy
            || 0                 //       use a dummy row if we're out of the board
          )[X = x + (h %= 2)]    //       h = dx, X = x + dx
          &                      //       yield 1 if there's a peg on the skipped cell
          ( R =                  //       R = target row
            a[y + R * 2]         //         = a[y + 2 * dy]
            || 0                 //       use a dummy row if we're out of the board
          )[h += x + h]          //       h = x + 2 * dx = target column
          < v                    //       yield 1 if there's no peg on the target cell
          &&                     //       and there's a peg on the source cell (0 < 1)
          g(                     //       if the above result is true, do a recursive call:
            b,                   //         pass b[] unchanged
            A[X] = r[x] =        //         clear the source and skipped cells
            R[h]++               //         set the target cell
          ) & (                  //       and then restore the board to its initial state:
            A[X] = r[x] =        //         set the source and skipped cells
            R[h]--               //         clear the target cell
          )                      //
        )                        //     end of some() over directions
      )                          //   end of some() over columns
    )                            // end of some() over rows
Arnauld
fonte
1

Limpo , 232 bytes

import StdEnv,Data.List
r=reverse
@[a:t=:[b,c:u]]=[[a:v]\\v<- @t]++take(a*b-c)[[0,0,1:u]];@l=[]

flip elem o\c=limit(iterate(nub o concatMap\l=[l]++[f(updateAt i p(f l))\\f<-[id,transpose],q<-f l&i<-[0..],p<- @q++(map r o@o r)q])[c])

Experimente online!

Essa é uma das raras ocasiões em que posso utilizar composição e curry enquanto poupando bytes.

Explicado:

@ :: [Int] -> [[Int]]é uma função auxiliar usada para gerar as diferentes novas linhas / colunas em potencial que podem resultar de uma movimentação. Isso evita a necessidade de um caso especial [1,1,0:_], notando que a*b-c>0somente quando [a,b,c]=[1,1,0]e, portanto, take(a*b-c)...fornece []capturas -1ou 0elementos para todas as configurações que não são válidas.

flip elem o...reverte a ordem dos argumentos para elem(fazer com que "x contenha um y" em vez de "é xa membro de y") e aplica a função anônima cao primeiro argumento.

\c=limit(iterate(nub o concatMap ...)[c])gera todos os painéis potenciais que podem resultar disso c, juntando o conjunto atual de painéis com todos os movimentos que podem ocorrer em todos os painéis e removendo as duplicatas, até que o resultado pare de mudar.

\l=[l]++...anexa o quadro là lista de todas as possíveis novas placas a uma distância de distância, geradas aplicando @às linhas de cada orientação do quadro (rotações de 0, 90, 180, 270 graus) e substituindo a linha alterada correspondente pelo novo linha.

Furioso
fonte