Criar um quebra-cabeça não-programa

24

Um nonograma é um quebra-cabeça lógico bidimensional que se parece com isso (capturas de tela do jogo Pixelo , meu jogo favorito do nonograma):

Um quadro vazio de nonograma

O objetivo do jogo é descobrir qual imagem esses números estão codificando. As regras são simples: um número em uma coluna ou linha significa que em algum lugar dessa coluna ou linha, muitas caixas são preenchidas em uma linha. Por exemplo, a linha inferior na imagem acima não deve ter caixas preenchidas, enquanto a linha acima deve ter todas as caixas preenchidas. A terceira linha da parte inferior tem 8 caixas preenchidas e todas elas serão seguidas.

Dois ou mais números para a mesma coluna ou linha significam que existem várias "execuções" de caixas preenchidas, com pelo menos um espaço entre esses comprimentos. O pedido é preservado. Por exemplo, há três caixas preenchidas na coluna direita da imagem acima, pelo menos um espaço abaixo delas e mais uma caixa preenchida.

Aqui está o mesmo quebra-cabeça, quase completo:

Um quadro não programado quase pronto

(Os Xs não são importantes, são apenas uma dica que o jogador deixa para dizerem "Este quadrado definitivamente não está preenchido". Pense em bandeiras no Campo Minado. Eles não têm significado para as regras.)

Felizmente, você pode ver que, por exemplo, as colunas do meio com dicas que dizem "2 2" têm duas execuções de 2 comprimentos de caixas preenchidas.

Sua missão, caso você aceite, é escrever um programa ou função que criará um quebra-cabeça como esse. Você recebe o tamanho do quadro como um único número inteiro (5 <= n <= 50) no stdin ou como argumento (não há razão para que um quebra-cabeça que não seja do programa deve ser quadrado, mas, para esse desafio, será). Depois disso, você receberá uma série de 1s e 0s representando quadrados preenchidos e não preenchidos na imagem, respectivamente. O primeiro n deles é a linha superior, depois a próxima linha, etc. Você retornará ou imprimirá um stdout de uma placa de 2 * 1 células (porque elas ficam melhores e oferecem espaço para dicas de dois dígitos para uma coluna ), todos vazios, com dicas correspondentes aos dados de entrada.

Formato de saída

Formato de saída

Amostra

Entrada:

./nonogram <<< '5 0 1 1 1 0 1 1 0 1 1 1 0 1 0 1 1 1 0 1 1 0 1 1 1 0'
                                 OR
      n(5,[0,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1,1,1,0])

Imagem:

Primeira imagem de exemplo

Saída:

           1
         2 1 2
       3 2 1 2 3
     +----------
    3|
  2 2|
1 1 1|
  2 2|
    3|

Entrada:

./nonogram <<< '15 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 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 1 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 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 1 0 1 0 0 1 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1 0 0 0 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1'

Imagem:

Segunda imagem de exemplo

Saída:

                   1                       1
                 1 1 3       3 5   5 3   3 1
                 7 2 3 2 4 2 3 210 2 3 0 4 215
               +------------------------------
              2|
              1|
              1|
              1|
              1|
            1 1|
        3 3 1 1|
        1 5 1 1|
          3 5 3|
          1 5 1|
          1 3 1|
      1 1 1 1 1|
1 1 1 1 1 1 1 1|
           11 3|
           11 3|

Esclarecimentos

  • Sua saída não precisa ser um quebra-cabeça solucionável. Nem todos os nonogramas são solucionáveis, mas essa não é sua preocupação. Basta emitir as dicas que correspondem à entrada, sejam elas um bom quebra-cabeça ou não.
  • É permitido um programa que aceita argumentos na linha de comando. É o tipo de afirmação acima, mas é possível ter uma idéia errada. É para isso que servem os esclarecimentos.
  • 0É obrigatório imprimir um para uma linha ou coluna que não tenha caixas preenchidas. Não digo isso com palavras em nenhum lugar, mas nos dados da amostra.
