diff --git a/.gitignore b/.gitignore
index a3f73ed..db869a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
pkg/*
data/**/*.json
data/settings.json
-data/simulator.rb
\ No newline at end of file
+data/simulator.rb
+data/*.csv
\ No newline at end of file
diff --git a/lib/pages/drive_team_rotation_generator.rb b/lib/pages/drive_team_rotation_generator.rb
new file mode 100644
index 0000000..0a59859
--- /dev/null
+++ b/lib/pages/drive_team_rotation_generator.rb
@@ -0,0 +1,204 @@
+module TAC
+ class Pages
+ class DriveTeamRotationGenerator < Page
+ FILENAME = "#{TAC::ROOT_PATH}/data/drive_team_rotation.csv"
+
+ def setup
+ header_bar("Drive Team Rotation Generator")
+
+ @roster ||= [
+ "Alexander",
+ "Aubrey",
+ "Cayden",
+ "Gabe",
+ "Spencer",
+ "Olivia"
+ ]
+
+ @roles ||= [
+ "Coach",
+ "Driver A",
+ "Driver B"
+ ]
+
+ menu_bar.clear do
+ button get_image("#{TAC::ROOT_PATH}/media/icons/save.png"), image_height: 1.0, tip: "Export rotation as Comma-Seperated Values" do
+ export_rotation
+
+ @status_bar.clear do
+ tagline "Saved to: #{FILENAME}"
+ end
+ end
+
+ button get_image("#{TAC::ROOT_PATH}/media/icons/target.png"), margin_right: 10, image_height: 1.0, tip: "Generate rotation" do
+ populate_rotation
+ end
+ end
+
+ body.clear do
+ flow(margin_left: 20, width: 1.0, height: 1.0) do
+ stack(width: 0.25) do
+ title "Roles", width: 1.0, margin_bottom: 4, text_align: :center
+
+ flow(width: 1.0, margin_bottom: 20) do
+ @role_name = edit_line "", placeholder: "Add role", width: 0.9
+ button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_width: 0.1 do
+ if @role_name.value.strip.length.positive?
+ @roles.push(@role_name.value.strip)
+ @role_name.value = ""
+
+ populate_roles
+ end
+ end
+ end
+
+ @roles_container = stack(width: 1.0, height: 0.835, scroll: true) do
+ end
+ end
+
+ stack(margin_left: 20, width: 0.25, height: 1.0) do
+ title "Roster", width: 1.0, margin_bottom: 4, text_align: :center
+
+ flow(width: 1.0, margin_bottom: 20) do
+ @roster_name = edit_line "", placeholder: "Add name", width: 0.9
+ button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_width: 0.1 do
+ if @roster_name.value.strip.length.positive?
+ @roster.push(@roster_name.value.strip)
+ @roster_name.value = ""
+
+ populate_roster
+ end
+ end
+ end
+
+ @roster_container = stack(width: 1.0, height: 0.835, scroll: true) do
+ end
+ end
+
+ stack(margin_left: 20, margin_right: 20, width: 0.5, height: 1.0) do
+ title "Rotation", width: 1.0, margin_bottom: 4, text_align: :center
+
+ @rotation_container = stack(width: 1.0, height: 0.835, scroll: true) do
+ end
+ end
+ end
+ end
+
+ populate_roles
+ populate_roster
+ populate_rotation
+ end
+
+ def populate_roles
+ @roles_container.clear do
+ @roles.each_with_index do |name, i|
+ flow(width: 1.0, padding: 2) do
+ background i.even? ? 0xff_007000 : 0xff_006000
+
+ tagline name, width: 0.9
+ button "X", width: 0.1, text_size: 18, **THEME_DANGER_BUTTON do
+ @roles.delete(name)
+ populate_roles
+ end
+ end
+ end
+ end
+ end
+
+ def populate_roster
+ @roster_container.clear do
+ @roster.each_with_index do |name, i|
+ flow(width: 1.0, padding: 2) do
+ background i.even? ? 0xff_007000 : 0xff_006000
+
+ tagline name, width: 0.9
+ button "X", width: 0.1, text_size: 18, **THEME_DANGER_BUTTON do
+ @roster.delete(name)
+ populate_roster
+ end
+ end
+ end
+ end
+ end
+
+ def populate_rotation
+ @rotation = Generator.new(roster: @roster, team_size: @roles.count)
+
+ @rotation_container.clear do
+ fraction = (1.0 / @rotation.team_size) - 0.02
+
+ flow(width: 1.0, padding: 2) do
+ background Gosu::Color::BLACK
+
+ @roles.each do |role|
+ tagline "#{role}", width: fraction
+ end
+ end
+
+ teams = @rotation.teams unless @shuffle_teams&.value
+ teams = @rotation.teams.shuffle if @shuffle_teams&.value
+
+ teams.each_with_index do |team, i|
+ flow(width: 1.0, padding: 2) do
+ background i.even? ? 0xff_007000 : 0xff_006000
+
+ team.each do |player|
+ tagline player, width: fraction
+ end
+ end
+ end
+ end
+ end
+
+ def export_rotation
+ return unless @rotation
+
+ buff = "#{@roles.join(',')}\n"
+
+ @rotation.teams.each do |team|
+ buff += "#{team.join(",")}\n"
+ end
+
+ buff.strip
+
+ File.write(FILENAME, buff)
+ end
+ end
+
+ class Generator
+ attr_reader :roster, :team_size, :rounds, :teams, :schedule
+
+ def initialize(roster:, team_size: 4, rounds: 6)
+ @roster = roster.clone
+ @roster.freeze
+ @team_size = team_size
+ @rounds = rounds
+
+ @teams = []
+ @schedule = []
+
+ generate
+ end
+
+ def generate
+ generate_teams
+ generate_round_robin
+ end
+
+ def generate_teams
+ return unless @roster.size >= @team_size
+
+ list = @roster.dup
+
+ list.size.times do
+ list.rotate!
+
+ @teams << list[0..@team_size - 1]
+ end
+ end
+
+ def generate_round_robin
+ end
+ end
+ end
+end
diff --git a/lib/states/editor.rb b/lib/states/editor.rb
index 2d15f1c..9f07a93 100644
--- a/lib/states/editor.rb
+++ b/lib/states/editor.rb
@@ -84,6 +84,10 @@ class Editor < CyberarmEngine::GuiState
button get_image("#{TAC::ROOT_PATH}/media/icons/joystickLeft.png"), margin: 4, tip: "Field Planner", image_width: 1.0 do
page(TAC::Pages::FieldPlanner)
end
+
+ button get_image("#{TAC::ROOT_PATH}/media/icons/massiveMultiplayer.png"), margin: 4, tip: "Drive Team Rotation Generator", image_width: 1.0 do
+ page(TAC::Pages::DriveTeamRotationGenerator)
+ end
end
@content = stack(width: window.width - @navigation.style.width, height: 1.0) do
diff --git a/timecrafters_configuration_tool.rb b/timecrafters_configuration_tool.rb
index 85c6b85..c12c6d8 100644
--- a/timecrafters_configuration_tool.rb
+++ b/timecrafters_configuration_tool.rb
@@ -27,6 +27,7 @@ require_relative "lib/pages/configurations"
require_relative "lib/pages/presets"
require_relative "lib/pages/search"
require_relative "lib/pages/field_planner"
+require_relative "lib/pages/drive_team_rotation_generator"
require_relative "lib/simulator/robot"
require_relative "lib/simulator/field"
require_relative "lib/simulator/simulation"