How can we avoid player position allocated in same team during random team generation

Would like to generate two or three teams based on selection ie ( 7-aside or 8- aside) . While doing the generation for 3 teams, for a 7 side game with 20 players, D-level players or F level player are not evenly distributed between teams based on Levels.

Could someone please advise the issue here ?

Extra players need to display as Substitutes:
code:

  const [input, setInput] = useState('');
  const [team1, setTeam1] = useState([]);
  const [team2, setTeam2] = useState([]);
  const [team3, setTeam3] = useState([]);
  const [subs, setSubs] = useState([]);
  const [savedTeams, setSavedTeams] = useState(JSON.parse(localStorage.getItem('savedTeams')) || []);
  const [numTeams, setNumTeams] = useState(2);
  const [playersPerSide, setPlayersPerSide] = useState(7);
  const [error, setError] = useState(null);
  const captureRef = useRef(null);
 

  useEffect(() => {
    localStorage.removeItem('savedTeams');
  }, []);

  const sanitizeInput = (input) => {
    return input.replace(/[^a-zA-Z0-9-.ns]/g, '');
  };

  const handleInputChange = (e) => {
    const sanitizedInput = sanitizeInput(e.target.value);
    setInput(sanitizedInput);
  };

  const handleNumTeamsChange = (e) => {
    setNumTeams(Number(e.target.value));
  };

  const handlePlayersPerSideChange = (e) => {
    setPlayersPerSide(Number(e.target.value));
  };

  const splitTeams = () => {
    if (!input.trim()) {
      setError('The input field cannot be empty. Please enter player names!');
      return;
    }

    const players = input
      .split('n')
      .map(player => player.trim())
      .filter(player => player)
      .map(player => player.replace(/^d+.s*/, ''));

    // Extract goalkeepers and outfield players
    const goalkeepers = players.filter(player => player.includes('GK'));
    const outfieldPlayers = players.filter(player => !player.includes('GK'));

    // Identify repeat players (marked with -R)
    const repeatPlayers = players.filter(player => player.includes('-R')).map(player => player.replace('-R', ''));
    const uniqueRepeatPlayers = [...new Set(repeatPlayers)];

    // Remove the repeat players from the list if exists
    const cleanedPlayers = players.filter(player => !player.includes('-R'));

    // Calculate the total number of required players
    const totalRequiredPlayers = playersPerSide * numTeams;
    const totalAvailablePlayers = cleanedPlayers.length + uniqueRepeatPlayers.length;

    // Check if we have enough players, including the repeat player
    
    // if (totalAvailablePlayers < totalRequiredPlayers) {
    //   setError(`Insufficient players. You need at least ${totalRequiredPlayers} players for ${numTeams} teams.`);
    //   return;
    // }

    // Initialize teams and substitutes
    const mainTeams = Array.from({ length: numTeams }, () => []);
    const shuffledOutfieldPlayers = outfieldPlayers.sort(() => Math.random() - 0.5);
    const availablePlayers = [...cleanedPlayers, ...uniqueRepeatPlayers];

    // Distribute goalkeepers among teams
    const usedGoalkeepers = new Set();
    goalkeepers.forEach(gk => {
      if (usedGoalkeepers.size < numTeams) {
        for (let i = 0; i < numTeams; i++) {
          if (mainTeams[i].filter(player => player.includes('GK')).length === 0 && !usedGoalkeepers.has(gk)) {
            mainTeams[i].push(gk);
            usedGoalkeepers.add(gk);
            break;
          }
        }
      }
    });

    // Distribute outfield players among teams
    let currentTeamIndex = 0;
    shuffledOutfieldPlayers.forEach(player => {
      if (mainTeams[currentTeamIndex].length < playersPerSide) {
        mainTeams[currentTeamIndex].push(player);
      }
      currentTeamIndex = (currentTeamIndex + 1) % numTeams;
    });

    // Ensure repeat players are placed correctly in the white team
    const whiteTeamIndex = numTeams === 3 ? 2 : 1; // Assuming white team is the last team if there are 3 teams
    const whiteTeamPlayers = new Set(mainTeams[whiteTeamIndex]);
    uniqueRepeatPlayers.forEach(player => {
      if (!whiteTeamPlayers.has(player)) {
        if (mainTeams[whiteTeamIndex].length < playersPerSide) {
          mainTeams[whiteTeamIndex].push(player);
          whiteTeamPlayers.add(player);
        }
      }
    });

    // Collect all players currently in teams
    const allPlayersInTeams = mainTeams.flat();
    // Calculate substitutes
    const substitutePlayers = availablePlayers.filter(player => !allPlayersInTeams.includes(player));

    setTeam1(mainTeams[0]);
    setTeam2(mainTeams[1]);
    if (numTeams === 3) setTeam3(mainTeams[2]);
    setSubs(substitutePlayers);
    setError(null);

    const newSavedTeams = [...savedTeams, { team1: mainTeams[0], team2: mainTeams[1], team3: mainTeams[2] || [], subs }];
    setSavedTeams(newSavedTeams);
    localStorage.setItem('savedTeams', JSON.stringify(newSavedTeams));
  };

  const sortPlayers = (players) => {
    return players.sort((a, b) => {
      const [aCategory, aLevel] = a.split('-').slice(1);
      const [bCategory, bLevel] = b.split('-').slice(1);

      const categoryOrder = ['GK', 'D', 'M', 'F'];
      const levelOrder = ['A', 'B', 'C', 'D'];

      if (aCategory !== bCategory) {
        return categoryOrder.indexOf(aCategory) - categoryOrder.indexOf(bCategory);
      }

      return levelOrder.indexOf(aLevel) - levelOrder.indexOf(bLevel);
    });
  };

  const downloadImage = () => {
    if (captureRef.current) {
      html2canvas(captureRef.current).then(canvas => {
        const link = document.createElement('a');
        link.href = canvas.toDataURL('image/png');
        link.download = 'teams.png';
        link.click();
      });
    }
  };

  const deleteSavedTeam = (index) => {
    const newSavedTeams = savedTeams.filter((_, i) => i !== index);
    setSavedTeams(newSavedTeams);
    localStorage.setItem('savedTeams', JSON.stringify(newSavedTeams));
  };

  const loadSavedTeam = (index) => {
    const team = savedTeams[index];
    setTeam1(team.team1);
    setTeam2(team.team2);
    setTeam3(team.team3);
    setSubs(team.subs);
  };