undergroundmonorail
fonte
Estou quase terminando com a minha solução. Podemos supor que não haverá um número de três dígitos de caixas em uma linha ou coluna?
afuous
2
@voidpigeon: 5<=n<=50é a especificação, por isso, não pode haver qualquer número de 3 dígitos
Kyle Kanos
Depois de postar essa pergunta, comecei a trabalhar em uma solução. Eu não vou postá-lo ainda (como por esta resposta meta), mas vou postar minha contagem de bytes para que você caras têm algo por que lutar: 404 bytes em Python 2.7
undergroundmonorail
Seu primeiro exemplo de saída não contém mais um -do que deveria?
Ventero
@ Ventro Você está correto! Eu sabia como escreveria um programa para fazer isso, mas na verdade não o fiz até agora, então minhas saídas de amostra estavam à mão. Opa! (I também asneira a segunda saída de exemplo, mas que fixa-lo antes de haver quaisquer respostas.)
undergroundmonorail

Respostas:

9

GolfScript, 128 caracteres

~](:k/.{{1,%{,}%.!,+}%}:^~{' ':s*}%.{,}%$-1=:9{s*\+9~)>'|'n}+%\zip^.{,~}%$0=){.~[s]*@+>{s\+-2>}%}+%zip{9)s*\n}%\[9s*'+''--'k*n]\

A entrada deve ser fornecida no STDIN como números separados por espaço.

Você pode testar o exemplo aqui .

Código comentado:

# Parse the input into an 2D array of digits. The width is saved to variable k
~](:k/

# Apply the code block ^ to a copy of this array
.
{                # begin on code block
  {              # for each line
   1,%           #   split at 0s (1, => [0]) (leading, trailing, multiple 0s are 
                 #   removed because of operator % instead of /)
   {,}%          #   calculate the length of each run of 1s                 
   .!,+          #   special case: only zeros, i.e. []
                 #   in this case the ! operator yiels 1, thus [0], else []
  }%             # end for
}:^              # end of code block
~                # apply

# Format row headers
{' ':s*}%        # join numbers with spaces
.{,}%$-1=:9      # calulate the length of the longest row header
                 # and save it to variable <9>
{                # for each row
  s*\+           #   prepend padding spaces
  9~)>           #   and cut at length <9> from the right
  '|'n           #   append '|' and newline
}+%              # end for

# Format column headers
\zip^            # transpose input array and apply the code block ^
                 # i.e. calculate length of runs
.{,~}%$0=)       # determine (negative) length of the longest column header
{                # for each column
  .~[s]*@+       #   prepend enough spaces
  >              #   and cut at common length (from right)
  {s\+-2>}%      #   format each number/empty to 2 chars width
}+%              # end for
zip              # transpose column header into output lines
{9)s*\n}%        # prepend spaces to each line and append newline

