I thought I'd do an animation of the switchings on-and-off (just getting the answer is straightforward: each light is flipped on each pass corresponding to one of its distinct factors; those left on at the end are those with an odd number of distinct factors, i.e., squares). It had been a while since I'd used GD, long enough to forget that it didn't support animated gifs.
const SIZE = 100;
class GridImage
{
const BulbSize = 20;
const Padding = 2;
private int $bulb_width = 0;
private int $bulb_height = 0;
private int $pixel_width = 0;
private int $pixel_height = 0;
private GdImage $image;
private int $light_on = 0;
private int $light_off = 0;
private function n_to_wh(int $n): array
{
--$n;
$w = $n % $this->bulb_width;
$h = ($n - $w)/$this->bulb_width;
return [$w, $h];
}
public function __construct()
{
$this->bulb_width = (int)ceil(sqrt(SIZE));
$this->bulb_height = (int)ceil(SIZE / $this->bulb_width);
$this->pixel_width = ($this->bulb_width - 1) * self::BulbSize + (self::BulbSize - 1) * self::Padding;
$this->pixel_height = ($this->bulb_height - 1) * self::BulbSize + (self::BulbSize - 1) * self::Padding;
$this->image = imagecreate($this->pixel_width, $this->pixel_height);
imagefill($this->image, 0, 0, imagecolorallocate($this->image, 0, 0, 0));
$this->light_off = imagecolorallocate($this->image, 10, 10, 10);
$this->light_on = imagecolorallocate($this->image, 255, 255, 64);
for($i = 1; $i <= SIZE; ++$i)
{
$this->paint_bulb($i, false);
}
}
public function paint_bulb(int $i, bool $state): void
{
$state = $state ? $this->light_on : $this->light_off;
[$wpos, $hpos] = $this->n_to_wh($i);
$xpos = $wpos * (self::BulbSize + self::Padding);
$ypos = $hpos * (self::BulbSize + self::Padding);
imagefilledrectangle($this->image, $xpos, $ypos, $xpos + self::BulbSize, $ypos + self::BulbSize, $state);
}
public function getImage(): GdImage
{
return $this->image;
}
}
function toggles()
{
for($i = 1; $i <= SIZE; ++$i)
{
for($j = 1; $j <= SIZE; ++$j)
{
($j % $i) or yield $j;
}
}
}
function actions()
{
$array = array_fill(0, SIZE, false);
foreach(toggles() as $toggle)
{
yield [$toggle, $array[$toggle - 1] = !$array[$toggle - 1]];
}
}
$gridimage = new GridImage;
$digs = (int)ceil(log10(SIZE))+1;
$frame = 0;
$filenames = [];
foreach(actions() as [$i, $state])
{
$frame++;
$gridimage->paint_bulb($i, $state);
imagegif($gridimage->getImage(), $filenames[] = sprintf("frames/%0*d.gif", $digs, $frame));
}
$command = "gifsicle --delay 12 -O3 " . join(' ', $filenames) . " > lightup.gif";
`$command`;