Cortar una pizza en rebanadas idénticas

16

Esto es lo que pensé que iba a ser esta pregunta , antes de leerla completamente.

Un grupo de golfistas de código entra en The Nineteenth Bite Pizzeria y pide una pizza. Viene en una forma irregular, hecha de cuadrados unitarios. Su tarea es ayudarlos a cortarlo en rodajas idénticas. Es decir, las rodajas deben tener exactamente la misma forma y tamaño; se pueden girar pero no voltear / reflejar. Por ejemplo, si son piezas de Tetris, deben ser del mismo tipo, no puede usar tanto una pieza L como una pieza J.

Entrada

Se le dará el número de personas en el grupo en la primera línea (siempre un número entero de 2 a 10, inclusive), seguido de una matriz rectangular de caracteres '' (espacio) y '#', que representan la pizza. Todos los caracteres '#' están conectados a través de sus bordes. El número de caracteres '#' está garantizado para ser un múltiplo del número de personas.

Salida

Debe imprimir la misma matriz, con cada carácter '#' reemplazado con un dígito de 0 a n-1 (n es el número de personas). Cada dígito debe marcar una rebanada. La forma del corte debe estar conectada a través de los bordes cuadrados. La numeración de la porción no necesita estar en ningún orden en particular. Si hay varias formas de cortar la pizza, cualquiera de ellas es aceptable.
Si no es posible cortar la pizza según sea necesario, debe imprimir la cadena "¡No hay pizza para usted!" en lugar.

Puntuación

Este es el código de golf. Su puntaje será el número de bytes en el programa. Los caracteres se contarán a través de su codificación UTF-8. La puntuación más baja gana.

Ejemplos

Entrada:

3
 #  
### 
####
   #

Salida:

 0  
100 
1122
   2

Entrada:

4
###
# #
###

Salida:

001
2 1
233

Entrada:

2
#    #
######

Salida:

No pizza for you!

Entrada:

5
    #  
   ####
  #####
 ##### 
#####  
####   
  #    

Salida:

    0  
   1000
  21110
 32221 
43332  
4443   
  4    

Entrada:

4
   #   
 ####  
###### 
  #####
  #### 

Salida:

   0   
 1000  
111203 
  12233
  2233 

Requisitos

  • Debe escribir un programa completo que lea desde la entrada estándar y escriba en la salida estándar.
  • El programa debe ser ejecutable en Linux utilizando software disponible gratuitamente.
  • Su programa debe terminar cada uno de los ejemplos anteriores en menos de 1 minuto en una computadora moderna.
  • No hay lagunas estándar.
aditsu
fuente
3
The Nineteenth Bite : ^)
FryAmTheEggman
@FryAmTheEggman © Pasatiempos de Calvin
aditsu
Bonificación por soluciones regex.
flawr

Respuestas:

3

Código PHP, 1808 971 bytes

Implementación rápida y sucia en PHP. Primero fuerza bruta todas las formas posibles de corte, luego fuerza bruta todas las posiciones y orientaciones de los cortes.

Uso: cat pizza.txt | php pizza.php

Editar: redujo el tamaño del código en más del 45% al ​​volver a escribir el algoritmo utilizando recursividad en lugar de bucles anidados. Sin embargo, esto consume memoria (y pizza ;-)). Las pizzas de más de 8x8 probablemente se quedarán sin memoria. La variante de bucle anidado puede manejar fácilmente cualquier tamaño, pero es dos veces el tamaño del código.

<?php define('A',98);$n=fgets(STDIN);$d=array();$m=$u=str_pad('',A,'+');$s=0;while($g=fgets(STDIN)){$g=rtrim($g);assert(strlen($g)<=A-2);$s++;$m.='+'.str_pad(rtrim($g),A-2,' ').'+';for($l=0;$l<strlen($g);$l++)if($g[$l]=='#')$d[]=$s*A+$l+1;}$m.=$u;$r=count($d)/$n;x(reset($d),array(array()),0,0,0,0);die('No pizza for you!');function x($e,$c,$b,$a,$q,$t){global$r,$m,$d;$h=$a*A+$b;if(!in_array($e+$h,$d))return;if(in_array($h,$c[0]))return;$c[0][]=$h;$c[1][]=$b*A-$a;$c[2][]=-$a*A-$b;$c[3][]=-$b*A+$a;if(count($c[0])<$r)do{x($e,$c,$b+1,$a,$b,$a);x($e,$c,$b,$a+1,$b,$a);x($e,$c,$b-1,$a,$b,$a);x($e,$c,$b,$a-1,$b,$a);$v=($b!=$q||$a!=$t);$b=$q;$a=$t;}while($v);else w($c,$m,0,reset($d),0);}function w(&$p,$f,$o,$e,$i){global$n,$d;foreach($p[$i]as$h){$j=$e+$h;if(!isset($f[$j])||$f[$j]!='#')return;$f[$j]=chr(ord('0')+$o);}if(++$o==$n){for($k=A;$k<strlen($f)-A;$k++)if($k%A==A-1)echo PHP_EOL;else if($k%A)echo$f[$k];exit;}foreach($d as$j)for($i=0;$i<4;$i++)w($p,$f,$o,$j,$i);}

Código no documentado y documentado

A continuación se muestra el código original documentado. Para mantener mi cordura, trabajé con el código fuente completo y escribí un script minificador simple para eliminar las declaraciones como assert()y error_reporting(), eliminar corchetes innecesarios, renombrar variables, funciones y constantes para generar el código de golf anterior.

<?php
error_reporting(E_ALL) ;

