Ruby 组合学

发布于 2024-12-17 12:34:33 字数 2742 浏览 0 评论 0原文

我想生成一个包含俱乐部列表的足球比赛。每场比赛都在周日进行,时间随机包含在 match_starts_at 数组中。每个俱乐部每周日只打一场比赛。

示例:

拥有这些俱乐部:

Club Atlético All Boys
Asociación Atlética Argentinos Juniors
Arsenal Fútbol Club
Club Atlético Banfield
Club Atlético Belgrano
Club Atlético Boca Juniors
Club Atlético Colón
Club Estudiantes de La Plata
Club Deportivo Godoy Cruz Antonio Tomba
Asociación Mutual Social y Deportiva Atlético de Rafaela
Club Atlético Independiente
Club Atlético Lanús
Club Atlético Newell's Old Boys
Club Olimpo
Racing Club
Club Atlético San Martín
Club Atlético San Lorenzo de Almagro
Club Atlético Tigre
Club Atlético Unión
Club Atlético Vélez Sarsfield

结果应与此处看到的类似:http://www.afa.org.ar/index.php?option=com_content&view=article&id=16780%3Afixture-del-torneo-de-primera-division&Itemid=100< /a>

俱乐部结构示例:

=> # Club @id=1 @name="Example Name"

=> # Club @id=2 @name="Example2 Name"

Fixture 结构示例:

=> # Fixture @id=1 @datetime='2011-11-19 19:12:49' @home_id=1 @away_id=2

Fixture 对象需要将以下内容保存到数据库中:

a home club (:home)    
an away club (:away)    
and the time of the match (:datetime)

每个俱乐部只能与其他俱乐部比赛一场,并且所有俱乐部都应该参加一场比赛主场,另一场客场,另一场主场,等等。一个日期应该有 10 场比赛。如何创建匹配列表?

这就是我到目前为止所做的。

  competition = Competition.get(1)
  clubs = Club.all #20 clubs
  @time = Time.now
  @count = 0
  until @time.sunday? do
     @time += (24*60*60) # add 1 day until it's sunday
  end
  @first_time = @time
  @fixture = {1 => []}
  clubs.combination(2).each_with_index do |(club1, club2), idx|
    Fixture.create(
      :home => idx.even? ? club1 : club2,
      :away => idx.even? ? club2 : club1,
      :datetime =>  available_fixture_date(club1,club2)
    ).save
  end

  def getFecha(club1, club2)
    @fixture.keys.each do |fecha|
      if (!@fixture[fecha].include?(club1.name) && !@fixture[fecha].include?(club2.name))
        @fixture[fecha] << club1.name
        @fixture[fecha] << club2.name
        @fixture[@fixture.keys.last + 1] = []
        return fecha
      end
    end
  end

  def available_fixture_date(club1, club2)
    fecha = getFecha(club1, club2)
    match_starts_at = ['16:00', '17:30', '18:10', '22:00']
    match_time = match_starts_at.shuffle.first
    @time  = @first_time + (24*60*60) * fecha * 7
    Time.new(@time.year, @time.month, @time.day, match_time[0,2], match_time[3,2])
 end

使用我的代码,我可以获得超过 19 个日期,并且我应该获得 19 个日期,每个日期有 10 个匹配项。

I want to generate a soccer football fixture with a list of clubs. Each game is played on Sundays in a random time included in the match_starts_at array. Each club plays only one game each Sunday.

Example:

Having these clubs:

Club Atlético All Boys
Asociación Atlética Argentinos Juniors
Arsenal Fútbol Club
Club Atlético Banfield
Club Atlético Belgrano
Club Atlético Boca Juniors
Club Atlético Colón
Club Estudiantes de La Plata
Club Deportivo Godoy Cruz Antonio Tomba
Asociación Mutual Social y Deportiva Atlético de Rafaela
Club Atlético Independiente
Club Atlético Lanús
Club Atlético Newell's Old Boys
Club Olimpo
Racing Club
Club Atlético San Martín
Club Atlético San Lorenzo de Almagro
Club Atlético Tigre
Club Atlético Unión
Club Atlético Vélez Sarsfield