# Inject separator line
\[
9s*              # spaces
'+'              # a plus sign
'--'k*           # k (width) number of '--'
n                # newline
]\
Howard
fonte
11
Um bom, eu aprendi alguns truques bons deste post
Cristian Lupascu 4/14/14
Eu consegui jogar golfe com 123 caracteres: ~](:k/.zip\]{{1,%{,}%.!,+}%}/{' ':^*}%{.{,}%$-1=}:f~:r{^*\+r~)>'|'n}+%\f{.~)\[^]*@+>{^\+-2>}%}+%zip{r)^*\n}%r^*'+''--'k*n]((por algum motivo, lettercount.com diz 125 caracteres se você o copiar, mas garanto que são 123 caracteres). Algumas partes do algoritmo foram alteradas, mas a maioria ainda é a mesma. Também mudei alguns nomes de variáveis ​​(ter 9 como variável é inteligente, mas também confuso), mas você pode alterá-los novamente, se quiser.
Volatilidade
7

Ruby, 216 255

n=$*.shift.to_i;k=*$*.each_slice(n)
u=->k{k.map{|i|r=i.join.scan(/1+/).map{|i|"%2d"%i.size}
[*["  "]*n,*r[0]?r:" 0"][-n,n]}}
puts u[k.transpose].transpose.map{|i|" "*(n-~n)+i*""},"  "*n+?++"--"*n,u[k].map{|i|i*""+?|}

Embora isso não produza a amostra exata de saída dada na pergunta, ela segue as especificações. A única diferença para os exemplos é que eu imprimo alguns espaços / novas linhas.

Exemplo:

$ ruby nonogram.rb 15 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 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 1 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 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 1 0 1 0 0 1 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1 0 0 0 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1
# empty lines removed for brevity
                                  1                       1  
                                1 1 3       3 5   5 3   3 1  
                                7 2 3 2 4 2 3 210 2 3 0 4 215
                              +------------------------------
                             2|
                             1|
                             1|
                             1|
                             1|
                           1 1|
                       3 3 1 1|
                       1 5 1 1|
                         3 5 3|
                         1 5 1|
                         1 3 1|
                     1 1 1 1 1|
               1 1 1 1 1 1 1 1|
                          11 3|
                          11 3|

Changelog:

  • 240 -> 231: Formato de entrada alterado para usar argumentos de linha de comando em vez de stdin.
  • 231 -> 230: Eliminado um espaço movendo a verificação de valor de chunkpara map.
  • 230 -> 226: Subtraia em [nil]vez de chamar Array#compact.
  • 226 -> 216: Simplifique a geração de dicas.
Ventero
fonte
Você imprime algumas novas linhas e espaços extras, mas até agora em todos os meus testes eles se encaixam na especificação "0 ou mais", então você é bom. Estou avisando agora, no entanto, se eu começar a ver os números que flutuam no ar para a esquerda meu monitor, eu vou ter de desqualificar esta resposta :)
undergroundmonorail
11
@undergroundmonorail: A saída é impressa de tal forma que length(leading spaces + numbers to the left) == 2*ne height(leading newlines + numbers at the top) == n... portanto, desde que o seu monitor seja grande o suficiente para 3*n+1 × 2*n+2caracteres, você não precisará desqualificar-me. :)
Ventero
4

Ruby, 434

n=$*[i=0].to_i
a,b=[],[]
a.push $*.slice!(1..n)*""while $*.size>1
(b.push a.map{|c|c[i]}*"";i+=1)while i<n
a,b=*[a,b].map{|c|c.map{|d|e=d.split(/[0]+/).map(&:size).select{|f|f>i=0}.map &:to_s;(e.size>0)?e:[?0]}}
m,k=*[a,b].map{|c|c.map(&:size).max}
s="  "*m
k.times{$><<s+"  "+b.map{|c|(" "+((c.size==k-i)?(c.shift):(" ")))[-2..-1]}*"";i+=1;puts}
puts s+" "+?++?-*n*2
a.each{|c|puts"  "*(m-c.size)+" "+c.map{|d|(" "+d)[-2..-1]}*""+?|}
úmido
fonte
Como você executa isso? Eu tentei, ruby $yourprogram <<< $inputmas consegui ruby_nanograms:7:in '<main>': undefined method '+' for nil:NilClass (NoMethodError).
Undergroundmonorail
@undergroundmonorail ruby nonogram.rb 2 1 0 0 1para um 2x2
final
Essa é uma boa resposta, mas você não imprime 0a quarta quarta coluna no segundo exemplo.
Undergroundmonorail
Acabei de notar que a +------linha ... também é recuada por muitos espaços.
Undergroundmonorail
11
@undergroundmonorail Corrigido ambos.
afuous
4

GolfScript 149 147

O código

~](:s/.zip{{[0]%{,`}%['0']or}%.{,}%$)\;:¶;{.,¶\-[' ']*\+}%}:f~¶:v;\[f~]\zip{{{.,2\-' '*\+}%''*}:d2*)' '*:z\+{puts}:o~}%z(;'+'s'-'2**++o~{d'|'+o}/

Edições:

  • espaço inútil removido
  • definiu uma função reutilizável de um caractere para putssalvar mais um caractere

Demos online

Uma versão um pouco anotada do código

# split lines
~](:s/

# make transposed copy
.zip

#prepare numbers to show in the header
{{[0]%{,`}%['0']or}%.{,}%$)\;:¶;{.,¶\-[' ']*\+}%}:f~¶:v;

# prepare numbers to show in the left column
\[f~]\zip

#print header (vertical hints)
{  {{.,2\-' '*\+}%''*}:d~  2*)' '*:z\+puts}%

