3
$\begingroup$

In how many different ways can two knights and two rooks be placed on $6\times 6$ chessboard so that no one attacks the others?

  • 0
    What is your formula so far?2017-01-23
  • 0
    I doubt that there's a "formula". The rooks cover two rows and two columns, but the count of knight placements will depend on which two. It's not hard to write a program to enumerate the possibilities.2017-01-23
  • 0
    i dont know program but i want to learn answers and solutions :)2017-01-23
  • 0
    Start by putting the first rook. THanks to the symmetry, you have, essentially, only $6$ possible places. Then put the second and so on...2017-01-23

1 Answers 1

0

I don't have a formula, but I brute forced it for you, using the same script I provided in your question on an other website.

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++.'
'.$solution.'
'; } 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 = '
') { $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.'
'; } } //configure the pieces to be added $pieces = array( new Rook(), new Rook(), new Knight(), new Knight() ); $boardSize = 6; $app = new App($pieces, $boardSize); //run it $app->execute(); //see if it worked echo $app->printSolutions();

and got 22248 results (including rotations and symmetrical positions).
The script is far from optimal, but it seams to work. You can try it yourself on http://phpfiddle.org/