跳到主要内容

舞台选座位

舞台选座位-Gist

问题描述

某公司要在体育馆办一场晚会,体育馆由ABCD四个区域组成,区域之间由过道分割,每个区域第一排50个座位,隔排递增2个座位,最后一排为100个座位。

/**
* 场景:
* 某公司要在体育馆办一场晚会,体育馆由ABCD四个区域组成,
* 区域之间由过道分割,每个区域第一排50个座位,隔排递增2个座位,
* 最后一排为100个座位。
*
* 请您帮忙设计一个系统,解决以下需求点:
* 1. 用户一次性可购买1~5张票
* 2. 系统随机为用户分配座位
*/

/**
* 舞台选座位
*/
class ChoiceSeat
{
/**
* @var int 第一排多少个座位,默认:50
*/
private $baseSeatNumber = 50;
/**
* @var int 最后一排多少个座位,默认:100
*/
private $lastSeatNumber = 100;
/**
* @var array 总递增座位编号集合
*/
private $totalSeats = [];

/**
* @var string 总座位编号缓存文件
*/
private static $cacheFilename = 'total-seats.bin';

/**
* ChoiceSeat constructor.
*/
public function __construct()
{
$cache = $this->getTotalSeatsByCache();
if (empty($cache)) {
/**
* 求出总共需要多少排
* x=需要多少排,从0开始,隔排+2个座位。
* 设方程式:50 + (x * 2) = 100 (一元一次方程)
* 解:
* 2x = 100 - 50
* x = 50/2
*/
$baseSeatNumber = $this->getBaseSeatNumber();
$lastSeatNumber = $this->getLastSeatNumber();
if (empty($baseSeatNumber) || empty($lastSeatNumber)) {
throw new Exception('第一排和最后一排座位数不能为空');
}
// 还需要 $x 排,总排数 $x + 1(第一排)
$x = ($lastSeatNumber - $baseSeatNumber) / 2;

$areas = ['A', 'B', 'C', 'D'];
foreach ($areas as $areaCode) {
// 区域的总递增座位编号
$totalCounter = 1;
for ($row = 0; $row < $x + 1; $row++) {
// 每排的座位编号范围(隔排+2)
$endSeatNumber = $baseSeatNumber + ($row * 2);
for ($j = 1; $j <= $endSeatNumber; $j++) {
// 总体座位编号:区域编号-排的编号-区域的总递增座位数
$uuid = sprintf("%s%'.04d%'.06d", $areaCode, ($row + 1), $totalCounter);
// 商品名称
$name = sprintf("%s区%s排%s号", $areaCode, ($row + 1), $j);

$this->addSeat([
'uuid' => $uuid,
'name' => $name,
]);

$totalCounter ++;
}
}
}
// 缓存到文件
$totalSeats = $this->getTotalSeats();
if (!empty($totalSeats)) {
$cacheValue = serialize($totalSeats);
} else {
$cacheValue = serialize([]);
}
$handle = fopen(self::$cacheFilename, 'w');
flock($handle, LOCK_EX);
fwrite($handle, $cacheValue);
flock($handle, LOCK_UN);
fclose($handle);
} else {
$this->setTotalSeats($cache);
}
}

/**
* @return int
*/
public function getBaseSeatNumber()
{
return $this->baseSeatNumber;
}

/**
* @param int $baseSeatNumber
*
* @return $this
*/
public function setBaseSeatNumber($baseSeatNumber)
{
$this->baseSeatNumber = $baseSeatNumber;
return $this;
}

/**
* @return int
*/
public function getLastSeatNumber()
{
return $this->lastSeatNumber;
}

/**
* @param int $lastSeatNumber
*
* @return $this
*/
public function setLastSeatNumber($lastSeatNumber)
{
$this->lastSeatNumber = $lastSeatNumber;
return $this;
}

/**
* @return array
*/
public function getTotalSeats()
{
return $this->totalSeats;
}

/**
* @param array $totalSeats
*/
public function setTotalSeats($totalSeats)
{
$this->totalSeats = $totalSeats;
}

/**
* @param array $uuid
*/
public function addSeat($uuid)
{
$this->totalSeats[] = $uuid;
}

/**
* 获取连续的座位
*
* @param int $needNumber 需要多少个座位
*
* @return array
*/
public function getSerialSeat($needNumber = 0)
{
// TODO 未实现
return [];
}

/**
* 获取系统随机分配的座位
*
* @param int $needNumber 需要多少个座位
*
* @return array
*/
public function getRandomSeat($needNumber = 0)
{
$totalSeats = $this->getTotalSeats();
if (empty($totalSeats)) {
return [];
}

// 随机取出几个元素的键
$return = [];
$randomKeys = array_rand($totalSeats, $needNumber);
if (!empty($randomKeys)) {
foreach ($randomKeys as $key) {
if (isset($totalSeats[$key])) {
$return[] = $totalSeats[$key];
}
}
}

return $return;
}

/**
* 获取总座位编号缓存
*
* @return array
*/
private function getTotalSeatsByCache()
{
$cachaData = [];

$handle = @fopen(self::$cacheFilename, 'r');
if ($handle !== false) {
flock($handle, LOCK_EX);
$content = '';
while (!feof($handle)) {
$buffer = fgets($handle, 4096);
$content .= $buffer;
}
flock($handle, LOCK_UN);
fclose($handle);

if (!empty($content)) {
$array = unserialize($content);
if ($array !== false) {
$cachaData = $array;
}
}
}

return $cachaData;
}
}

$service = new ChoiceSeat();
//// 随机选择5个座位
//$output = $service->getRandomSeat(5);
//foreach ($output as $item) {
// echo sprintf('编号:%s 商品:%s', $item['uuid'], $item['name']) . PHP_EOL;
//}
//die;


// !!! 探索增加筛选条件:比如:同一区域、同一排、座位号是否需要连续


//// 总编号集合
//$output = $service->getTotalSeats();
//foreach ($output as $item) {
// echo sprintf('编号:%s 商品:%s', $item['uuid'], $item['name']) . PHP_EOL;
//}
//die;