[![enter image description here][1]][1]

Input players:

1.Done-GK-A
2.Jerril-D-A
3.Max-D-B
4.Mikhail-M-B
5.Sante-F-A
6.Rodie-M-A
7.Wanner-M-A
8.Aaron-D-A
9.Frank-F-A
10.Milton-GK-B
11.Ferris-M-B
12.Rashes-F-A
13.Sajin-GK-A
14.Jacob-M-A
15.Johns-M-A-R
16.Lewis-F-B
17.Aabel-D-A
18.Melvin-D-A
19.Reymond-M-B
20.Delvin-F-A

CodeSandbox >>> https://codesandbox.io/p/sandbox/teamgen-8nzrs5

Rules need to follow / align while doing the team split:

 1. Split into two teams or three teams for a 7 - aside or 8 - aside game.
 2. Allocate GK into three teams, no two GK in the same team, same with other position not all defence or mid or forward players in one team
 3. Display in the below order, First Gk , then Defence, then Mid and finally Forward players. Positions- Gk, D, M and F are the positions 
 4. Evenly split Level-A player for any position between teams. A, B, C and D are the levels 
 5. If there are only 20 players available for a 7 - aside game, and if -R is given for a player input  >> Repeat that player in the third team. So eventually that player will be available in two teams. 

Generated teams: ( see Defense player got allocated in White and Black teams)

Team Red
Done-GK-A
Rodie-M-A
Jacob-M-A
Mikhail-M-B
Frank-F-A
Rashes-F-A
Lewis-F-B

Team Black
Milton-GK-B
Jerril-D-A
Melvin-D-A
Wanner-M-A
Johns-M-A-R
Reymond-M-B
Sante-F-A

Team White
Sajin-GK-A
Aabel-D-A
Aaron-D-A
Max-D-B
Johns-M-A
Ferris-M-B
Delvin-F-A