// Width of each line of pizza shape.
// Constant will be reduced to single character by minifier,
// so the extra cost of the define() will be gained back.
define('WIDTH', 98) ;

// Read number of slices
$nrSlices = fgets(STDIN) ;

// Read pizza shape definition and 
// convert to individual $positionList[]=$y*width+$x and
// linear (1D) $pizzaShape[$y*WIDTH+$x] with protective border around it.
//
// WARNING: assumes maximum pizza width of WIDTH-2 characters!
$positionList = array() ;
$pizzaShape = $headerFooter = str_pad('', WIDTH, '+') ;
$y = 0 ;
while ($line = fgets(STDIN))
{  $line = rtrim($line) ;
   assert(strlen($line) <= WIDTH-2) ;
   $y++ ;
   $pizzaShape .= '+'.str_pad(rtrim($line), WIDTH-2, ' ').'+' ;
   for ($x = 0 ; $x < strlen($line) ; $x++)
   {  if ($line[$x] == '#') $positionList[] = $y*WIDTH + $x+1 ;
   }
}
$pizzaShape .= $headerFooter ;

// Determine size of a slice
$sliceSize = count($positionList)/$nrSlices ;

// Build all possible slice shapes. All shapes start with their first part at 
// the top of the pizza, and "grow" new parts in all directions next to the 
// existing parts. This continues until the slice has the full size. This way
// we end up with all shapes that fit at the top of the pizza.
//
// The shape is defined as the offsets of the parts relative to the base 
// position at the top of the pizza. Offsets are defined as linear offsets in
// the 1-D $pizzaShape string.
//
// For efficiency, we keep track of all four possible rotations while building
// the slice shape.
//
growSlice(reset($positionList), array(array()), 0, 0, 0, 0) ;
die('No pizza for you!') ;

function growSlice($basePosition, $shapeDeltas, $dx, $dy, $prevDx, $prevDy)
{  global $sliceSize, $pizzaShape, $positionList ;

   // Check validity of new position
   // Abort if position is not part of pizza, or 
   // if position is already part of slice
   $delta = $dy*WIDTH + $dx ;
   if (!in_array($basePosition+$delta, $positionList)) return ;
   if (in_array($delta, $shapeDeltas[0])) return ;

   // Add all four rotations to shapeDeltas[]
   $shapeDeltas[0][] = $delta ;
   $shapeDeltas[1][] = $dx*WIDTH - $dy ;
   $shapeDeltas[2][] = -$dy*WIDTH - $dx ;
   $shapeDeltas[3][] = -$dx*WIDTH + $dy ;

   // Have we built a full slice shape?
   if (count($shapeDeltas[0]) < $sliceSize) 
   {  // Grow shape either at current position or at previous position
      do
      {  growSlice($basePosition, $shapeDeltas, $dx+1, $dy,   $dx, $dy) ;
         growSlice($basePosition, $shapeDeltas, $dx,   $dy+1, $dx, $dy) ;
         growSlice($basePosition, $shapeDeltas, $dx-1, $dy,   $dx, $dy) ;
         growSlice($basePosition, $shapeDeltas, $dx,   $dy-1, $dx, $dy) ;
         $retry = ($dx != $prevDx || $dy != $prevDy) ;
         $dx = $prevDx ;
         $dy = $prevDy ;
      } while ($retry) ;
   } else
   {  // Try to cover the entire pizza by translated and rotated instances of
      // the slice shape.
      fitSlice($shapeDeltas, $pizzaShape, 0, reset($positionList), 0) ;
   }
}

function fitSlice(&$shape, $pizza, $id, $basePosition, $rotation)
{  global $nrSlices, $positionList ;

   // Try to fit each part of the slice onto the pizza. If the part falls
   // outsize the pizza, or overlays another slice we reject this position
   // and rotation. If it fits, we mark the $pizza[] with the slice $id.
   foreach ($shape[$rotation] as $delta)
   {  $position = $basePosition + $delta ;
      if (!isset($pizza[$position]) || $pizza[$position] != '#') return ;
      $pizza[$position] = chr(ord('0')+$id) ;
   }

   // If $nrSlices slices have been fitted, we have found a valid solution!
   // In that case, we display the solution and quit.
   if (++$id == $nrSlices)
   {  for ($pos = WIDTH ; $pos < strlen($pizza)-WIDTH ; $pos++)
      {  if ($pos % WIDTH == WIDTH-1) echo PHP_EOL ;
         else if ($pos % WIDTH) echo $pizza[$pos] ;
      }
      exit ;
   }

   // The current slice did fit, but we have still more slices to fit.
   // Try all positions and rotations for the next slice.
   foreach ($positionList as $position)
   {  for ($rotation = 0 ; $rotation < 4 ; $rotation++)
      {  fitSlice($shape, $pizza, $id, $position, $rotation) ;
      }
   }
}
Jason Smith
fuente
Me estoy poniendo "PHP Fatal error: No se puede redeclare _ () en pizza.php en la línea 1"
aditsu
@aditsu: solo hay una función _ () en la versión de golf. ¿Copiaste y pegaste accidentalmente el código dos veces?
Jason Smith
El tamaño del archivo es 972, así que no creo que el código pueda caber dos veces. El código no protegido parece funcionar por cierto :)
Aditsu
Me di cuenta de que define('_',98)sí, ¿no está en conflicto con eso function _? No sé php, así que no puedo decir ...
Aditsu
@aditsu: El código de golf funciona bien en mi Mac con PHP 5.4.43, pero parece que _ () es un alias para gettext () en otras plataformas. Se modificó el minificador para evitar _ () por completo.
Jason Smith