Last active
May 23, 2021 11:53
-
-
Save drjamesj/0e407e69824a5a60154bc6bcdb530f39 to your computer and use it in GitHub Desktop.
Wordsearch Generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class WordsearchGenerator | |
{ | |
private array $matrix; | |
private array $letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; | |
private int $dimension = 14; | |
private array $leftMargin = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; | |
// 'Circular' wordsearch grid | |
// private array $leftMargin = [6, 3, 2, 1, 1, 1, 0, 0, 1, 1, 1, 2, 3, 6]; | |
private array $movement = [ | |
[0, 1], [1, 1], [1, 0], [1, -1], | |
[0, -1], [-1, -1], [-1, 0], [-1, 1], | |
]; | |
private array $usedWords = []; | |
private array $unusedWords = []; | |
public function __construct($words = []) | |
{ | |
$this->createWordMatrix(array_map(fn ($w) => strtoupper($w), $words)); | |
} | |
public function getMatrix(): array | |
{ | |
return $this->matrix; | |
} | |
public function getUsedWords(): array | |
{ | |
return $this->usedWords; | |
} | |
public function getUnusedWords(): array | |
{ | |
return $this->unusedWords; | |
} | |
/** | |
* Initiates the word matrix grid. | |
* # - denotes fillable cell | |
* * - denotes unfillable cell for padding | |
*/ | |
private function initiateMatrix(): void | |
{ | |
$matrix = []; | |
for ($i = 0; $i < $this->dimension; $i++) { | |
for ($j = 0; $j < $this->dimension; $j++) { | |
$matrix[$i][$j] = '#'; | |
} | |
} | |
for ($i = 0; $i < $this->dimension; $i++) { | |
for ($j = 0; $j < $this->leftMargin[$i]; $j++) { | |
$matrix[$i][$j] = '*'; | |
$matrix[$i][$this->dimension - $j - 1] = '*'; | |
} | |
} | |
$this->matrix = $matrix; | |
} | |
/** | |
* Validates word against length requirements and removes word substrings | |
*/ | |
private function validWord(string $word = ''): bool | |
{ | |
if (strlen($word) < 2 || strlen($word) > 14) { | |
return false; | |
} | |
if ( | |
count( | |
array_filter($this->usedWords, fn ($w) => strpos($w, $word) !== false) | |
) | |
) { | |
return false; | |
} | |
return true; | |
} | |
/** | |
* Used to validate a potential word position and direction in the current matrix | |
*/ | |
private function validWordPosition($i, $j, $word, $direction): bool | |
{ | |
$ii = $i; | |
$jj = $j; | |
for ($k = 0; $k < strlen($word); $k++) { | |
if ($ii < 0 || $ii >= $this->dimension) return false; | |
if ($jj < 0 || $jj >= $this->dimension) return false; | |
if ($this->matrix[$ii][$jj] == '*') return false; | |
if ($this->matrix[$ii][$jj] != $word[$k] && $this->matrix[$ii][$jj] != '#') return false; | |
$ii = $ii + $this->movement[$direction][0]; | |
$jj = $jj + $this->movement[$direction][1]; | |
} | |
return true; | |
} | |
private function addWordToMatrix($i, $j, $word, $direction): void | |
{ | |
$ii = $i; | |
$jj = $j; | |
for ($k = 0; $k < strlen($word); $k++) { | |
$this->matrix[$ii][$jj] = $word[$k]; | |
$ii = $ii + $this->movement[$direction][0]; | |
$jj = $jj + $this->movement[$direction][1]; | |
} | |
} | |
private function createWordMatrix($words = []) | |
{ | |
$this->initiateMatrix(); | |
foreach ($words as $word) { | |
if ($this->validWord($word)) { | |
$valid = false; | |
$positions = range(0, pow($this->dimension, 2)); | |
shuffle($positions); | |
for ($t = 0; $t < pow($this->dimension, 2); $t++) { | |
$i = floor($positions[$t] / $this->dimension); | |
$j = $positions[$t] % $this->dimension; | |
$directions = range(0, 7); | |
shuffle($directions); | |
foreach ($directions as $direction) { | |
if ($this->validWordPosition($i, $j, $word, $direction)) { | |
$this->addWordToMatrix($i, $j, $word, $direction); | |
$valid = true; | |
break; | |
} | |
} | |
if ($valid) { | |
break; | |
} | |
} | |
if ($valid) { | |
$this->usedWords[] = $word; | |
} else { | |
$this->unusedWords[] = $word; | |
} | |
} else { | |
$this->unusedWords[] = $word; | |
} | |
} | |
for ($i = 0; $i < $this->dimension; $i++) { | |
for ($j = 0; $j < $this->dimension; $j++) { | |
if ($this->matrix[$i][$j] == '#') { | |
$this->matrix[$i][$j] = $this->letters[array_rand($this->letters)]; | |
} | |
} | |
} | |
} | |
} | |
// Create 'fruit' wordsearch | |
$fruits = new WordsearchGenerator(['Banana', 'Apple', 'Orange', 'Pear', 'Lemon', 'Watermelon', 'Grape', 'Melon', 'Strawberry', 'Impossible_Word_To_Fit']); | |
foreach ($fruits->getMatrix() as $line) { | |
echo implode(' ', $line) . "\r\n"; | |
} | |
echo 'Used words: ' . implode(', ', $fruits->getUsedWords()) . "\r\n"; | |
echo 'Unused words: ' . implode(', ', $fruits->getUnusedWords()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment