本文目录导读:

在PHP项目中入手“半全场”玩法(通常指足球彩票的半全场胜平负),需要从业务逻辑、数据结构、算法实现、接口对接四个维度来考虑,下面是一个完整的入手思路:
理解半全场玩法规则
半全场胜平负(Half-Time/Full-Time,简称HT/FT)是指预测一场比赛上半场结果和全场结果的组合,共9种选项:
| 选项 | 含义 |
|---|---|
| 胜胜 | 上半场主胜,全场主胜 |
| 胜平 | 上半场主胜,全场平局 |
| 胜负 | 上半场主胜,全场主负 |
| 平胜 | 上半场平局,全场主胜 |
| 平平 | 上半场平局,全场平局 |
| 平负 | 上半场平局,全场主负 |
| 负胜 | 上半场主负,全场主胜 |
| 负平 | 上半场主负,全场平局 |
| 负负 | 上半场主负,全场主负 |
核心难点:需要同时获取或计算半场比分和全场比分,且两者要能正确映射到9种组合。
数据结构设计(MySQL示例)
-- 比赛表
CREATE TABLE matches (
id INT PRIMARY KEY AUTO_INCREMENT,
match_code VARCHAR(32) UNIQUE, -- 赛事编号
home_team VARCHAR(64),
away_team VARCHAR(64),
match_time DATETIME,
status TINYINT DEFAULT 0, -- 0未开始 1上半场 2中场 3下半场 4完场
half_home_score TINYINT DEFAULT NULL,
half_away_score TINYINT DEFAULT NULL,
full_home_score TINYINT DEFAULT NULL,
full_away_score TINYINT DEFAULT NULL
);
-- 半全场投注表
CREATE TABLE htft_bets (
id INT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(32) UNIQUE,
match_id INT,
user_id INT,
play_type TINYINT DEFAULT 1, -- 1=半全场
selection VARCHAR(4), -- 'HH','HD','HA','DH','DD','DA','AH','AD','AA'
odds DECIMAL(8,2),
amount DECIMAL(10,2),
status TINYINT DEFAULT 0, -- 0待结算 1中奖 2未中 3已退款
create_time DATETIME,
INDEX idx_match(match_id)
);
选项编码建议:用 H/D/A(Home/Draw/Away)两字符表示,如 HH、HD、HA……便于程序判定和存储。
核心算法实现
比分 → 结果映射
class HtftCalculator
{
/**
* 根据比分得出 H/D/A 结果
*/
public static function getResult(int $homeScore, int $awayScore): string
{
if ($homeScore > $awayScore) return 'H';
if ($homeScore === $awayScore) return 'D';
return 'A';
}
/**
* 计算半全场结果,如 'HH'、'DA'
*/
public static function calcHtft(
int $halfHome, int $halfAway,
int $fullHome, int $fullAway
): string {
$halfResult = self::getResult($halfHome, $halfAway);
$fullResult = self::getResult($fullHome, $fullAway);
return $halfResult . $fullResult;
}
/**
* 判定是否中奖
*/
public static function isWin(string $selection, string $actual): bool
{
return strtoupper($selection) === $actual;
}
}
结算流程
// 比赛完场后触发结算
$actual = HtftCalculator::calcHtft(
$match['half_home_score'], $match['half_away_score'],
$match['full_home_score'], $match['full_away_score']
);
// 批量更新该场比赛的投注状态
foreach ($bets as $bet) {
$status = HtftCalculator::isWin($bet['selection'], $actual) ? 1 : 2;
// 更新 + 派奖
}
关键业务点
数据来源
- 第三方赛事API(如纳米数据、雷速、Sportradar):需确认API是否提供半场比分字段,通常有
home_score_half/away_score_half。 - 爬虫:注意合规性,且需处理半场比分延迟问题。
- 人工录入后台:作为兜底方案。
结算时机与状态机
未开始 → 上半场 → 中场休息 → 下半场 → 完场 → 待结算 → 已结算
注意:必须等到完场且比分确认(防逆转/改判)后才结算,建议设置延迟结算(如完场后10-30分钟)。
赔率管理
- 9个选项各自独立赔率,需支持动态调整(受注量、伤停、天气等)。
- 建议建
odds_htft表按match_id + selection存储,保留历史版本。
风控
- 单场限额:按选项设置最大投注额。
- 组合投注限制:如禁止在全场"胜"上重注"胜胜"套利。
- 异常投注监控:某选项赔率骤降时预警。
- 对冲检测:同一用户在一场比赛多选项大额投注。
混合过关(串关)
半全场常参与串关,需与让球、大小球等其他玩法统一赔率计算框架:
总赔率 = Π(各场选中项赔率)
注意选项互斥校验(同一场不能同时选多个半全场选项)。
PHP工程化建议
目录结构
app/
├── Controller/
│ └── HtftController.php
├── Service/
│ ├── HtftService.php # 业务逻辑
│ ├── SettlementService.php # 结算
│ └── OddsService.php # 赔率
├── Model/
│ ├── MatchModel.php
│ └── HtftBetModel.php
├── Lib/
│ └── HtftCalculator.php # 纯计算类,可单测
└── Console/
└── SettleCommand.php # 定时结算
定时任务(crontab)
# 每5分钟扫描完场比赛进行结算 */5 * * * * php think htft:settle
队列化结算
用 Redis + 队列(如 think-queue / Laravel Queue)异步处理结算,避免大批量更新阻塞。
单元测试重点
- 各种比分组合 → 9种结果映射
- 边界:0:0、大比分、半场平全场不平
- 中奖判定、退款逻辑
入手路线图(建议顺序)
- 第1步:写
HtftCalculator纯计算类 + 单元测试(1天) - 第2步:设计表结构,搭比赛数据录入/对接(2-3天)
- 第3步:实现投注下单、赔率展示(3-5天)
- 第4步:实现结算 + 派奖 + 定时任务(3-5天)
- 第5步:接入风控、限额、串关(持续迭代)
常见坑
| 坑点 | 应对 |
|---|---|
| 半场比分延迟/错误 | 结算前二次校验,完后延迟结算 |
| 比赛腰斩/改判 | 保留退款流程,状态置为"待定" |
| 串关中半全场选项冲突 | 下单前做互斥校验 |
| 赔率并发更新 | 用乐观锁或 Redis 原子操作 |
| 结算重复派奖 | 结算操作幂等(加唯一约束 + 状态机) |
如果你能说明具体场景(自建竞猜平台 / 对接体彩 / 内部模拟系统)和现有PHP框架(ThinkPHP / Laravel / 原生),我可以给出更贴合的代码骨架和表结构细化。