篮球"撞墙式配合"(Give and Go)统计案例
"撞墙式配合"(Give and Go,也叫传切配合)是篮球中经典的二人配合战术:A 传球给 B,A 快速空切篮下,B 再回传给 A 完成进攻。

下面用 Java 演示如何统计这种配合完成的次数。
需求分析
统计"撞墙式配合完成次数"需要识别:
- 传球事件:球员 A → 球员 B
- 接球后快速回传:B → A(短时间内,A 已完成空切)
- 最终完成:A 接球后投篮命中/得分
即:A传B → B回传A → A得分 才算一次成功的撞墙式配合。
数据模型设计
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 篮球比赛事件
*/
public class GameEvent {
public enum Type {
PASS, // 传球
SCORE, // 得分
MISS // 投篮不中
}
private final String fromPlayer; // 传球者(对传球事件)
private final String toPlayer; // 接球者(对传球事件)/ 得分者
private final Type type;
private final LocalDateTime time;
public GameEvent(String fromPlayer, String toPlayer, Type type, LocalDateTime time) {
this.fromPlayer = fromPlayer;
this.toPlayer = toPlayer;
this.type = type;
this.time = time;
}
public String getFromPlayer() { return fromPlayer; }
public String getToPlayer() { return toPlayer; }
public Type getType() { return type; }
public LocalDateTime getTime(){ return time; }
// getter/setter 略
}
核心统计逻辑
import java.time.Duration;
import java.util.List;
public class GiveAndGoAnalyzer {
/** 回传最大时间窗口(秒),超过则不算撞墙式配合 */
private static final long MAX_INTERVAL_SECONDS = 3;
/**
* 统计撞墙式配合完成次数
* 识别模式:A --PASS--> B --PASS--> A --SCORE--> 得分
*/
public static int countGiveAndGo(List<GameEvent> events) {
int count = 0;
for (int i = 0; i + 2 < events.size(); i++) {
GameEvent e1 = events.get(i); // 第一次传球 A -> B
GameEvent e2 = events.get(i + 1); // 回传 B -> A
GameEvent e3 = events.get(i + 2); // 得分
if (!isGiveAndGo(e1, e2, e3)) continue;
count++;
i += 2; // 跳过已匹配的三个事件,避免重复统计
}
return count;
}
/** 判断三个连续事件是否构成一次撞墙式配合 */
private static boolean isGiveAndGo(GameEvent e1, GameEvent e2, GameEvent e3) {
// 1. 第一次传球
if (e1.getType() != GameEvent.Type.PASS) return false;
// 2. 第二次传球
if (e2.getType() != GameEvent.Type.PASS) return false;
// 3. 最后必须得分
if (e3.getType() != GameEvent.Type.SCORE) return false;
String a = e1.getFromPlayer();
String b = e1.getToPlayer();
// 4. 回传方向必须是 B -> A
if (!Objects.equals(e2.getFromPlayer(), b)) return false;
if (!Objects.equals(e2.getToPlayer(), a)) return false;
// 5. 得分者必须是 A
if (!Objects.equals(e3.getToPlayer(), a)) return false;
// 6. 时间间隔不能太长(传球和回传必须是快速衔接)
long gap = Duration.between(e1.getTime(), e2.getTime()).getSeconds();
if (gap > MAX_INTERVAL_SECONDS) return false;
return true;
}
}
测试用例
import java.time.LocalDateTime;
import java.util.List;
public class Main {
public static void main(String[] args) {
LocalDateTime t = LocalDateTime.of(2025, 1, 1, 19, 0, 0);
List<GameEvent> events = List.of(
// A -> B,B 立刻回传 A,A 得分 = 一次撞墙式配合 ✔
new GameEvent("A", "B", GameEvent.Type.PASS, t.plusSeconds(0)),
new GameEvent("B", "A", GameEvent.Type.PASS, t.plusSeconds(1)),
new GameEvent(null, "A", GameEvent.Type.SCORE, t.plusSeconds(3)),
// C -> D 后 D 传给 E,不算撞墙(回传对象不一致)✘
new GameEvent("C", "D", GameEvent.Type.PASS, t.plusSeconds(10)),
new GameEvent("D", "E", GameEvent.Type.PASS, t.plusSeconds(11)),
new GameEvent(null, "E", GameEvent.Type.SCORE, t.plusSeconds(13)),
// F -> G,G 回传 F,但 F 投篮不中 ✘
new GameEvent("F", "G", GameEvent.Type.PASS, t.plusSeconds(20)),
new GameEvent("G", "F", GameEvent.Type.PASS, t.plusSeconds(21)),
new GameEvent(null, "F", GameEvent.Type.MISS, t.plusSeconds(23)),
// H -> I,但回传太慢(超过 3 秒)✘
new GameEvent("H", "I", GameEvent.Type.PASS, t.plusSeconds(30)),
new GameEvent("I", "H", GameEvent.Type.PASS, t.plusSeconds(40)),
new GameEvent(null, "H", GameEvent.Type.SCORE, t.plusSeconds(42))
);
int total = GiveAndGoAnalyzer.countGiveAndGo(events);
System.out.println("撞墙式配合完成次数:" + total + " 次");
}
}
运行结果:
撞墙式配合完成次数:1 次
扩展优化建议
| 需求 | 实现思路 |
|---|---|
| 统计每名球员的撞墙次数 | 用 Map<String, Integer> 以 A 为 key 累计 |
| 支持投篮造犯规(罚球得分) | 在 Type 中新增 FREE_THROW 分支 |
| 处理传球被断 | 新增 STEAL 事件,遇到则中断匹配 |
| 处理滑动窗口内多步配合 | 改为状态机:等待回传 → 等待终结 |
| 从文件/数据库读取事件 | 用 BufferedReader 或 JDBC 加载后构造 List |
状态机版(推荐用于真实数据)
真实比赛数据顺序可能有噪声,建议用状态机代替"三事件连看":
public static int countByStateMachine(List<GameEvent> events) {
int count = 0;
String passer = null; // A
String receiver = null; // B
LocalDateTime passTime = null;
for (GameEvent e : events) {
switch (e.getType()) {
case PASS:
if (passer == null) {
// 记录第一次传球
passer = e.getFromPlayer();
receiver = e.getToPlayer();
passTime = e.getTime();
} else if (e.getFromPlayer().equals(receiver)
&& e.getToPlayer().equals(passer)
&& Duration.between(passTime, e.getTime()).getSeconds() <= 3) {
// 已形成回传,等待 A 得分
passTime = e.getTime(); // 复用字段标记"等待终结"
} else {
// 其他传球,重置
passer = e.getFromPlayer();
receiver = e.getToPlayer();
passTime = e.getTime();
}
break;
case SCORE:
if (passer != null && e.getToPlayer().equals(passer)
&& Duration.between(passTime, e.getTime()).getSeconds() <= 5) {
count++;
}
passer = null;
break;
case MISS:
passer = null; // 未中,放弃
break;
}
}
return count;
}
统计撞墙式配合的关键是识别"传—回传—得分"这条链,并加上时间窗口和球员身份匹配约束,上面给出了最简三事件匹配法和更健壮的状态机法,可根据实际数据噪音程度选择。