1
0
mirror of https://github.com/jcwimer/wrestlingApp synced 2026-03-25 01:14:43 +00:00

Added queues for mats and provided a way for tournament directors to move matches to a mat.

This commit is contained in:
2026-02-03 17:50:52 -05:00
parent a2f8c7bced
commit 2767274066
26 changed files with 1039 additions and 196 deletions

View File

@@ -1,53 +1,50 @@
class Mat < ApplicationRecord
include ActionView::RecordIdentifier
belongs_to :tournament
has_many :matches, dependent: :nullify
has_many :mat_assignment_rules, dependent: :destroy
validates :name, presence: true
before_destroy do
if tournament.matches.size > 0
tournament.reset_mats
matsToAssign = tournament.mats.select{|m| m.id != self.id}
tournament.assign_mats(matsToAssign)
end
end
after_create do
if tournament.matches.size > 0
tournament.reset_mats
matsToAssign = tournament.mats
tournament.assign_mats(matsToAssign)
end
end
QUEUE_SLOTS = %w[queue1 queue2 queue3 queue4].freeze
def assign_next_match
slot = first_empty_queue_slot
return true unless slot
match = next_eligible_match
self.matches.reload
if match and self.unfinished_matches.size < 4
match.mat_id = self.id
if match.save
# Invalidate any wrestler caches
if match.w1
match.wrestler1.touch
match.wrestler1.school.touch
return false unless match
place_match_in_empty_slot!(match, slot)
true
end
def advance_queue!(finished_match = nil)
self.class.transaction do
if finished_match
position = queue_position_for_match(finished_match)
if position == 1
shift_queue_forward!
fill_queue_slots!
elsif position
remove_match_from_queue_and_collapse!(finished_match.id)
else
fill_queue_slots!
end
if match.w2
match.wrestler2.touch
match.wrestler2.school.touch
end
return true
else
return false
if queue1_match&.finished == 1
shift_queue_forward!
end
fill_queue_slots!
end
else
return true
end
broadcast_current_match
true
end
def next_eligible_match
# Start with all matches that are either unfinished (nil or 0), have a bout number, and are ordered by bout_number
filtered_matches = tournament.matches
filtered_matches = Match.where(tournament_id: tournament_id)
.where(finished: [nil, 0]) # finished is nil or 0
.where(mat_id: nil) # mat_id is nil
.where.not(bout_number: nil) # bout_number is not nil
@@ -57,6 +54,11 @@ class Mat < ApplicationRecord
filtered_matches = filtered_matches
.where("loser1_name != ? OR loser1_name IS NULL", "BYE")
.where("loser2_name != ? OR loser2_name IS NULL", "BYE")
# Filter out matches without a wrestlers
filtered_matches = filtered_matches
.where("w1 IS NOT NULL")
.where("w2 IS NOT NULL")
# Apply mat assignment rules
mat_assignment_rules.each do |rule|
@@ -80,9 +82,178 @@ class Mat < ApplicationRecord
filtered_matches.first
end
def queue_match_ids
QUEUE_SLOTS.map { |slot| public_send(slot) }
end
def queue_matches
queue_match_ids.map { |match_id| match_id ? Match.find_by(id: match_id) : nil }
end
def queue1_match
queue_match_at(1)
end
def queue2_match
queue_match_at(2)
end
def queue3_match
queue_match_at(3)
end
def queue4_match
queue_match_at(4)
end
def queue_position_for_match(match)
return nil unless match
return 1 if queue1 == match.id
return 2 if queue2 == match.id
return 3 if queue3 == match.id
return 4 if queue4 == match.id
nil
end
def remove_match_from_queue_and_collapse!(match_id)
queue_ids = queue_match_ids
return if queue_ids.none? { |id| id == match_id }
queue_ids.map! { |id| id == match_id ? nil : id }
queue_ids = queue_ids.compact
queue_ids += [nil] * (4 - queue_ids.size)
update!(
queue1: queue_ids[0],
queue2: queue_ids[1],
queue3: queue_ids[2],
queue4: queue_ids[3]
)
fill_queue_slots!
broadcast_current_match
end
def assign_match_to_queue!(match, position)
position = position.to_i
raise ArgumentError, "Queue position must be 1-4" unless (1..4).cover?(position)
self.class.transaction do
match.update!(mat_id: id)
remove_match_from_other_mats!(match.id)
queue_ids = queue_match_ids.map { |id| id == match.id ? nil : id }
queue_ids = queue_ids.compact
queue_ids.insert(position - 1, match.id)
bumped_match_id = queue_ids.length > 4 ? queue_ids.pop : nil
queue_ids += [nil] * (4 - queue_ids.length)
update!(
queue1: queue_ids[0],
queue2: queue_ids[1],
queue3: queue_ids[2],
queue4: queue_ids[3]
)
bumped_match = Match.find_by(id: bumped_match_id)
if bumped_match && bumped_match.finished != 1
bumped_match.update!(mat_id: nil)
end
end
broadcast_current_match
end
def clear_queue!
update!(queue1: nil, queue2: nil, queue3: nil, queue4: nil)
end
def unfinished_matches
matches.select{|m| m.finished != 1}.sort_by{|m| m.bout_number}
end
private
def queue_match_at(position)
match_id = public_send("queue#{position}")
match_id ? Match.find_by(id: match_id) : nil
end
def first_empty_queue_slot
QUEUE_SLOTS.each_with_index do |slot, index|
return index + 1 if public_send(slot).nil?
end
nil
end
def shift_queue_forward!
update!(
queue1: queue2,
queue2: queue3,
queue3: queue4,
queue4: nil
)
end
def fill_queue_slots!
queue_ids = queue_match_ids
updated = false
QUEUE_SLOTS.each_with_index do |_slot, index|
next if queue_ids[index].present?
match = next_eligible_match
break unless match
queue_ids[index] = match.id
match.update!(mat_id: id)
updated = true
end
if updated
update!(
queue1: queue_ids[0],
queue2: queue_ids[1],
queue3: queue_ids[2],
queue4: queue_ids[3]
)
end
end
def remove_match_from_other_mats!(match_id)
self.class.where.not(id: id)
.where("queue1 = :match_id OR queue2 = :match_id OR queue3 = :match_id OR queue4 = :match_id", match_id: match_id)
.find_each do |mat|
mat.remove_match_from_queue_and_collapse!(match_id)
end
end
def place_match_in_empty_slot!(match, slot)
self.class.transaction do
match.update!(mat_id: id)
remove_match_from_other_mats!(match.id)
update!(slot_key(slot) => match.id)
end
broadcast_current_match
end
def slot_key(slot)
"queue#{slot}"
end
def broadcast_current_match
Turbo::StreamsChannel.broadcast_update_to(
self,
target: dom_id(self, :current_match),
partial: "mats/current_match",
locals: {
mat: self,
match: queue1_match,
next_match: queue2_match,
show_next_bout_button: true
}
)
end
end