Result should be similar to what is seen here: http://www.afa.org.ar/index.php?option=com_content&view=article&id=16780%3Afixture-del-torneo-de-primera-division&Itemid=100

Club structure example:

=> # Club @id=1 @name="Example Name"

=> # Club @id=2 @name="Example2 Name"

Fixture structure example:

=> # Fixture @id=1 @datetime='2011-11-19 19:12:49' @home_id=1 @away_id=2

A Fixture object needs the following to be saved to the database:

a home club (:home)    
an away club (:away)    
and the time of the match (:datetime)

Each club should play only one time with the other clubs and all clubs should play one match at home, the other away , the other at home, etc. There should be 10 matches in a date. How can I create the list of matches?

This is what I've done so far.

  competition = Competition.get(1)
  clubs = Club.all #20 clubs
  @time = Time.now
  @count = 0
  until @time.sunday? do
     @time += (24*60*60) # add 1 day until it's sunday
  end
  @first_time = @time
  @fixture = {1 => []}
  clubs.combination(2).each_with_index do |(club1, club2), idx|
    Fixture.create(
      :home => idx.even? ? club1 : club2,
      :away => idx.even? ? club2 : club1,
      :datetime =>  available_fixture_date(club1,club2)
    ).save
  end

  def getFecha(club1, club2)
    @fixture.keys.each do |fecha|
      if (!@fixture[fecha].include?(club1.name) && !@fixture[fecha].include?(club2.name))
        @fixture[fecha] << club1.name
        @fixture[fecha] << club2.name
        @fixture[@fixture.keys.last + 1] = []
        return fecha
      end
    end
  end

  def available_fixture_date(club1, club2)
    fecha = getFecha(club1, club2)
    match_starts_at = ['16:00', '17:30', '18:10', '22:00']
    match_time = match_starts_at.shuffle.first
    @time  = @first_time + (24*60*60) * fecha * 7
    Time.new(@time.year, @time.month, @time.day, match_time[0,2], match_time[3,2])
 end

With my code I get more than 19 dates and I should get 19 dates with 10 matches per date.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

£噩梦荏苒 2024-12-24 12:34:33

你不会得到一个很好的俏皮话,就像你为团队配对所做的那样,因为它需要查阅现有数据来找出已经采取的日期。但这应该可以正常工作。请注意,我使用了 ActiveSupport 的时间助手,但如果您没有可用的 ActiveSupport 并且不想包含它,则可以使用 Chronic 之类的东西。

def available_fixture_date(club1, club2)
  last_played = (club1.fixtures | club2.fixtures).max(:datetime)
  last_played.nil? ? DateTime.now.sunday : last_played + 1.week
end

def create_fixtures(clubs)
  clubs.combination(2).each_with_index do |(club1, club2), idx|
    Fixture.create(
      :home     => idx.even? ? club1 : club2,
      :away     => idx.even? ? club2 : club1,
      :datetime =>  available_fixture_date(club1, club2)
    )
  end
end

You won't get a nice one-liner for that, like you did for the pairing of teams, since it requires consulting the existing data to find out what dates are already taken. But this should work fine. Note that I've used ActiveSupport's time helpers, but you could use something like Chronic if you don't have ActiveSupport available and don't want to include it.

def available_fixture_date(club1, club2)
  last_played = (club1.fixtures | club2.fixtures).max(:datetime)
  last_played.nil? ? DateTime.now.sunday : last_played + 1.week
end

def create_fixtures(clubs)
  clubs.combination(2).each_with_index do |(club1, club2), idx|
    Fixture.create(
      :home     => idx.even? ? club1 : club2,
      :away     => idx.even? ? club2 : club1,
      :datetime =>  available_fixture_date(club1, club2)
    )
  end
end
陌伤ぢ 2024-12-24 12:34:33

我相信您在这里寻找的通用算法是循环。以下代码为我正确获取了日期,最终总共 19 个日期,每个日期 10 个匹配项:

