Java案例:统计"撞墙式配合"完成次数
"撞墙式配合"(也叫"二过一"、"撞墙配合")是足球中的经典战术:A 传球给 B,B 不停球直接回传给 A,A 接球后继续推进,就像球打在墙上弹回来一样。

下面用 Java 模拟一个简单的比赛事件流,统计该配合的成功完成次数。
思路设计
一次成功的"撞墙式配合"需要满足以下事件序列:
- 球员 A 传球 给 球员 B
- 球员 B 不停球(一次触球)立刻回传 给 球员 A
- 球员 A 接到球(接球成功)
我们只需要按顺序扫描事件流,匹配 A传球给B → B回传给A 这个模式即可。
代码实现
import java.util.*;
// 事件类型
enum EventType {
PASS, // 传球
RECEIVE, // 接球
SHOT, // 射门
DRIBBLE, // 带球
LOSE_BALL // 丢球
}
// 比赛事件
class MatchEvent {
int minute; // 比赛第几分钟
EventType type; // 事件类型
String fromPlayer; // 发起球员
String toPlayer; // 目标球员(若无可为 null)
public MatchEvent(int minute, EventType type, String fromPlayer, String toPlayer) {
this.minute = minute;
this.type = type;
this.fromPlayer = fromPlayer;
this.toPlayer = toPlayer;
}
@Override
public String toString() {
return String.format("[%d'] %s: %s -> %s",
minute, type, fromPlayer, toPlayer);
}
}
public class OneTwoCounter {
/**
* 统计撞墙式配合(二过一)完成的次数
* 匹配模式:A 传球给 B,紧接着 B 传球回给 A
*/
public static List<String> countOneTwo(List<MatchEvent> events) {
List<String> results = new ArrayList<>();
for (int i = 0; i < events.size() - 1; i++) {
MatchEvent cur = events.get(i);
MatchEvent next = events.get(i + 1);
// 当前是传球,且下一次也是传球
if (cur.type == EventType.PASS && next.type == EventType.PASS) {
String a = cur.fromPlayer; // 传球人 A
String b = cur.toPlayer; // 接球人 B
// 判断是否为A->B 紧接着 B->A
if (b != null
&& b.equals(next.fromPlayer)
&& a.equals(next.toPlayer)) {
results.add(String.format("%d'-%d' 分钟: %s 与 %s 完成一次撞墙配合",
cur.minute, next.minute, a, b));
i++; // 跳过下一事件,避免重复计数
}
}
}
return results;
}
public static void main(String[] args) {
// 模拟一段比赛事件流
List<MatchEvent> events = Arrays.asList(
new MatchEvent(10, EventType.PASS, "梅西", "苏亚雷斯"),
new MatchEvent(10, EventType.PASS, "苏亚雷斯", "梅西"), // ✅ 撞墙1
new MatchEvent(12, EventType.DRIBBLE, "梅西", null),
new MatchEvent(20, EventType.PASS, "内马尔", "阿尔维斯"),
new MatchEvent(21, EventType.DRIBBLE, "阿尔维斯", null),
new MatchEvent(30, EventType.PASS, "哈维", "伊涅斯塔"),
new MatchEvent(30, EventType.PASS, "伊涅斯塔", "哈维"), // ✅ 撞墙2
new MatchEvent(45, EventType.PASS, "布斯克茨", "皮克"),
new MatchEvent(45, EventType.PASS, "皮克", "布斯克茨"), // ✅ 撞墙3
new MatchEvent(60, EventType.SHOT, "梅西", null)
);
List<String> result = countOneTwo(events);
System.out.println("=== 撞墙式配合统计 ===");
result.forEach(System.out::println);
System.out.println("总计完成: " + result.size() + " 次");
}
}
运行结果
=== 撞墙式配合统计 ===
10'-10' 分钟: 梅西 与 苏亚雷斯 完成一次撞墙配合
30'-30' 分钟: 哈维 与 伊涅斯塔 完成一次撞墙配合
45'-45' 分钟: 布斯克茨 与 皮克 完成一次撞墙配合
总计完成: 3 次
进阶优化:用正则/栈的思想处理复杂场景
实际比赛中可能存在干扰事件(如带球、接球记录等),可以采用状态机方式更健壮地判断:
public static int countOneTwoByStateMachine(List<MatchEvent> events) {
int count = 0;
MatchEvent firstPass = null; // 暂存第一次传球
for (MatchEvent e : events) {
if (e.type != EventType.PASS) {
firstPass = null; // 非传球事件打断连续判定
continue;
}
if (firstPass == null) {
firstPass = e; // 记下第一次传球
} else {
// 检查是否构成 A->B B->A
boolean isOneTwo = Objects.equals(firstPass.toPlayer, e.fromPlayer)
&& Objects.equals(firstPass.fromPlayer, e.toPlayer);
if (isOneTwo) {
count++;
firstPass = null; // 计数后重置
} else {
firstPass = e; // 不匹配则把当前当作新的起点
}
}
}
return count;
}
| 关键点 | 说明 |
|---|---|
| 核心逻辑 | 检测连续两个传球事件 A→B、B→A |
| 数据来源 | 可用足球数据 API(如 Opta、StatsBomb)生成事件流 |
| 扩展方向 | 加入时间窗口限制(如两次传球间隔 < 3 秒)、位置信息判断 |
| 算法复杂度 | O(n),一次遍历即可 |
如果需要接入真实比赛数据(JSON/CSV) 或做成 Spring Boot 接口,可以进一步告诉我,我帮你扩展。