2184 solutions. / 546 if you exclude rotations.
2184 solutions. / 546 if you exclude rotations.
2184 solutions.
Even if I was a few minutes late I still want to post this because I'm really proud of my work and I invested some time in it.
I've brute forced it and got
2184 solutions. / 546 if you exclude rotations.
I chose PHP as my weapon.
The script below can be extended to check for other pieces just by creating the additional classes like Queen
, Bishop
and implementing the method attack
that returns true or false depending if the current position of a piece attacks or not a certain square.
<?php
class ReachedEndException extends Exception {}
class Point
{
/**
* @var int
*/
private $x;
/**
* @var int
*/
private $y;
public function __construct($x, $y)
{
$this->setX($x);
$this->setY($y);
}
/**
* @return int
*/
public function getX()
{
return $this->x;
}
/**
* @param $x
* @return $this
*/
public function setX($x)
{
$this->x = $x;
return $this;
}
/**
* @return int
*/
public function getY()
{
return $this->y;
}
/**
* @param $y
*/
public function setY($y)
{
$this->y = $y;
}
/**
* @param Point $p
* @return bool
*/
public function equals(Point $p)
{
return ($this->getX() == $p->getX() && $this->getY() == $p->getY());
}
/**
* used for debugging
*
* @return string
*/
public function __toString()
{
return '('.$this->x.', '.$this->y.')';
}
}
interface PieceInterface
{
/**
* @param Point $p
* @return bool
*/
public function attack(Point $p);
}
abstract class Piece implements PieceInterface
{
/**
* @var Point
*/
protected $position;
/**
* @var string
*/
protected $notation = '';
/**
* Piece constructor.
* @param Point|null $position
*/
public function __construct(Point $position = null)
{
$this->position = $position;
}
/**
* @return Point
*/
public function getPosition()
{
return $this->position;
}
/**
* @return mixed
*/
public function getNotation()
{
return $this->notation;
}
/**
* @param Point $position
*/
public function setPosition($position)
{
$this->position = $position;
}
/**
* used for debugging
* @return string
*/
public function __toString()
{
return $this->notation.$this->getPosition();
}
public abstract function attack(Point $p);
}
class Rook extends Piece implements PieceInterface
{
/**
* @var string
*/
protected $notation = 'R';
/**
* @param Point $p
* @return bool
*/
public function attack(Point $p)
{
if (!$this->position) {
return false;
}
return ($this->getPosition()->getX() == $p->getX() || $this->getPosition()->getY() == $p->getY());
}
}
class Knight extends Piece implements PieceInterface
{
/**
* @var string
*/
protected $notation = 'K';
/**
* @param Point $p
* @return bool
*/
public function attack(Point $p)
{
if (!$this->position) {
return false;
}
$thisX = $this->getPosition()->getX();
$thisY = $this->getPosition()->getY();
$pointX = $p->getX();
$pointY = $p->getY();
if (abs($thisX - $pointX) == 2 && abs($thisY - $pointY) == 1) {
return true;
}
if (abs($thisX - $pointX) == 1 && abs($thisY - $pointY) == 2) {
return true;
}
return false;
}
}
class App
{
/**
* board X size
* @var int
*/
private $boardX;
/**
* board Y size
* @var int
*/
private $boardY;
/**
* pieces to add on the table
* @var Piece[]
*/
protected $piecesToAdd = array();
/**
* all solutions
* @var string[]
*/
protected $solutions = array();
/**
* already added pieces
* @var Piece[]
*/
private $pieces = array();
/**
* App constructor.
* @param $boardX
* @param null $boardY
* @param $piecesToAdd
*/
public function __construct($piecesToAdd, $boardX, $boardY = null)
{
if (is_null($boardY)) {
$boardY = $boardX;
}
$this->boardX = $boardX;
$this->boardY = $boardY;
$this->piecesToAdd = $piecesToAdd;
}
/**
* add a piece on the board
* @param Piece $p
* @param Point $point
* @return bool
*/
public function addPiece(Piece $p, Point $point)
{
$p->setPosition($point);
$canPlace = true;
//check of the piece does not attack the other set pieces or if it's not attacked by one
foreach ($this->pieces as $piece) {
if (
$p->getPosition()->equals($piece->getPosition())
|| $p->attack($piece->getPosition()) ||
$piece->attack($p->getPosition())
) {
$canPlace = false;
}
}
if ($canPlace) {
$this->pieces[] = $p;
$this->pieces = array_values($this->pieces);
return true;
} else {
//if a piece cannot be added, move to the next position
$nextPoint = $this->incrementPoint($point);
if ($nextPoint) {
return $this->addPiece($p, $nextPoint);
}
}
//if there is no valid position return false
return false;
}
/**
* get the next position where you can add a piece if you need to move one
* @return bool|Point
*/
private function getNextPosition()
{
$nextPosition = false;
while (!$nextPosition) {
//remove last piece and increment the position for the previous one.
$piece = end($this->pieces);
if (!$piece) {
throw new ReachedEndException();
}
$position = clone $piece->getPosition();
$nextPosition = $this->incrementPoint($position);
$this->removePiece(count($this->pieces) - 1);
}
return $nextPosition;
}
/**
* do the dew
* @return App
*/
public function execute()
{
$currentPosition = new Point(0, 0);
$added = true;
while (true) {
while ($added && !$this->isBoardFilled()) {
$pieceToAdd = $this->piecesToAdd[count($this->pieces)];
$added = $this->addPiece($pieceToAdd, $currentPosition);
//if a piece was added start the next one from top left corner
if ($added) {
$currentPosition = new Point(0, 0);
}
}
//if we cannot add a piece, remove the last one(s) and check the next valid position
if (!$added) {
try {
$currentPosition = $this->getNextPosition();
} catch (ReachedEndException $e) {
//it means we cannot move anything arround anymore
return $this;
}
$added = true;
} elseif ($this->isBoardFilled()) {
//if the board is in a valid position save the state
$solution = $this->printBoardState();
//remember a hash of the position to avoid duplicates
$hash = sha1($solution);
$this->solutions[$hash] = $solution;
try {
$currentPosition = $this->getNextPosition();
} catch (ReachedEndException $e) {
//it means we are done
return $this;
}
} else {
$added = true;
//start over
$currentPosition = new Point(0, 0);
}
}
return $this;
}
/**
* form a readable string with the solutions
* @return string
*/
public function printSolutions()
{
$string = '';
$increment = 1;
foreach ($this->solutions as $solution) {
$string .= 'Solution '.$increment++.'<br />'.$solution.'<br />';
}
return $string;
}
/**
* remove a piece
* @param $index
* @return App
*/
private function removePiece($index)
{
unset($this->pieces[$index]);
return $this;
}
/**
* check if all pieces are on the board
* @return bool
*/
public function isBoardFilled()
{
return count($this->pieces) == count($this->piecesToAdd);
}
/**
* generate the board configuration string
* @param string $positionSeparator
* @param string $blank
* @param string $lineSeparator
* @return string
*/
private function printBoardState($positionSeparator = '|', $blank = '--', $lineSeparator = '<br />')
{
$board = array();
$text = '';
foreach ($this->pieces as $piece) {
$position = $piece->getPosition();
$board[$position->getX()][$position->getY()] = $piece->getNotation();
}
for ($i = 0;$i<$this->boardX; $i++) {
$text .= $positionSeparator;
for ($j = 0;$j<$this->boardY; $j++) {
if (isset($board[$i][$j])) {
$text .= $board[$i][$j];
} else {
$text .= $blank;
}
$text .= $positionSeparator;
}
$text .= $lineSeparator;
}
return $text;
}
/**
* get the next valid point
* @param Point $p
* @return bool|Point
*/
private function incrementPoint(Point $p)
{
if ($p->getX() == $this->boardX - 1) {
if ($p->getY() == $this->boardY - 1) {
return false; //reached the end
}
return new Point(0, $p->getY() + 1);
}
return new Point($p->getX()+1, $p->getY());
}
/**
* take a whild guess
* @return string
*/
public function debug()
{
$string = "state: ";
foreach ($this->pieces as $piece) {
$string.= ' '.$piece.'--';
}
return $string.'<br />';
}
}
//configure the pieces to be added
$pieces = array(
new Rook(),
new Rook(),
new Knight(),
new Knight()
);
$boardSize = 5;
$app = new App($pieces, $boardSize);
//run it
$app->execute();
//see if it worked
echo $app->printSolutions();
you can give it a try by copy/pasting it into http://phpfiddle.org/.
You will see results like:
Solution 1
|R |--|--|--|--|
|--|R |--|--|--|
|--|--|K |--|--|
|--|--|--|--|--|
|--|--|K |--|--|
or
Solution 481
|--|--|--|--|--|
|--|K |--|--|--|
|R |--|--|--|--|
|--|--|--|R |--|
|--|--|K |--|--|
Just chose 2 at random.