View File

@@ -37,12 +37,14 @@ class Match < ApplicationRecord
wrestler2.touch
end
if self.finished == 1 && self.winner_id != nil
if self.mat
self.mat.assign_next_match
end
advance_wrestlers
if self.mat
self.mat.advance_queue!(self)
end
self.tournament.refill_open_bout_board_queues
# School point calculation has move to the end of advance wrestler
# calculate_school_points
self.update(mat_id: nil)
end
end
@@ -352,13 +354,13 @@ class Match < ApplicationRecord
next unless mat
Turbo::StreamsChannel.broadcast_update_to(
mat,
target: dom_id(mat, :current_match),
partial: "mats/current_match",
locals: {
mat: mat,
match: mat.unfinished_matches.first,
next_match: mat.unfinished_matches.second,
mat,
target: dom_id(mat, :current_match),
partial: "mats/current_match",
locals: {
mat: mat,
match: mat.queue1_match,
next_match: mat.queue2_match,
show_next_bout_button: true
}
)

View File

@@ -82,23 +82,18 @@ class Tournament < ApplicationRecord
matches.maximum(:round) || 0 # Return 0 if no matches or max round is nil
end
def assign_mats(mats_to_assign)
if mats_to_assign.count > 0
until mats_to_assign.sort_by{|m| m.id}.last.matches.count == 4
mats_to_assign.sort_by{|m| m.id}.each do |m|
m.assign_next_match
end
end
end
end
def reset_mats
matches.reload
mats.reload
matches_to_reset = matches.select{|m| m.mat_id != nil}
# matches_to_reset.update_all( {:mat_id => nil } )
matches_to_reset.each do |m|
m.mat_id = nil
m.save
end
mats.each do |mat|
mat.clear_queue!
end
end
def pointAdjustments
@@ -228,19 +223,24 @@ class Tournament < ApplicationRecord
def reset_and_fill_bout_board
reset_mats
if mats.any?
4.times do
# Iterate over each mat and assign the next available match
mats.each do |mat|
match_assigned = mat.assign_next_match
# If no more matches are available, exit early
unless match_assigned
puts "No more eligible matches to assign."
return
end
matches.reload
refill_open_bout_board_queues
end
def refill_open_bout_board_queues
return unless mats.any?
loop do
assigned_any = false
# Fill in round-robin order by queue depth:
# all mats queue1 first, then queue2, then queue3, then queue4.
(1..4).each do |slot|
mats.reload.each do |mat|
next unless mat.public_send("queue#{slot}").nil?
assigned_any ||= mat.assign_next_match
end
end
end
break unless assigned_any
end
end
@@ -279,4 +279,4 @@ class Tournament < ApplicationRecord
def connection_adapter
ActiveRecord::Base.connection.adapter_name
end
end
end