 # 0wl's solution

## to Queen Attack in the PHP Track

Published at Jul 20 2019 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other.

In the game of chess, a queen can attack pieces which are on the same row, column, or diagonal.

A chessboard can be represented by an 8 by 8 array.

So if you're told the white queen is at (2, 3) and the black queen at (5, 6), then you'd know you've got a set-up like so:

``````_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ W _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ B _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
``````

You'd also be able to answer whether the queens can attack each other. In this case, that answer would be yes, they can, because both pieces share a diagonal.

## Running the tests

1. Go to the root of your PHP exercise directory, which is `<EXERCISM_WORKSPACE>/php`. To find the Exercism workspace run

`````` % exercism debug | grep Workspace
``````
2. Get PHPUnit if you don't have it already.

`````` % wget --no-check-certificate https://phar.phpunit.de/phpunit.phar
% chmod +x phpunit.phar
``````
3. Execute the tests:

`````` % ./phpunit.phar queen-attack/queen-attack_test.php
``````

## Source

J Dalbey's Programming Practice problems http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### queen-attack_test.php

``````<?php

require "queen-attack.php";

class QueenAttackTest extends PHPUnit\Framework\TestCase
{
/**
* Test a queen is placed in a valid position.
*/
public function testCreateQueenWithValidPosition()
{
\$this->assertTrue(placeQueen(2, 2));
}

/**
* Test the queen is placed on a positive rank.
*/
public function testQueenHasPositiveRank()
{
\$this->expectException(InvalidArgumentException::class);
\$this->expectExceptionMessage('The rank and file numbers must be positive.');

placeQueen(-2, 2);
}

/**
* Test the queen has a rank on the board.
*/
public function testQueenHasRankOnBoard()
{
\$this->expectException(InvalidArgumentException::class);
\$this->expectExceptionMessage('The position must be on a standard size chess board.');

placeQueen(8, 4);
}

/**
* Test the queen is placed on a positive file.
*/
public function testQueenHasPositiveFile()
{
\$this->expectException(InvalidArgumentException::class);
\$this->expectExceptionMessage('The rank and file numbers must be positive.');

placeQueen(2, -2);
}

/**
* Test the queen has a file on the board.
*/
public function testQueenHasFileOnBoard()
{
\$this->expectException(InvalidArgumentException::class);
\$this->expectExceptionMessage('The position must be on a standard size chess board.');

placeQueen(4, 8);
}

/**
* Test if queens can attack each other.
*/
public function testQueensCanAttack()
{
\$this->assertFalse(canAttack([2, 4], [6, 6]));
}

/**
* Test if queens can attack each other on the same rank.
*/
public function testQueensCanAttackOnSameRank()
{
\$this->assertTrue(canAttack([2, 4], [2, 6]));
}

/**
* Test if queens can attack each other on the same file.
*/
public function testQueensCanAttackOnSameFile()
{
\$this->assertTrue(canAttack([4, 5], [2, 5]));
}

/**
* Test if queens can attack each other on the first diagonal.
*/
public function testQueensCanAttackOnFirstDiagonal()
{
\$this->assertTrue(canAttack([2, 2], [0, 4]));
}

/**
* Test if queens can attack each other on the second diagonal.
*/
public function testQueensCanAttackOnSecondDiagonal()
{
\$this->assertTrue(canAttack([2, 2], [3, 1]));
}

/**
* Test if queens can attack each other on the third diagonal.
*/
public function testQueensCanAttackOnThirdDiagonal()
{
\$this->assertTrue(canAttack([2, 2], [1, 1]));
}

/**
* Test if queens can attack each other on the fourth diagonal.
*/
public function testQueensCanAttackOnFourthDiagonal()
{
\$this->assertTrue(canAttack([2, 2], [5, 5]));
}
}``````
``````<?php

/**
* @param int \$rank
* @param int \$file
* @return bool
*/
function placeQueen(int \$rank, int \$file): bool
{
if (min([\$rank, \$file]) < 0) {
throw new InvalidArgumentException('The rank and file numbers must be positive.');
}

if (max([\$rank, \$file]) > 7) {
throw new InvalidArgumentException('The position must be on a standard size chess board.');
}

return true;
}

/**
* @param array \$queen1
* @param array \$queen2
* @return bool
*/
function canAttack(array \$queen1, array \$queen2): bool
{
if (\$queen1 - \$queen2 === 0 || \$queen1 - \$queen2 === 0) {
return true;
}

\$ranks = [];
for (\$i = 0; \$i < 8; \$i++) {
\$ranks[] = array_fill(0, 8, 0);
}

\$ranks[\$queen2][\$queen2] = \$ranks[\$queen1][\$queen1] = 1;
\$x = \$y = 0;
\$xLength = \$yLength = array_key_last(\$ranks);

foreach (\$ranks as \$rank) {
\$xCoordinates = range(\$x, \$xLength);
\$yCoordinates = range(\$y, \$yLength);
if (canAttackOnDiagonal(\$ranks, \$xCoordinates, \$yCoordinates)) {
return true;
};
\$x++;
\$yLength--;
}

\$x = array_key_last(\$ranks);
\$y = 0;
foreach (\$ranks as \$rank) {
\$xCoordinates = range(\$x, \$y);
\$yCoordinates = array_reverse(\$xCoordinates);
if (canAttackOnDiagonal(\$ranks, \$xCoordinates, \$yCoordinates)) {
return true;
};
\$y++;
}

\$x = array_key_last(\$ranks);
\$y = 0;
foreach (\$ranks as \$rank) {
\$xCoordinates = range(\$x, \$y);
\$yCoordinates = array_reverse(\$xCoordinates);
if (canAttackOnDiagonal(\$ranks, \$xCoordinates, \$yCoordinates)) {
return true;
};
\$x--;
}

return false;
}

/**
* @param array \$ranks
* @param array \$xCoordinates
* @param array \$yCoordinates
* @return bool
*/
function canAttackOnDiagonal(array \$ranks, array \$xCoordinates, array \$yCoordinates): bool
{
\$diagonalQueenCount = 0;
\$oppositeDiagonalQueenCount = 0;
foreach (\$xCoordinates as \$index => \$xCoordinate) {
\$diagonalQueenCount += \$ranks[\$xCoordinate][\$yCoordinates[\$index]];
\$oppositeDiagonalQueenCount += \$ranks[\$yCoordinates[\$index]][\$xCoordinate];
}

if (\$diagonalQueenCount === 2 || \$oppositeDiagonalQueenCount === 2) {
return true;
}

return false;
}``````