#print first line
z(;'+'s'-'2**++puts

#print horizontal hints
~{d'|'+ puts}/
Cristian Lupascu
fonte
4

Javascript (E6) 314 334 357 410

N=(d,l)=>{J=a=>a.join(''),M=s=>(s.match(/1+/g)||['']).map(x=>x.length),f=' '.repeat(d+1),c=[n='\n'],o=n+f+'+'+'--'.repeat(d);for(i=-1;++i<d;)c[i]=M(J(l.map((e,p)=>p%d-i?'':e))),o+=n+(f+J(M(J(l).substr(i*d,d)).map(P=n=>n>9?n:n<10?' '+n:'  '))+'|').slice(-d-2);for(;--i;)o=n+f+' '+J(c.map(e=>P(e.pop())))+o;return o}

Ungolfed

N=(d,l)=> {
  J = a => a.join(''),
  M = s => (s.match(/1+/g)||['']).map(x=>x.length),
  f=' '.repeat(d+1), c=[n='\n'], o=n+f+'+'+'--'.repeat(d);
  for(i = -1; ++i < d;)
    c[i] = M(J(l.map((e,p)=>p%d-i?'':e))),
    o += n+(f+J(M(J(l).substr(i*d,d)).map(P=n=>n>9?n:n<10?' '+n:'  '))+'|').slice(-d-2);
  for(;--i;)
    o=n+f+' '+J(c.map(e=>P(e.pop())))+o;
  return o
}

Uso

N(5,[0,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1,1,1,0])

N(15,[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,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,1,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,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,1,1,1,0,1,0,1,1,1,1,0,0,0,1,1,1,1,1,0,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1])

Editar histórico

1 Removido o regexp usado para encontrar colunas
. O Overkill 2 Simpler é melhor. Saída para uma sequência, não para uma matriz. Função auxiliar removida FILL (F)
3 Ainda mais simples. Eu não posso fazer melhor que isso. Ainda não se pode comparar com o Golfscript :(

edc65
fonte
Agradável. Também tentei uma versão Javascript, mas terminei com algo em torno de 500 bytes e decidi que era grande demais para colocá-la aqui. Seria bom publicar uma versão não-gasta com nomes de variáveis ​​originais (se você ainda a tiver). Além disso, como você executa isso? Se copiar e colar na janela do console do Chrome, recebo "ReferenceError: lado esquerdo inválido na atribuição". Existe algo para mudar ou adicionar antes de executar?
usar o seguinte
@tigrou desculpe a sintaxe "=>" funciona apenas no firefox. Variáveis: c colunns dicas, dimensão d, l lista de entrada, S saída, a variável de contagem i, q e temperatura z
edc65
-15 bytes :)
nderscore
@nderscore brincando com o código, obtive 326. No seu código, R não é inicializado (erro fácil quando você tenta repetidamente ...)
edc65
1

R, 384 caracteres

a=scan();p=function(x)paste(x,collapse="");P=paste0;s=sapply;l=length;f=function(i)lapply(apply(matrix(a[-1],nr=a,b=T),i,rle),function(x)if(any(x$v)){x$l[!!x$v]}else{0});g=function(j,i)apply(s(j,function(x)sprintf("%2s",c(rep("",max(s(j,l))-l(x)),x))),i,p);c=P(g(f(1),2),"|");d=g(f(2),1);h=p(rep(" ",nchar(c[1])-1));e=P(h,"+",p(rep("-",nchar(d[1]))));d=P(h," ",d);cat(d,e,c,sep="\n")

Com recuos e algumas explicações:

a=scan() #Takes input

p=function(x)paste(x,collapse="") #Creates shortcuts
P=paste0
s=sapply
l=length

#This function finds the number of subsequent ones in a line (using rle = run length encoding).
#It takes 1 or 2 as argument (1 being row-wise, 2 column-wise
f=function(i)lapply(apply(matrix(a[-1],nr=a,b=T),i,rle),function(x)if(any(x$v)){x$l[!!x$v]}else{0})

#This function takes the result of the previous and format the strings correctly (depending if they are rows or columns)
g=function(j,i)apply(s(j,function(x)sprintf("%2s",c(rep("",max(s(j,l))-l(x)),x))),i,p)

c=paste0(g(f(1),2),"|") #Computes the rows
d=g(f(2),1) #Computes the columns
h=p(rep(" ",nchar(c[1])-1)) 
e=paste0(h,"+",p(rep("-",nchar(d[1])))) #Prepare vertical border
d=paste0(h," ",d) #Pad column indices with spaces
cat(d,e,c,sep="\n") #Prints

Uso:

> a=scan();p=function(x)paste(x,collapse="");P=paste0;s=sapply;l=length;f=function(i)lapply(apply(matrix(a[-1],nr=a,b=T),i,rle),function(x)if(any(x$v)){x$l[!!x$v]}else{0});g=function(j,i)apply(s(j,function(x)sprintf("%2s",c(rep("",max(s(j,l))-l(x)),x))),i,p);c=P(g(f(1),2),"|");d=g(f(2),1);h=p(rep(" ",nchar(c[1])-1));e=P(h,"+",p(rep("-",nchar(d[1]))));d=P(h," ",d);cat(d,e,c,sep="\n")
1: 15 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 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 1 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 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 1 0 1 0 0 1 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1 0 0 0 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1
227: 
Read 226 items
                    1                       1  
                  1 1 3       3 5   5 3   3 1  
                  7 2 3 2 4 2 3 210 2 3 0 4 215
                +------------------------------
               2|
               1|
               1|
               1|
               1|
             1 1|
         3 3 1 1|
         1 5 1 1|
           3 5 3|
           1 5 1|
           1 3 1|
       1 1 1 1 1|
 1 1 1 1 1 1 1 1|
            11 3|
            11 3|
plannapus
fonte
1

C - 511

Definitivamente, o C não foi feito para formatar bem a saída. A contagem de caracteres inclui apenas os espaços necessários / novas linhas.

A entrada é de STDIN, números separados por espaços.

#define P printf
#define L(x) for(x=0;x<s/2+1;x++)
#define l(x) for(x=0;x<s;x++)
#define B(x,y) x[i][j]||y==s/2?P("%2d",x[i][j]):P("  ");
a[50][50],i,j,s,h[25][50],v[50][25],H[50],V[50],x[25],y[25];
main(){
    scanf("%d",&s);
    L(j)x[j]=y[j]=s/2+1;
    l(i)l(j)scanf("%d",&a[i][j]);
    for(i=s-1;i>=0;i--)
        for(j=s-1;j>=0;j--)
            a[i][j]?
                !H[j]&&(x[j]--,H[j]=1),
                h[x[j]][j]++,
                !V[i]&&(y[i]--,V[i]=1),
                v[i][y[i]]++:
            (H[j]=V[i]=0);
    L(i){
        L(j)P("  ");
        P(" ");
        l(j)B(h,i);
        P("\n");
    }
    L(i)P("  ");
    P("+");
    l(i)P("--");
    P("\n");
    l(i){
        L(j)B(v,j);
        P("|\n");
    }
}
Allbeert
fonte
1

Já faz alguns dias e ninguém respondeu em python, então aqui está minha (provavelmente muito pobre) tentativa:

Python 2.7 - 404 397 380 bytes

def p(n,m):
 k=str.join;l=[];g=lambda y:[['  ']*(max(map(len,y))-len(t))+t for t in[[' '*(a<10)+`a`for a in map(len,k("",c).split('0'))if a]or[' 0']for c in y]]
 while m:l+=[map(str,m[:n])];m=m[n:]
 x=g(l);j=k('\n',['  '*max(map(len,x))+'+'+k("",a)for a in zip(*[list(a)+['--']for a in g(zip(*l))])]);return j.replace('+',' ',j.count('+')-1)+'\n'+k('\n',[k("",a+['|'])for a in x])

Vou postar uma versão não-gasta em breve, mas no momento acho que é bem legível. :)

