1

I'm trying to assign players to a club. A club has n players and a player belongs to a club. A club can only have less than 23 players and no more than 2 players playing in the same position.

clubs = Club.all #Club is a datamapper object. Returns 20 clubs
to_generate = 10000
while (to_generate > 0)
  p = Player.new #Player is a datamapper object
  p.position = position #position is a random integer defined elsewhere

  clubs.each do |club|
    count = 0
    club.players.each do |club_player|
      if (club_player.position == p.position)
        count += 1
      end
    end
    if (count < 2 && club.players.length < 22)
      club.players << p
      p.club = club
    end
  end
  p.save
  to_generate -= 1

end

At the end of the script, I expect that all the clubs have 22 players. Why it's not like that?

EDIT: At the end of the script I only get 22 players assigned to the last club (20) and 10000 players generated

marcosdsanchez
  • 2,529
  • 2
  • 17
  • 20

1 Answers1

0

Problem 1: You can exceed the max players per team and per position

These lines

if (count < 3 && club.players.length < 23)
  club.players << p
  p.club = club
end

can be summarized as "You can add the player to the club if the club has fewer than 23 players and there are fewer than 3 players already at that position."

This means it allows you to add one more... giving a total of 3 for the position and 23 for the team. So that part of the logic is wrong. Instead you want

if (count < 2 && club.players.length < 22)

Problem 2: Random number may not guarantee you have the right types of players

If the position is generated randomly, you can't be certain that you'll have enough players of the right types. What if, for example, the random number was coincidentally always 2? You'll never end up with a full team.

Problem 3: Once a player is assigned, you keep trying other clubs

Once you assign a player, you should not look at any more clubs. To do this, you need to break out of the each block.

if (count < 3 && club.players.length < 23)
  club.players << p
  p.club = club
  break
end

Even though you call club.players << p a bunch of times for the same player, DataMapper is aware of your one-to-one association and the last assignment "wins."

Larsenal
  • 49,878
  • 43
  • 152
  • 220
  • Problem 1: ok! Problem 2: I'm generating 10000 players, there's no easy way that this could happen. – marcosdsanchez Nov 04 '11 at 16:48
  • Regarding problem 2, it's true that it's not likely. But it's better to have deterministic behavior. So instead of just throwing 10,000 iterations at the problem, you could make your while loop conditioned on a check of whether each team has its required 22 players. – Larsenal Nov 04 '11 at 17:07