ピザを同じスライスに切る


16

これは、私が完全に読む前に、この質問がそうなると思っいたものです。

コードゴルファーのグループがThe Nineteenth Bite Pizzeriaに入ってピザを注文します。不規則な形状で、単位は正方形です。あなたの仕事は、彼らがそれを同一のスライスにカットするのを助けることです。つまり、スライスの形状とサイズはまったく同じでなければなりません。回転させることはできますが、反転/ミラーリングすることはできません。たとえば、テトリスのピースの場合、それらは同じ種類である必要があり、LピースとJピースの両方を使用することはできません。

入力

グループの人数を最初の行(常に2〜10の整数)で指定し、その後にピザを表す ''(スペース)および '#'文字の長方形の行列が続きます。すべての「#」文字は、エッジを介して接続されています。「#」文字の数は、人数の倍数であることが保証されています。

出力

同じマトリックスを印刷し、各「#」文字を0〜n-1(nは人数)の数字に置き換えます。各桁はスライスをマークする必要があります。スライス形状は、正方形のエッジで接続する必要があります。スライスの番号付けは、特定の順序である必要はありません。ピザを切る方法が複数ある場合は、どれでもかまいません。
必要に応じてピザをカットできない場合は、「No pizza for you!」という文字列を印刷する必要があります。代わりに。

得点

これはコードゴルフです。スコアはプログラムのバイト数になります。文字は、UTF-8エンコードによってカウントされます。最低スコアが勝ちます。

入力:

3
 #  
### 
####
   #

出力:

 0  
100 
1122
   2

入力:

4
###
# #
###

出力:

001
2 1
233

入力:

2
#    #
######

出力:

No pizza for you!

入力:

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

出力:

    0  
   1000
  21110
 32221 
43332  
4443   
  4    

入力:

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

出力:

   0   
 1000  
111203 
  12233
  2233 

必要条件

  • 標準入力から読み取り、標準出力に書き込む完全なプログラムを作成する必要があります。
  • プログラムは、自由に利用可能なソフトウェアを使用してLinuxで実行可能である必要があります。
  • プログラムは、最新のコンピューターで1分未満で上記の各例を完了する必要があります。
  • 標準的な抜け穴はありません。

3
第19 :^)
FryAmTheEggman

@FryAmTheEggman©Calvin's Hobbies
aditsu

正規表現ソリューションのボーナス。
flawr

回答:


3

PHPコード、 1808 971バイト

PHPでの迅速でダーティな実装。最初に、可能なすべてのスライス形状をブルートフォースし、次にスライスのすべての位置と方向をブルートフォースします。

使用法: cat pizza.txt | php pizza.php

編集:ネストされたループではなく、再帰を使用するアルゴリズムを書き換えることにより、コードサイズを45%以上削減しました。ただし、これは記憶力を消費します(ピザの;-))。ピザのサイズが8x8より大きいと、おそらくメモリ不足になります。ネストされたループバリアントは、任意のサイズを簡単に処理できますが、コードサイズは2倍です。

<?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);}

記録されていない、文書化されたコード

以下は、文書化された元のコードです。私の正気を保つために、私は完全なソースコードで働いていた、とのようなステートメントを除去するために、単純なminifierスクリプトを書いたassert()error_reporting()、上記golfedコードを生成するために、不必要なブラケット、リネーム、変数、関数と定数を削除します。

<?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) ;
      }
   }
}

「PHPの致命的なエラー:1行目のpizza.phpで_()を再宣言できません」
-aditsu

@aditsu:ゴルフバージョンには関数_()が1つだけあります。誤ってコードを2回コピーして貼り付けましたか?
ジェイソンスミス

ファイルサイズは972なので、コードが2回収まるとは思いません。改変されていないコードは次のように機能するようです:)
aditsu

私はあなたが持っていることに気づきましたdefine('_',98)、それは衝突しませんfunction _か?私はphpを知らないのでわかりません
...-aditsu

@aditsu:ゴルフされたコードはPHP 5.4.43を搭載したMacで正常に動作しますが、_()は他のプラットフォームのgettext()のエイリアスのようです。_()が完全に回避されるように、ミニファイヤが変更されました。
ジェイソンスミス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.