篮球"撞墙式配合"统计案例(Java实现)
需求分析
撞墙式配合(Give and Go / 传切配合) 是篮球进攻中的经典配合:

- 球员A传球给球员B
- 球员A立即切入篮下
- 球员B回传给A完成进攻
统计目标:从传球序列中识别出"撞墙式配合"次数。
数据模型设计
/**
* 传球事件
*/
public class PassEvent {
private String fromPlayer; // 传球人
private String toPlayer; // 接球人
private long timestamp; // 毫秒时间戳
private String actionType; // PASS(传球) / CUT(切入) / SHOT(投篮)
public PassEvent(String fromPlayer, String toPlayer, long timestamp, String actionType) {
this.fromPlayer = fromPlayer;
this.toPlayer = toPlayer;
this.timestamp = timestamp;
this.actionType = actionType;
}
// getter
public String getFromPlayer() { return fromPlayer; }
public String getToPlayer() { return toPlayer; }
public long getTimestamp() { return timestamp; }
public String getActionType() { return actionType; }
@Override
public String toString() {
return fromPlayer + " -> " + toPlayer + " [" + actionType + "] @" + timestamp;
}
}
核心统计逻辑
判定规则:连续两次传球满足以下条件即算一次撞墙配合:
- 第1次:A → B (传球)
- 第2次:B → A (回传),且时间间隔在 阈值 内(如3秒)
import java.util.List;
public class GiveAndGoCounter {
/** 回传时间阈值:3秒内视为同一次配合 */
private static final long TIME_WINDOW_MS = 3000L;
/**
* 统计撞墙式配合次数
*/
public static int count(List<PassEvent> events) {
if (events == null || events.size() < 2) return 0;
int count = 0;
for (int i = 0; i < events.size() - 1; i++) {
PassEvent first = events.get(i);
PassEvent second = events.get(i + 1);
// 第一次必须是传球
if (!"PASS".equals(first.getActionType())) continue;
// A → B
String a = first.getFromPlayer();
String b = first.getToPlayer();
// B → A 回传
boolean isReturn = b.equals(second.getFromPlayer())
&& a.equals(second.getToPlayer())
&& "PASS".equals(second.getActionType());
// 时间窗口内
boolean inWindow = (second.getTimestamp() - first.getTimestamp()) <= TIME_WINDOW_MS;
if (isReturn && inWindow) {
count++;
i++; // 跳过已配对的两条事件,防止重复统计
}
}
return count;
}
}
测试案例
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<PassEvent> events = Arrays.asList(
new PassEvent("A", "B", 1000, "PASS"), // A→B
new PassEvent("B", "A", 2500, "PASS"), // B→A ✅ 第1次撞墙
new PassEvent("A", "C", 4000, "PASS"),
new PassEvent("C", "A", 5000, "PASS"), // C→A ✅ 第2次撞墙
new PassEvent("A", "D", 6000, "PASS"),
new PassEvent("D", "E", 8500, "PASS"), // 时间超3秒+非回传 ❌
new PassEvent("E", "D", 9000, "PASS"), // E→D ✅ 第3次撞墙
new PassEvent("D", "A", 11000, "PASS")
);
int total = GiveAndGoCounter.count(events);
System.out.println("撞墙式配合完成次数:" + total);
}
}
输出:
撞墙式配合完成次数:3
进阶扩展
篮球位置过滤(只在特定区域发生)
增加坐标字段,判断传球是否发生在 三分线外 → 篮下 等区域。
结合追踪数据(SportVU / Hawk-Eye)
真实场景下需要:
- 球员坐标轨迹:识别 A 传球后是否真的 向篮下切入(速度突变+方向朝向篮筐)
- 防守人距离:判断是否为有效进攻配合
使用状态机(更严谨)
enum State { IDLE, WAIT_RETURN }
IDLE:记录第一次传球的 (A, B, t)WAIT_RETURN:检查下一次事件是否为 B→A 且在时间窗内- 匹配则 count++,状态重置
处理复杂情况
- 多次传球:A→B→C→A 算不算?(一般不算严格撞墙)
- 投篮结束:B→A 后 A 出手,可作为一次"有效撞墙配合"加权
- 时间窗自适应:根据节奏(Pace)动态调整阈值
完整类图
PassEvent ─────► GiveAndGoCounter
▲ │
│ │ count()
│ ▼
数据源(CSV/DB) List<PassEvent>
| 要素 | 说明 |
|---|---|
| 核心特征 | A→B,B→A 双向传球 |
| 关键约束 | 时间窗口、方向反转 |
| 算法复杂度 | O(n) 单次遍历 |
| 扩展方向 | 坐标轨迹、区域限制、投篮联动 |
如果需要 读取CSV文件、对接数据库 或 可视化输出 的完整Demo,可以告诉我具体数据格式,我帮你扩展。