You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 11中如何使用Seeder与Factory实现从固定数量的已有用户中随机生成符合2v2规则的游戏关联

Laravel 11中如何使用Seeder与Factory实现从固定数量的已有用户中随机生成符合2v2规则的游戏关联

问题描述

我的问题和一个未解决的问题类似。我正在用Laravel 11做一个2v2天梯系统,有两个模型:

  • Users(用户)
  • Games(游戏)

用户和游戏之间有一个中间表,里面加了user_team字段,用来定义用户属于哪个队伍。

用户可以参与无限多场游戏,但每场游戏只能有4个玩家,每个玩家的队伍由中间表的字段决定。

我现在的Seeder代码是这样的:

$users = User::factory(20)->create();

Game::factory(100)
  ->hasAttached($users->random(2), [
    'user_team' => 'team1'
  ])
  ->hasAttached($users->random(2), [
    'user_team' => 'team2'
  ])
  ->create();

这段代码能生成20个用户和100场游戏,但问题是每场游戏都用的是同样的4个用户。如果我直接把User::factory()放进hasAttached()里,又会给每场游戏都生成新用户。

我想要的效果是:用这20个用户随机组队参与100场游戏,而且同一场游戏里不能有重复的用户。

希望我表达清楚了需求!


解决方案:自定义逻辑实现随机不重复组队

这个问题我之前做类似的多人对战系统时也踩过坑,核心问题是你两次调用$users->random(2)时,都是从整个用户池里随机抽取,不仅可能出现重复用户,还会导致每场游戏的玩家固定。咱们可以通过自定义Factory回调或者Seeder里的循环逻辑来解决:

方法一:直接在Seeder里处理(快速实现)

修改你的Seeder代码,先为每场游戏一次性选出4个不重复的用户,再拆分两队关联:

$users = User::factory(20)->create();

// 遍历每个生成的游戏,单独处理用户关联
Game::factory(100)->create()->each(function ($game) use ($users) {
    // 从20个用户里随机选4个完全不重复的
    $selectedPlayers = $users->random(4);
    
    // 拆分两队:前2个是team1,后2个是team2
    $team1 = $selectedPlayers->take(2);
    $team2 = $selectedPlayers->skip(2);

    // 关联team1用户到游戏,设置队伍字段
    $game->users()->attach(
        $team1,
        array_fill(0, $team1->count(), ['user_team' => 'team1'])
    );

    // 关联team2用户到游戏
    $game->users()->attach(
        $team2,
        array_fill(0, $team2->count(), ['user_team' => 'team2'])
    );
});

方法二:封装成Factory状态(更优雅,可复用)

如果以后需要多次生成2v2的游戏数据,可以把这个逻辑封装到Game Factory的状态里,方便复用:

在database/factories/GameFactory.php中添加状态方法:

use Illuminate\Database\Eloquent\Collection;

// ...

public function twoVsTwo(Collection $users)
{
    return $this->afterCreating(function ($game) use ($users) {
        // 随机选4个不重复用户
        $selectedPlayers = $users->random(4);
        $team1 = $selectedPlayers->take(2);
        $team2 = $selectedPlayers->skip(2);

        // 关联两队用户
        $game->users()->attach($team1, ['user_team' => 'team1']);
        $game->users()->attach($team2, ['user_team' => 'team2']);
    });
}

然后在Seeder里调用这个状态:

$users = User::factory(20)->create();

Game::factory(100)
    ->twoVsTwo($users)
    ->create();

方案优势说明

  • 先一次性抽取4个不重复用户,彻底避免了同一场游戏出现重复玩家的问题
  • 所有游戏都从已有的20个用户中随机选择,不会生成新用户,也不会固定使用某几个用户
  • 两种方法可以根据你的需求选择:快速实现用方法一,需要复用逻辑用方法二

如果想要更贴近真实场景的对战数据(比如让部分用户参与更多游戏),还可以用weightedRandom方法给用户设置权重,但基础的2v2不重复组队需求,上面的方案完全够用啦。


备注:内容来源于stack exchange,提问作者Ricaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 12:03:05