DAY = 24 * 60 * 60
MATCH_START_TIMES = ['16:00', '17:30', '18:10', '22:00']

def fixture_date(fecha)
  # select a random start time
  match_time = MATCH_START_TIMES.sample

  @time = @first_time + DAY * fecha * 7
  Time.new(@time.year, @time.month, @time.day, match_time[0,2].to_i, match_time[3,2].to_i)
end

# uses round-robin indexing algorithm described on
# http://en.wikipedia.org/wiki/Round-robin%5Ftournament#Scheduling_algorithm
def round_robin(n, round)
  arr = [*0...n]
  arr.insert 1, *arr.pop(round)
  [arr.slice(0, n/2), arr.slice(n/2, n).reverse]
end

def find_club_combination(clubs, round, pair)
  indexes = round_robin(clubs.size, round)
  index_a, index_b = indexes.first[pair], indexes.last[pair]
  [clubs[index_a], clubs[index_b]]
end

competition = Competition.get(1)
clubs = Club.all #20 clubs
@time = Time.now
@count = 0
@time += DAY until @time.sunday?

@first_time = @time

num_rounds = clubs.size - 1
matches_per_day = clubs.size / 2
(0...num_rounds).collect do |round|
  matches_per_day.times do |pair|
    club1, club2 = find_club_combination(clubs, round, pair)
    Fixture.create(
      :home => round.even? ? club1 : club2,
      :away => round.even? ? club2 : club1,
      :datetime => fixture_date(round)
    ).save
  end
end

I believe the general algorithm you're looking for here is the Round-Robin. The following gets the dates correctly for me, ending up with 19 dates total, 10 matches per date:

DAY = 24 * 60 * 60
MATCH_START_TIMES = ['16:00', '17:30', '18:10', '22:00']

def fixture_date(fecha)
  # select a random start time
  match_time = MATCH_START_TIMES.sample

  @time = @first_time + DAY * fecha * 7
  Time.new(@time.year, @time.month, @time.day, match_time[0,2].to_i, match_time[3,2].to_i)
end

# uses round-robin indexing algorithm described on
# http://en.wikipedia.org/wiki/Round-robin%5Ftournament#Scheduling_algorithm
def round_robin(n, round)
  arr = [*0...n]
  arr.insert 1, *arr.pop(round)
  [arr.slice(0, n/2), arr.slice(n/2, n).reverse]
end

def find_club_combination(clubs, round, pair)
  indexes = round_robin(clubs.size, round)
  index_a, index_b = indexes.first[pair], indexes.last[pair]
  [clubs[index_a], clubs[index_b]]
end

competition = Competition.get(1)
clubs = Club.all #20 clubs
@time = Time.now
@count = 0
@time += DAY until @time.sunday?

@first_time = @time

num_rounds = clubs.size - 1
matches_per_day = clubs.size / 2
(0...num_rounds).collect do |round|
  matches_per_day.times do |pair|
    club1, club2 = find_club_combination(clubs, round, pair)
    Fixture.create(
      :home => round.even? ? club1 : club2,
      :away => round.even? ? club2 : club1,
      :datetime => fixture_date(round)
    ).save
  end
end
琉璃繁缕 2024-12-24 12:34:33

不确定您到底想要什么,但您似乎想要一种更简单的方法来进行时间计算?

如果是这样,Chronic 就非常酷了。

Chronic.parse('next sunday at 4pm')
#=> Sun Nov 20 16:00:00 -0800 2011

match_starts_at = ['16:00', '17:30', '18:10', '22:00']
Chronic.parse("sunday at #{match_starts_at[0]}")
#=> Sun Nov 20 16:00:00 -0800 2011

Not sure exactly what you are after here, but you seem to want an easier way to do time calculations?

If so, Chronic is pretty cool.

Chronic.parse('next sunday at 4pm')
#=> Sun Nov 20 16:00:00 -0800 2011

match_starts_at = ['16:00', '17:30', '18:10', '22:00']
Chronic.parse("sunday at #{match_starts_at[0]}")
#=> Sun Nov 20 16:00:00 -0800 2011
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文