Initial Commit
This commit is contained in:
commit
ddf09fe00c
113 changed files with 187148 additions and 0 deletions
241
app/Game/GameBoardState.php
Normal file
241
app/Game/GameBoardState.php
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
<?php
|
||||
|
||||
namespace App\Game;
|
||||
|
||||
class GameBoardState
|
||||
{
|
||||
/**
|
||||
* Cell states. (unset is default state)
|
||||
*/
|
||||
const STATE_PRESSED = 0;
|
||||
const STATE_WIN = 1;
|
||||
|
||||
/**
|
||||
* Width of the board
|
||||
*/
|
||||
protected int $width;
|
||||
|
||||
/**
|
||||
* Height of the board
|
||||
*/
|
||||
protected int $height;
|
||||
|
||||
/**
|
||||
* State of the cells.
|
||||
*/
|
||||
protected array $state = [];
|
||||
|
||||
/**
|
||||
* If the board is in a winning state or not.
|
||||
*/
|
||||
protected int $winning = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($width, $height)
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of a cell.
|
||||
*/
|
||||
public function set(int $pos, bool $pressed = true) : self
|
||||
{
|
||||
if ($this->hasGameEnded()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($pressed) {
|
||||
$this->state[$pos] = self::STATE_PRESSED;
|
||||
} else {
|
||||
unset($this->state[$pos]);
|
||||
}
|
||||
|
||||
$this->update();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle pressed state of a cell.
|
||||
*/
|
||||
public function toggle(int $pos) : self
|
||||
{
|
||||
return $this->set($pos, !$this->isPressed($pos));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a cell is pressed or not.
|
||||
*/
|
||||
public function isPressed(int $pos) : bool
|
||||
{
|
||||
return isset($this->state[$pos]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a cell is part of a winning row/column.
|
||||
*/
|
||||
public function isWin(int $pos) : bool
|
||||
{
|
||||
return isset($this->state[$pos]) && $this->state[$pos] == self::STATE_WIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sate of the cells.
|
||||
*/
|
||||
public function getState() : array
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the board.
|
||||
*/
|
||||
public function getSize() : int
|
||||
{
|
||||
return $this->width * $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the board.
|
||||
*/
|
||||
public function clear() : self
|
||||
{
|
||||
$this->state = [];
|
||||
$this->winning = 0;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// TODO: Rename
|
||||
public function getNumWinRows() : int
|
||||
{
|
||||
return $this->winning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the board only has winning cards
|
||||
*/
|
||||
public function hasGameEnded() : bool
|
||||
{
|
||||
if (count($this->state) < $this->width * $this->height) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($this->state as $pos) {
|
||||
if ($pos !== self::STATE_WIN) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the board is full and all positions is in a given state.
|
||||
*/
|
||||
public function isFull($state) : bool
|
||||
{
|
||||
// Board not filled, impossible to have all positions set.
|
||||
if (count($this->state) < $this->width * $this->height) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($this->state as $pos) {
|
||||
if ($pos !== $state) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function update()
|
||||
{
|
||||
foreach($this->state as $pos => $_) {
|
||||
$this->state[$pos] = self::STATE_PRESSED;
|
||||
}
|
||||
|
||||
$patterns = $this->checkWinningState();
|
||||
foreach($patterns as $cards) {
|
||||
foreach($cards as $pos) {
|
||||
$this->state[$pos] = self::STATE_WIN;
|
||||
}
|
||||
}
|
||||
$this->winning = count($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the board is in a winning state.
|
||||
*/
|
||||
protected function checkWinningState() : array
|
||||
{
|
||||
$win = [];
|
||||
|
||||
// Rows
|
||||
for($y=0; $y < $this->height; $y++) {
|
||||
$c = $this->checkRow($y);
|
||||
if (count($c)) {
|
||||
$win[] = $c;
|
||||
}
|
||||
}
|
||||
|
||||
// Columns
|
||||
for($x=0; $x < $this->width; $x++) {
|
||||
$c = $this->checkCol($x);
|
||||
if (count($c)) {
|
||||
$win[] = $c;
|
||||
}
|
||||
}
|
||||
|
||||
return $win;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a row is in a winning state (all cells pressed)
|
||||
*/
|
||||
protected function checkRow($y) : array
|
||||
{
|
||||
$cards = [];
|
||||
|
||||
$y = $y * $this->width;
|
||||
for($x = 0; $x < $this->width; $x++) {
|
||||
$pos = $x + $y;
|
||||
if (!$this->isPressed($pos)) {
|
||||
return [];
|
||||
}
|
||||
/*
|
||||
if ($this->state[$pos] == self::STATE_WIN) {
|
||||
continue;
|
||||
} */
|
||||
$cards[] = $pos;
|
||||
}
|
||||
|
||||
return $cards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a column is in a winning state (all cells pressed)
|
||||
*/
|
||||
protected function checkCol($x) : array
|
||||
{
|
||||
$cards = [];
|
||||
|
||||
for($y = 0; $y < $this->height; $y++) {
|
||||
$pos = $x + ($y * $this->width);
|
||||
if (!$this->isPressed($pos)) {
|
||||
return [];
|
||||
}
|
||||
/*
|
||||
if ($this->state[$pos] == self::STATE_WIN) {
|
||||
continue;
|
||||
} */
|
||||
$cards[] = $pos;
|
||||
}
|
||||
|
||||
return $cards;
|
||||
}
|
||||
}
|
||||
Reference in a new issue