Created
April 12, 2017 13:36
-
-
Save srea/918655d0ebc9f706e83e4d8241f498bb to your computer and use it in GitHub Desktop.
パズドラ風PHP
This file contains 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 | |
// 一列ごとにどこからどこに動かせが揃うかを調査 | |
// 一番いいところを見つけたら次はそこからどこに | |
// 動かせば一番そろうか調査 | |
// ループして一番いい条件を出す。 | |
// 2012年4月6日 | |
// ・マップ上で消せそうな物を探す。 | |
// ・どれを探すか優先順位を決定する | |
// (青優先・赤優先・回復優先等) | |
// ・優先順位が決まったらそのコンボが揃うように動かす | |
// ・ | |
// tmp | |
// 0マッチしない | |
// 1縦にマッチ | |
// 2横にマッチ | |
// 3縦横にマッチ | |
$data = array(); | |
$data[] = array( | |
6, | |
1, | |
2, | |
3, | |
4, | |
5 | |
); | |
$data[] = array( | |
1, | |
2, | |
3, | |
4, | |
5, | |
6 | |
); | |
$data[] = array( | |
1, | |
2, | |
3, | |
4, | |
5, | |
6 | |
); | |
$data[] = array( | |
1, | |
2, | |
3, | |
4, | |
5, | |
6 | |
); | |
$data[] = array( | |
1, | |
2, | |
3, | |
4, | |
5, | |
6 | |
); | |
//P::set($data); | |
P::set(); | |
P::get(); | |
class PazzleException extends Exception | |
{ | |
} | |
class Escape | |
{ | |
} | |
class Candy | |
{ | |
} | |
class Board | |
{ | |
} | |
// パズドラ解析 | |
class P | |
{ | |
// マップ設定 | |
const X = 6; // 横の数 | |
const Y = 5; // 縦の数 | |
const V = 1; // 縦のマッチ | |
const H = 2; // 横のマッチ | |
const M = 3; // 両方マッチ | |
// ダンプ時の色設定 | |
const COL_BASE = "\033[0;%dm"; // 白 | |
const COL_0 = "0"; // 白 | |
const COL_1 = "31"; // 赤 | |
const COL_2 = "34"; // 青 | |
const COL_3 = "32"; // 緑 | |
const COL_4 = "33"; // 黄 | |
const COL_5 = "35"; // 紫 | |
const COL_6 = "36"; // 回復 | |
const COL_X = "45"; // 指の位置 | |
const ITEM_MIN = 1; // アイテム最小値 | |
const ITEM_MAX = 6; // アイテム最大値 | |
const MOVE_MAX = 200; // 最大移動回数 | |
static $data = array(); // マップデータ | |
static $tmp = array(); // 処理データ | |
static $combo = array(); // コンボデータ | |
static $finger = array(); // 現在の指の位置 | |
static $comboCount = 0; // 現在の指の位置 | |
static $nextMove = 0; // 現在の指の位置 | |
static $cnt = 0; //つかってない | |
static $movePattern = // 指の移動パターン | |
array(1 => array(-1, 0), // 上 | |
2 => array(1, 0), // 下 | |
3 => array(0, 1), // 右 | |
4 => array(0, -1), // 左 | |
5 => array(-1, 1), // 左上 | |
6 => array(1, 1), // 左下 | |
7 => array(-1, -1), // 右上 | |
8 => array(1, -1) // 右下 | |
); | |
static $checkPattern = // コンボ判定パターン | |
array(1 => array(-1, 0), // 上 | |
2 => array(1, 0), // 下 | |
3 => array(0, 1), // 右 | |
4 => array(0, -1) // 左 | |
); | |
// マップデータをチェック | |
// 縦横の幅、アイテム数値をチェックします。 | |
static private function check() | |
{ | |
// 縦幅 | |
if (count(self::$data) != self::Y) | |
return false; | |
// 横幅 | |
for ($i = 0; $i < self::Y; $i++) { | |
if (count(self::$data[$i]) != self::X) | |
return false; | |
for ($j = 0; $j < self::X; $j++) { | |
if (!(self::$data[$i][$j] >= self::ITEM_MIN && self::$data[$i][$j] <= self::ITEM_MAX)) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
// ランダムマップを生成 | |
static private function createMap() | |
{ | |
self::$data = array_fill(0, self::Y, array_fill(0, self::X, 0)); | |
self::$tmp = self::$data; | |
for ($i = 0; $i < self::Y; $i++) { | |
for ($j = 0; $j < self::X; $j++) { | |
self::$data[$i][$j] = rand(self::ITEM_MIN, self::ITEM_MAX); | |
} | |
} | |
} | |
// マップデータをセット | |
static public function set($data = array()) | |
{ | |
// マップ生成 | |
if (empty($data)) { | |
self::createMap(); | |
} else { | |
self::$data = $data; | |
} | |
if (!self::check()) { | |
die("Map erorr"); | |
} | |
self::$cnt = count($data); | |
self::$finger = array( | |
'x' => 0, | |
'y' => 0 | |
); | |
} | |
// 解析して結果取得 | |
static public function get() | |
{ | |
// データチェック | |
self::check(); | |
// 解析前 | |
self::analyze(); | |
// 解析後 | |
self::pazzle(); | |
} | |
// 現在のマップを解析 | |
static private function analyze() | |
{ | |
print("\033[2J"); | |
self::$combo = array(); // コンボ初期化 | |
for ($i = 0; $i < self::Y; $i++) { | |
for ($j = 0; $j < self::X; $j++) { | |
// コンボ成立判定 | |
self::$tmp[$i][$j] = self::vcheck($i, $j) ? self::hcheck($i, $j) == self::H ? self::M : self::V : self::hcheck($i, $j); | |
// コンボ箇所に色をつける とりあえず | |
if (self::$tmp[$i][$j] != 0) { | |
self::$tmp[$i][$j] = self::$data[$i][$j]; | |
} | |
// コンボデータを登録 | |
if (self::$tmp[$i][$j] != 0) { | |
// 一度に消せる時の配列の持ち方など考える | |
//self::$comboCount++; | |
self::$combo[self::$data[$i][$j]][] = array( | |
$i, | |
$j | |
); | |
} | |
} | |
} | |
//self::combo(); | |
//print("パズドラ\n"); | |
self::dump(self::$tmp); | |
self::dump(self::$combo); | |
// var_dump(self::$combo); | |
self::dump(self::$data); | |
} | |
// 何のために用意したのか忘れた/(^o^)\ | |
static private function combo() | |
{ | |
$combo = 0; | |
// 色事に解析 | |
foreach (self::$combo as $color => $lines) { | |
// 一コマずつ解析 | |
foreach ($lines as $line) { | |
$combo += self::checkAAAA($line[0], $line[1]); | |
} | |
} | |
echo $combo; | |
} | |
// あるマスの周りに同じ色があるかチェック | |
static private function checkAAAA($_y, $_x) | |
{ | |
$prevMove_y = 0; | |
$prevMove_x = 0; | |
$hit = 0; | |
$combo = 0; | |
// 周りを調査 | |
foreach (self::$checkPattern as $key => $move) { | |
// 同じ色の周囲を検索 | |
if (self::checkFinger($_y + $move[0], $_x + $move[1]) && self::$tmp[$_y][$_x] == self::$tmp[$_y + $move[0]][$_x + $move[1]] && $_y + $move[0] != $prevMove_y && $_x + $move[1] != $prevMove_x) { | |
// | |
self::$tmp[$_y][$_x] = 0; | |
$hit++; | |
$_y += $move[0]; | |
$_x += $move[1]; | |
$prevMove_y = $_y; | |
$prevMove_x = $_x; | |
if ($hit == 3) | |
$combo++; | |
continue; | |
} | |
echo "aa"; | |
} | |
return $combo; | |
} | |
// 再帰的に最適回を探す | |
static function pazzle() | |
{ | |
// 指の位置をセット | |
if (self::$finger['x'] == 0 && self::$finger['y'] == 0) { | |
self::setFinger(0, 0); | |
} | |
while (true) { | |
$move = fgets(STDIN, 10); | |
$move = rtrim($move, "\n"); | |
if (!empty($move)) { | |
break; | |
} | |
} | |
// 動かしてみる | |
if ($move == 'k' || $move == '8') | |
self::moveUp(); | |
if ($move == 'j' || $move == '2') | |
self::moveDown(); | |
if ($move == 'l' || $move == '6') | |
self::moveRight(); | |
if ($move == 'h' || $move == '4') | |
self::moveLeft(); | |
if ($move == '9') | |
self::moveRightUp(); | |
if ($move == '3') | |
self::moveRightDown(); | |
if ($move == '7') | |
self::moveLeftUp(); | |
if ($move == '1') | |
self::moveLeftDown(); | |
if ($move == 'p') | |
self::autoPlay(); | |
// 結果を出力 | |
self::analyze(); | |
self::combo(); | |
self::pazzle(); | |
} | |
// 今のところランダムで解いてる風 | |
static private function autoPlay() | |
{ | |
$cnt = 0; | |
while (true) { | |
usleep(50000); | |
self::moveMap(); | |
if (self::$nextMove == 0) { | |
// 身動きが取れない | |
continue; | |
} | |
// 結果を出力 | |
self::analyze(); | |
self::combo(); | |
$cnt++; | |
if ($cnt == self::MOVE_MAX) { | |
sleep(2); | |
break; | |
} | |
} | |
self::set(); | |
self::autoPlay(); | |
} | |
// 様々なアルゴリズムを使って次に動く場所を決める | |
// 一番のメイン部分!!!! | |
static private function moveMap() | |
{ | |
$move = self::algorithm_01(); | |
self::$nextMove = $move; | |
// 動かしてみる | |
switch (self::$nextMove) { | |
case 1: | |
self::moveUp(); | |
break; | |
case 2: | |
self::moveDown(); | |
break; | |
case 3: | |
self::moveRight(); | |
break; | |
case 4: | |
self::moveLeft(); | |
break; | |
case 5: | |
self::moveRightUp(); | |
break; | |
case 6: | |
self::moveRightDown(); | |
break; | |
case 7: | |
self::moveLeftUp(); | |
break; | |
case 8: | |
self::moveLeftDown(); | |
break; | |
} | |
} | |
// コンボ確定部分には移動しないアルゴリズム | |
// 説明:マップ上の動けるところにランダムで動いて | |
// コンボが確定した部分は通らない | |
static private function algorithm_01() | |
{ | |
// コンボマップを取ってきて動ける場所を決める | |
$num = 0; | |
$ok = array(); | |
$x = self::$finger['x']; | |
$y = self::$finger['y']; | |
// 指の動ける範囲を探す | |
foreach (self::$movePattern as $key => $move) { | |
$_y = $y + $move[0]; | |
$_x = $x + $move[1]; | |
if (self::checkFinger($_y, $_x) && !self::$tmp[$_y][$_x]) { | |
$ok[] = $key; | |
} | |
} | |
if (count($ok) > 1) { | |
shuffle($ok); | |
$num = mt_rand(0, count($ok) - 1); | |
} | |
return isset($ok[$num]) ? $ok[$num] : 0; | |
} | |
// マップ上で指から一番近いコンボを作っていく | |
// 基本アルゴリズム1を厳守 | |
static private function algorithm_02() | |
{ | |
} | |
// 創り上げたコンボを壊してでも最大最短コンボを導き出せる | |
static private function algorithm_03() | |
{ | |
} | |
// ある色だけを重視してコンボを作る | |
static private function algorithm_04() | |
{ | |
} | |
// ある色だけを重視してコンボを作る | |
static private function algorithm_05() | |
{ | |
} | |
// | |
// | |
static private function play() | |
{ | |
// コンボ順に消す | |
self::comboStart(); | |
// 消えた部分を落下させる | |
// 落下した時に不足分は今回は付けない | |
self::comboFinish(); | |
} | |
static private function comboStart() | |
{ | |
} | |
static private function comboFinish() | |
{ | |
} | |
// 有効な位置か判定 | |
static private function validMap($i, $j) | |
{ | |
return isset(self::$data[$i][$j]); | |
} | |
// 指の位置をチェック | |
// 必ず1つしか移動できない。スキップは出来ない | |
static private function checkFinger($i, $j) | |
{ | |
// 横の範囲をチェック | |
if (self::$finger['x'] <= $j) { | |
$x = ($j - self::$finger['x']) <= 1 ? true : false; | |
} else { | |
$x = (self::$finger['x'] - $j) <= 1 ? true : false; | |
} | |
// 縦の範囲をチェック | |
if (self::$finger['y'] <= $i) { | |
$y = ($i - self::$finger['y']) <= 1 ? true : false; | |
} else { | |
$y = (self::$finger['y'] - $i) <= 1 ? true : false; | |
} | |
// 移動範囲のチェックとマップ内に存在するか | |
return ($x && $y && self::validMap($i, $j)); | |
} | |
// 指の位置の初期設定(moveFingerのエイリアス) | |
static private function setFinger($i, $j) | |
{ | |
self::moveFinger($i, $j); | |
} | |
// 指の位置を移動 | |
static private function moveFinger($i, $j) | |
{ | |
self::$finger['x'] = $j; | |
self::$finger['y'] = $i; | |
} | |
// 上に移動 | |
static private function moveUp() | |
{ | |
if (self::moveChange(1)) { | |
//echo $i.",".$j."から".($i-1).",".$j."上に移動\n"; | |
} | |
} | |
// 下に移動 | |
static private function moveDown() | |
{ | |
if (self::moveChange(2)) { | |
} | |
} | |
// 右に移動 | |
// | |
// | |
static private function moveRight() | |
{ | |
if (self::moveChange(3)) { | |
} | |
} | |
// 左に移動 | |
static private function moveLeft() | |
{ | |
if (self::moveChange(4)) { | |
} | |
} | |
// 左上に移動 | |
static private function moveLeftUp() | |
{ | |
if (self::moveChange(7)) { | |
} | |
} | |
// 右上に移動 | |
static private function moveRightUp() | |
{ | |
if (self::moveChange(5)) { | |
} | |
} | |
// 左下に移動 | |
static private function moveLeftDown() | |
{ | |
if (self::moveChange(8)) { | |
} | |
} | |
// 右下に移動 | |
static private function moveRightDown() | |
{ | |
if (self::moveChange(6)) { | |
} | |
} | |
// 値を入れ替える | |
static private function moveChange($move) | |
{ | |
// 現在値を取得 | |
$i = self::$finger['y']; | |
$j = self::$finger['x']; | |
$_i = $i + self::$movePattern[$move][0]; | |
$_j = $j + self::$movePattern[$move][1]; | |
// 位置の変更が可能かチェック | |
if (!self::checkFinger($_i, $_j)) { | |
return false; | |
} | |
// 入れ替え | |
$tmp = self::$data[$i][$j]; | |
self::$data[$i][$j] = self::$data[$_i][$_j]; | |
self::$data[$_i][$_j] = $tmp; | |
// 現在値の更新 | |
self::moveFinger($_i, $_j); | |
return true; | |
} | |
// 縦ラインのチェック | |
static private function vcheck($i, $j) | |
{ | |
$check = false; | |
if ($i >= 0 && $i < self::Y - 2) { | |
$check = self::$data[$i][$j] === self::$data[$i + 1][$j] && self::$data[$i][$j] === self::$data[$i + 2][$j] ? true : false; | |
} | |
if ($i >= 1 && $i < self::Y - 1) { | |
if (!$check) | |
$check = self::$data[$i][$j] === self::$data[$i + 1][$j] && self::$data[$i][$j] === self::$data[$i - 1][$j] ? true : false; | |
} | |
if ($i >= 0 && $i >= 2) { | |
if (!$check) | |
$check = self::$data[$i][$j] === self::$data[$i - 1][$j] && self::$data[$i][$j] === self::$data[$i - 2][$j] ? true : false; | |
} | |
return $check; | |
} | |
// 横ラインのチェック | |
static private function hcheck($i, $j) | |
{ | |
$check = false; | |
if ($j >= 0 && $j < self::X - 2) { | |
$check = self::$data[$i][$j] === self::$data[$i][$j + 1] && self::$data[$i][$j] === self::$data[$i][$j + 2] ? 2 : 0; | |
} | |
if ($j >= 1 && $j < self::X - 1) { | |
if (!$check) | |
$check = self::$data[$i][$j] === self::$data[$i][$j + 1] && self::$data[$i][$j] === self::$data[$i][$j - 1] ? 2 : 0; | |
} | |
if ($j >= 0 && $j >= 2) { | |
if (!$check) | |
$check = self::$data[$i][$j] === self::$data[$i][$j - 1] && self::$data[$i][$j] === self::$data[$i][$j - 2] ? 2 : 0; | |
} | |
return $check; | |
} | |
// 番号と色 | |
static private function getColor($i = 0, $num = false) | |
{ | |
switch ($i) { | |
case 1: | |
$code = self::COL_1; | |
break; | |
case 2: | |
$code = self::COL_2; | |
break; | |
case 3: | |
$code = self::COL_3; | |
break; | |
case 4: | |
$code = self::COL_4; | |
break; | |
case 5: | |
$code = self::COL_5; | |
break; | |
case 6: | |
$code = self::COL_6; | |
break; | |
default: | |
$code = self::COL_0; | |
} | |
return !$num ? sprintf(self::COL_BASE, $code) : $code; | |
} | |
// とりあえずダンプの糞コード | |
static private function dump($data) | |
{ | |
if ($data === self::$data) { | |
for ($i = 0; $i < self::Y; $i++) { | |
for ($j = 0; $j < self::X; $j++) { | |
$mark = "●"; // $data[$i][$j] | |
if ($i == self::$finger['y'] && $j == self::$finger['x']) { | |
echo "\033[" . self::getColor($data[$i][$j], 1) . ";47;1m"; | |
echo $mark . "\033[m"; | |
} else { | |
echo self::getColor($data[$i][$j]); | |
echo $mark . self::getColor(0, 0); | |
} | |
} | |
echo "\n"; | |
} | |
} elseif ($data === self::$tmp) { | |
echo "\033[0;31mPazzle\033[0;0m\n"; | |
for ($i = 0; $i < self::Y; $i++) { | |
for ($j = 0; $j < self::X; $j++) { | |
$mark = "●"; // $data[$i][$j] | |
if ($i == self::$finger['y'] && $j == self::$finger['x']) { | |
echo "\033[37;47;1m"; | |
echo $mark . "\033[m"; | |
//echo self::getColor(); | |
//echo $mark.self::getColor(0, 0); | |
} else { | |
echo self::getColor($data[$i][$j]); | |
echo $mark . self::getColor(0, 0); | |
} | |
} | |
echo "\n"; | |
} | |
} else { | |
echo count($data), "コンボ\n"; | |
//var_dump($data); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment