ポリミーイズム

PHPを勉強する若輩者(おっさん)。専門用語の意味はわりかし覚えていません。macOS Sierra 10.12.6

ビンゴ判定プログラム

概要

ビンゴ判定って難しくない?難しくなくない?なんて頭をもたげたので書いてみる。

神のような友人は、「ん?簡単やんけ?死にたいんかお前」とおっしゃっておられました。

チェック系は特にやってないので動かしてみる人はその辺り念頭に置いていただければ。

ソース

テストコードとか残してるけどまぁ、それでもまぁ、未来の僕のためやと思いますので許してください。

<?php

require_once './class/Bingo.php';

use \App\Bingo;

// 3 * 3
$openBingos = [
    [0, 0], [0, 1], [0, 2],
    [1, 0], [1, 1],
    [2, 0], [2, 1], [2, 2],
];

// 単体
// $openBingos = [
//     [0,0]
// ];

// 4 * 4
// $openBingos = [
//     [0, 0], [0, 1], [0, 2], [0, 3],
//     [1, 0], [1, 1],
//     [2, 0], [2, 1], [2, 2],
//     [3, 3],
// ];

$line = 3;
// $line = 4;

$bingo = new \App\Bingo($openBingos, $line);
// $bingo->addOpens([1, 2]);
// $bingo->setBingoLineCount();
var_dump($bingo->getBingoCount());
  • class/Bingo.php
<?php
namespace App;

class Bingo
{
    /**
     * ビンゴ縦横マスの長さ
     * 
     * @var int
     */
    private $line;

    /**
     * ビンゴしているライン数
     * 
     * @var int
     */
    private $bingoLineCount = 0;

    /**
     * 現在開いているマスの連想配列
     * 
     * @var array
     */
    private $opens;

    const INDEX_X = 0;
    const INDEX_Y = 1;
    private $matrixCount = 2;  // x, y

    public function __construct(array $opens, int $line)
    {
        $this->opens = $opens;
        $this->line  = $line;

        $this->setBingoLineCount();
    }

    /**
     * ビンゴラインを設定する
     */
    public function setBingoLineCount() : void
    {
        // 縦横のビンゴ数を設定する
        $this->bingoLineCount += $this->simpleLineCount();

        // ななめのビンゴ数を設定する
        $this->bingoLineCount += $this->diagonalLineCount();
    }

    /**
     * ビンゴしている数を返す
     */
    public function getBingoCount() : int
    {
        return $this->bingoLineCount;
    }

    /**
     * 縦横にビンゴしている数を返す
     * 
     * @return int 
     */
    private function simpleLineCount() : int
    {
        $simpleLineCount = 0;

        for($i=0; $i < $this->matrixCount; $i++) {
            // 縦横で開いている要素数を取得する
            $simpleLines = array_count_values(array_column($this->opens, $i));
            
            foreach($simpleLines as $openCount) {
                // 開いている要素数が横幅と同じならビンゴ判定
                $simpleLineCount += $openCount === $this->line ? 1 : 0;
            }
        }
        return $simpleLineCount;
    }

    /**
     * 斜めにビンゴしている数を返す
     * 
     * @return int $diagonalLineCount
     */
    private function diagonalLineCount() : int
    {
        $diagonalLineCount = 0;

        // 斜めビンゴの要素を取得する
        list($rightDownCount, $leftDownCount) = $this->getDiagonalElementCount();

        // ビンゴの場合は加算する
        $diagonalLineCount += $rightDownCount === $this->line ? 1 : 0;
        $diagonalLineCount += $leftDownCount === $this->line ? 1 : 0;

        return $diagonalLineCount;
    }

    /**
     * 斜めのビンゴの要素を返す
     * 
     * @return array $diagonalOpens
     */
    private function getDiagonalElementCount() : array
    {
        $rightDownCount = 0;
        $leftDownCount = 0;

        foreach ($this->opens as $open) {
            foreach (range(0, $this->line - 1) as $position) {
                $rightDownCount += $this->isRightDownLineElement($open, $position) ? 1 : 0;
                $leftDownCount += $this->isLeftDownLineElement($open, $position) ? 1 : 0;
            }
        }

        return [$rightDownCount, $leftDownCount];
    }

    /**
     * 右斜めのビンゴに関係する要素か判定する
     * 3列の場合は、[0, 0], [1, 1], [2, 2]が対象
     * 
     * @param array $open
     * @param int $position
     * @return bool
     */
    private function isRightDownLineElement(array $open, int $position) : bool
    {
        return $open[self::INDEX_X] === $position && $open[self::INDEX_Y] === $position;

    }

    /**
     * 左斜めのビンゴに関係する要素か判定する
     * 3列の場合は、[0, 2], [1, 1], [2, 0]が対象
     * 
     * @param array $open
     * @param int $position
     * @return bool
     */
    private function isLeftDownLineElement(array $open, int $position) : bool
    {
        return $open[self::INDEX_X] === $position && $open[self::INDEX_Y] === $this->line - ($position + 1);
    }

    /**
     * ビンゴを開ける
     * 
     * @param array $addOpens
     */
    public function addOpens(array $addOpens) : void
    {
        $this->opens[] = $addOpens;
    }

    /**
     * ビンゴかどうかの判定
     * 
     * @return bool
     */
    public function hasBingo() : bool
    {
        return (bool)$this->bingoLineCount;
    }
    
}

反省

実力不足でループがすごいことになってる。

最初のデータの形が悪いのかなぁ。開いたマスを表現する連想配列をオブジェクトにしたい。

あと、斜めラインでビンゴしてる数を取得しているメソッドをgeneratorとか使って綺麗にするか、 もしくは早いタイミングでダメなやつは返すようにしてループを少しでも減らしたい。

斜めライン判定するメソッドも場当たり的な書き方ですね。なんですかねこの脳みそ。