EDITAR: Enquanto escrevia a versão desregrada, notei algumas melhorias que eu poderia fazer que se somavam bastante significativas! Por alguma razão que não sei explicar, ele agora possui novas linhas adicionais na parte superior e espaços à esquerda (embora eu ache que não mudei nada funcional), mas ainda atende às especificações.Versão ungolfed está chegando!

Ungolfed:

def nonogram(board_size, pixels):
    def hints(board):
        output = []
        for row in board:
            # Convert the row to a string of 1s and 0s, then get a list of strings
            # that came between two 0s.
            s = "".join(row).split('0')

            # A list of the length of each string in that list.
            l = map(len, s)

            # We now have our horizontal hints for the board, except that anywhere
            # there were two 0s consecutively we have a useless 0.
            # We can get rid of the 0s easily, but if there were no 1s in the row at
            # all we want exactly one 0.
            # Solution:
            output.append([h for h in l if h != 0] or [0])
            # In this context, `foo or bar` means `foo if foo is a truthy value, bar
            # otherwise`.
            # An empty list is falsey, so if we strip out all the strings we hardcode
            # the 0.
        return output

    def num_format(hints):
        # For both horizontal and vertical hints, we want a space before single-
        # digit numbers and no space otherwise. Convert hints to strings and add
        # spaces as necessary.
        output = []

        for row in hints:
            output.append([' '*(a < 10) + str(a) for a in row])
            # Multiplying a string by n repeats it n times, e.g. 'abc'*3=='abcabcabc'
            # The only numbers that need a space are the ones less than 10.
            # ' '*(a < 10) first evaluates a < 10 to get a True or False value.
            # Python automatically converts True to 1 and False to 0.
            # So, if a is a one digit number, we do `' '*(1) + str(a)`.
            # If it's a two digit number, we do `' '*(0) + str(a)`.
        return output

    def padding(hints):
        output = []
        longest = max(map(len, hints)) # how long is the longest row?
        for row in hints:
            output.append(['  ']*(longest - len(row)) + row)
            # Add '  ' to the beginning of every row until it's the same length
            # as the longest one. Because all hints are two characters wide, this
            # ensures all rows of hints are the same length.
        return output

    board = []

    while pixels: # non-empty list == True
        # Make a list of the first (board_size) pixels converted to strings, then
        # add that list to board. Remove those pixels from the list of pixels.
        # When pixels is empty, board has a seperate list for each row.
        board.append([str(n) for n in pixels[:board_size]])
        pixels = pixels[board_size:]

    horizontal_hints = padding(num_format(hints(board)))

    vertical_hints = padding(num_format(hints(zip(*board))))
    # zip(*l) is a common way to transpose l.
    # zip([1,2,3], [4,5,6], [7,8,9]) == [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
    # the star operator unpacks an iterable so the contents can be used as
    # multiple arguments, so
    # zip(*[[1,2,3],[4,5,6],[7,8,9]]) is the same as what we just did.
    # Transposing the board and getting the horizontal hints gives us the
    # vertical hints of the original, but transposed. We'll transpose it back,
    # but we'll also add '--' to the end of all of them to make up the line
    vertical_hints = zip(*[a + ['--'] for a in vertical_hints])

    # add n spaces, where n is the length of the longest horizontal hint, plus
    # one space to the beginning of each line in the vertical hints, then join
    # with newlines to make it all one string.
    vertical_hints = '\n'.join(['  '*max(map(len, horizontal_hints)) + '+' +
                               ''.join(a) for a in vertical_hints])

    # find the number of plus signs in the string
    # replace the first (that many - 1) plus signs with spaces
    vertical_hints = vertical_hints.replace('+', ' ', vertical_hints.count('+')-1)

    # add a pipe to each row of horizontal hints, then join it with newlines
    horizontal_hints = '\n'.join([''.join(a + ['|']) for a in horizontal_hints])

    # add and return
    return vertical_hints + '\n' + horizontal_hints

Algumas alterações foram feitas para facilitar a leitura ( gsendo divididas em três funções nomeadas, compreensões complexas de listas transformadas em forloops), mas logicamente funciona exatamente da mesma maneira.

É por isso que é confuso que este não imprima espaços extras e novas linhas, enquanto o golfe o faz. ¯ \ _ (ツ) _ / ¯

undergroundmonorail
fonte
11
Umm, não consigo encontrar sua solução. (desculpe, apenas um terrível piada sobre a contagem de caracteres, não me importa :))
Doorknob
@dor Aha! Tente fazer suas piadas de código de erro HTTP agora! : P
undergroundmonorail