diff --git a/.vs/TournamentManager/DesignTimeBuild/.dtbcache.v2 b/.vs/TournamentManager/DesignTimeBuild/.dtbcache.v2
index e5076c70ac9cda529afde7927fc1dff71499ceb4..28511334a479f5b5701ef7bf215af0394f20c23a 100644
Binary files a/.vs/TournamentManager/DesignTimeBuild/.dtbcache.v2 and b/.vs/TournamentManager/DesignTimeBuild/.dtbcache.v2 differ
diff --git a/.vs/TournamentManager/v16/.suo b/.vs/TournamentManager/v16/.suo
index 99bee51a68bf15ba9fd68d62c8344795d85ad1c2..feedc3ab649c204e2904e9047d10fef384fe17f3 100644
Binary files a/.vs/TournamentManager/v16/.suo and b/.vs/TournamentManager/v16/.suo differ
diff --git a/TournamentManager.csproj.user b/TournamentManager.csproj.user
index d81df0bb4c5c1793b6b08d1da0a40db8b091eadd..31512808a5436a2c90c4cf5642da6350ab225814 100644
--- a/TournamentManager.csproj.user
+++ b/TournamentManager.csproj.user
@@ -4,7 +4,7 @@
     <ShowAllFiles>false</ShowAllFiles>
   </PropertyGroup>
   <ItemGroup>
-    <Compile Update="src\CalculateControl.cs">
+    <Compile Update="src\ComputeControl.cs">
       <SubType>UserControl</SubType>
     </Compile>
     <Compile Update="src\ExportControl.cs">
diff --git a/obj/Debug/net5.0-windows/TournamentManager.csproj.CoreCompileInputs.cache b/obj/Debug/net5.0-windows/TournamentManager.csproj.CoreCompileInputs.cache
index 14a5c34bada98649481229c8762402687adcd32d..a7639951418afae6c1a38e0b5bcda512c42a3611 100644
--- a/obj/Debug/net5.0-windows/TournamentManager.csproj.CoreCompileInputs.cache
+++ b/obj/Debug/net5.0-windows/TournamentManager.csproj.CoreCompileInputs.cache
@@ -1 +1 @@
-9c56342d8d0782585dfb5a8f145b7388446bfec3
+32b0d61a8a00098f0ff2a6864f4e5e9054b43933
diff --git a/obj/Debug/net5.0-windows/TournamentManager.csproj.FileListAbsolute.txt b/obj/Debug/net5.0-windows/TournamentManager.csproj.FileListAbsolute.txt
index 66ce1be8491dea720e0b44e462355d801bf3f4ac..76fe7e106299cee003f9a3382dfa816de333c951 100644
--- a/obj/Debug/net5.0-windows/TournamentManager.csproj.FileListAbsolute.txt
+++ b/obj/Debug/net5.0-windows/TournamentManager.csproj.FileListAbsolute.txt
@@ -52,4 +52,4 @@ C:\Users\micha\School\RiderProjects\c-sharp-semestral-project-1\obj\Debug\net5.0
 C:\Users\micha\School\RiderProjects\c-sharp-semestral-project-1\obj\Debug\net5.0-windows\TournamentManager.genruntimeconfig.cache
 C:\Users\micha\School\RiderProjects\c-sharp-semestral-project-1\obj\Debug\net5.0-windows\TournamentManager.src.GroupControl.resources
 C:\Users\micha\School\RiderProjects\c-sharp-semestral-project-1\obj\Debug\net5.0-windows\TournamentManager.src.ExportControl.resources
-C:\Users\micha\School\RiderProjects\c-sharp-semestral-project-1\obj\Debug\net5.0-windows\TournamentManager.src.CalculateControl.resources
+C:\Users\micha\School\RiderProjects\c-sharp-semestral-project-1\obj\Debug\net5.0-windows\TournamentManager.src.ComputeControl.resources
diff --git a/obj/Debug/net5.0-windows/TournamentManager.csproj.GenerateResource.cache b/obj/Debug/net5.0-windows/TournamentManager.csproj.GenerateResource.cache
index 31ceece9a93e9f4390f2c97b676c835609f78207..a6324fb688133d11bccf7fc3c90aa5696ff67aed 100644
Binary files a/obj/Debug/net5.0-windows/TournamentManager.csproj.GenerateResource.cache and b/obj/Debug/net5.0-windows/TournamentManager.csproj.GenerateResource.cache differ
diff --git a/obj/Debug/net5.0-windows/TournamentManager.csprojAssemblyReference.cache b/obj/Debug/net5.0-windows/TournamentManager.csprojAssemblyReference.cache
index 8ec9cabf84c61390d17139e208b06a1c2e561174..fad52e5112686b1fe17ecd9e1f07ec50c3268c70 100644
Binary files a/obj/Debug/net5.0-windows/TournamentManager.csprojAssemblyReference.cache and b/obj/Debug/net5.0-windows/TournamentManager.csprojAssemblyReference.cache differ
diff --git a/obj/Debug/net5.0-windows/TournamentManager.dll b/obj/Debug/net5.0-windows/TournamentManager.dll
index 513211d477b05fd7d7935f6e68d867d5c9833c9d..f913267a235359355f923b45a0a82f2e98e4e8ff 100644
Binary files a/obj/Debug/net5.0-windows/TournamentManager.dll and b/obj/Debug/net5.0-windows/TournamentManager.dll differ
diff --git a/obj/Debug/net5.0-windows/TournamentManager.pdb b/obj/Debug/net5.0-windows/TournamentManager.pdb
index 3718a08aacd85fc4ec5c661428cd3a0b94b7fabc..e2a7d3eca6a21eb8e550166d0c0691d88aa0df9f 100644
Binary files a/obj/Debug/net5.0-windows/TournamentManager.pdb and b/obj/Debug/net5.0-windows/TournamentManager.pdb differ
diff --git a/obj/Debug/net5.0-windows/TournamentManager.src.CalculateControl.resources b/obj/Debug/net5.0-windows/TournamentManager.src.ComputeControl.resources
similarity index 100%
rename from obj/Debug/net5.0-windows/TournamentManager.src.CalculateControl.resources
rename to obj/Debug/net5.0-windows/TournamentManager.src.ComputeControl.resources
diff --git a/obj/Debug/net5.0-windows/ref/TournamentManager.dll b/obj/Debug/net5.0-windows/ref/TournamentManager.dll
index 9d23fe7715471eaeaa998cc797350f152a8eb0f7..0d05c167696644b2e9e1280cc0d81f971ea45da8 100644
Binary files a/obj/Debug/net5.0-windows/ref/TournamentManager.dll and b/obj/Debug/net5.0-windows/ref/TournamentManager.dll differ
diff --git a/obj/rider.project.restore.info b/obj/rider.project.restore.info
index d820c47ca79fafdeda233a59374f8ad43d39bde2..1e682781d2c191141cabdfcdc47360e0544842b4 100644
--- a/obj/rider.project.restore.info
+++ b/obj/rider.project.restore.info
@@ -1 +1 @@
-16225768046431808
\ No newline at end of file
+16226427414345850
\ No newline at end of file
diff --git a/src/CalculateGroupsEventArgs.cs b/src/CalculateGroupsEventArgs.cs
deleted file mode 100644
index 2a16a293eab1b1aa700962f5e7bc2f106b95a649..0000000000000000000000000000000000000000
--- a/src/CalculateGroupsEventArgs.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace TournamentManager
-{
-    public class CalculateGroupsEventArgs
-    {
-        public int GroupSize { get; }
-
-        public CalculateGroupsEventArgs(int groupSize)
-        {
-            GroupSize = groupSize;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/CalculateControl.Designer.cs b/src/ComputeControl.Designer.cs
similarity index 98%
rename from src/CalculateControl.Designer.cs
rename to src/ComputeControl.Designer.cs
index e7c195fb299b9dfe9761f509346d68c185e8d447..dac0386ae478ad069a25fd1a18429b7cf1ba6a33 100644
--- a/src/CalculateControl.Designer.cs
+++ b/src/ComputeControl.Designer.cs
@@ -1,7 +1,7 @@
 
 namespace TournamentManager.src
 {
-    partial class CalculateControl
+    partial class ComputeControl
     {
         /// <summary> 
         /// Required designer variable.
@@ -107,7 +107,7 @@ namespace TournamentManager.src
             this.Controls.Add(this.cbGroupSize);
             this.Controls.Add(this.label1);
             this.Controls.Add(this.btnGroups);
-            this.Name = "CalculateControl";
+            this.Name = "ComputeControl";
             this.Size = new System.Drawing.Size(490, 92);
             this.ResumeLayout(false);
             this.PerformLayout();
diff --git a/src/CalculateControl.cs b/src/ComputeControl.cs
similarity index 55%
rename from src/CalculateControl.cs
rename to src/ComputeControl.cs
index f8f1bd7f9a19a2e6ee9d94ebe89f712a40fdaf4f..e0d384932e0cd64e52347c4126ab5a79fac515f6 100644
--- a/src/CalculateControl.cs
+++ b/src/ComputeControl.cs
@@ -11,14 +11,17 @@ using System.Windows.Forms;
 
 namespace TournamentManager.src
 {
-    public partial class CalculateControl : UserControl
+    public partial class ComputeControl : UserControl
     {
-        public event CalculateGroupsEventArgsDelegate CalculateGroups;
+        public event ComputeEventArgsDelegate ComputeGroups;
+        public event ComputeEventArgsDelegate ComputePlayOff;
+
+        public delegate void ComputeEventArgsDelegate(object sender, ComputeEventArgs e);
+        protected void OnComputeGroups(ComputeEventArgs args) => ComputeGroups?.Invoke(this, args);
+        protected void OnComputePlayOff(ComputeEventArgs args) => ComputePlayOff?.Invoke(this, args);
 
-        public delegate void CalculateGroupsEventArgsDelegate(object sender, CalculateGroupsEventArgs e);
-        protected void OnCalculateGroups(CalculateGroupsEventArgs args) => CalculateGroups?.Invoke(this, args);
         
-        public CalculateControl()
+        public ComputeControl()
         {
             InitializeComponent();
             Func<int, int, int, IEnumerable<string> > createRange = (x, y, z) =>
@@ -36,12 +39,17 @@ namespace TournamentManager.src
                 //TODO: throw some message
                 return;
             }
-            OnCalculateGroups(new CalculateGroupsEventArgs(int.Parse(cbGroupSize.SelectedItem.ToString()!)));
+            OnComputeGroups(new ComputeEventArgs(int.Parse(cbGroupSize.SelectedItem.ToString()!)));
         }
 
         private void btnPlayOff_Click(object sender, EventArgs e)
         {
-            //TODO: Calculate playoff
+            if (cbEliminate.SelectedItem == null)
+            {
+                //TODO: throw some message
+                return;
+            }
+            OnComputePlayOff(new ComputeEventArgs(int.Parse(cbEliminate.SelectedItem.ToString()!)));
         }
     }
 }
diff --git a/src/CalculateControl.resx b/src/ComputeControl.resx
similarity index 100%
rename from src/CalculateControl.resx
rename to src/ComputeControl.resx
diff --git a/src/ComputeEventArgs.cs b/src/ComputeEventArgs.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0f2bab36b0146a010f328de805cbe10456e7d2cf
--- /dev/null
+++ b/src/ComputeEventArgs.cs
@@ -0,0 +1,12 @@
+namespace TournamentManager
+{
+    public class ComputeEventArgs
+    {
+        public int Amount { get; }
+
+        public ComputeEventArgs(int amount)
+        {
+            Amount = amount;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Group.cs b/src/Group.cs
index 6bb10c6d689cbb5d8682f89c1ac51a939e33944c..55aa62de42952e821aedbfc721a1968e0260ad30 100644
--- a/src/Group.cs
+++ b/src/Group.cs
@@ -1,4 +1,6 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Runtime.Serialization;
 
 namespace TournamentManager
@@ -6,12 +8,43 @@ namespace TournamentManager
     public class Group : ISerializable
     {
         public List<Participant> Members { get; set; }
-        public List<Match> Matches { get; set; }
+        public int[,] Matches { get; set; }
 
         public Group()
         {
             Members = new List<Participant>();
-            Matches = new List<Match>();
+        }
+
+        public Participant ExtractGroupMember(string name)
+        {
+            Participant? result;
+            if ((result = Members.FirstOrDefault(m =>
+                name.Equals($"{m.FirstName} {m.Surname}"))) == null)
+            {
+                throw new Exception("I should define my own exception fr");
+            }
+
+            return result;
+
+
+        }
+        public int GetIndex(Participant opponent)
+        {
+            if (!Members.Contains(opponent))
+                throw new Exception("this should not happen");
+            return Members.FindIndex(x => x.Equals(opponent));
+        }
+
+        public (int firstIndex, int secondIndex) GetIndices(Participant firstOpponent, Participant secondOpponent)
+        {
+            return (firstIndex: GetIndex(firstOpponent), secondIndex: GetIndex(secondOpponent));
+        }
+
+        public (int first, int second) GetScore(Participant firstOpponent, Participant secondOpponent)
+        {
+            var indices = GetIndices(firstOpponent, secondOpponent);
+            return (Matches[indices.firstIndex, indices.secondIndex],
+                Matches[indices.secondIndex, indices.firstIndex]);
         }
         
         public void GetObjectData(SerializationInfo info, StreamingContext context)
diff --git a/src/GroupControl.cs b/src/GroupControl.cs
index 7d7a44c0af7db32e037c1c3d457b883bc6ab4d18..38a2ba9eaa71b27df00ce8f824bacd1b41ce98ba 100644
--- a/src/GroupControl.cs
+++ b/src/GroupControl.cs
@@ -35,6 +35,7 @@ namespace TournamentManager.src
 
         public void AddGroups(int groupCount)
         {
+            cbGroup.Items.Clear();
             for (int i = 0; i < groupCount; i++)
             {
                 cbGroup.Items.Add($"Group {i + 1}");
diff --git a/src/ManageTournamentForm.Designer.cs b/src/ManageTournamentForm.Designer.cs
index 5fad2fd4a92f686a633c02c425e144de4c6d09bd..9871f4a901e035b26026c77e687feb4be340fa2a 100644
--- a/src/ManageTournamentForm.Designer.cs
+++ b/src/ManageTournamentForm.Designer.cs
@@ -38,7 +38,7 @@ namespace TournamentManager
             this.groupBox3 = new System.Windows.Forms.GroupBox();
             this.groupControl = new TournamentManager.src.GroupControl();
             this.groupBox4 = new System.Windows.Forms.GroupBox();
-            this.calculateControl = new TournamentManager.src.CalculateControl();
+            this.computeControl = new TournamentManager.src.ComputeControl();
             this.groupBox5 = new System.Windows.Forms.GroupBox();
             this.groupBox1.SuspendLayout();
             this.groupBox2.SuspendLayout();
@@ -100,7 +100,7 @@ namespace TournamentManager
             // 
             // groupBox4
             // 
-            this.groupBox4.Controls.Add(this.calculateControl);
+            this.groupBox4.Controls.Add(this.computeControl);
             this.groupBox4.Location = new System.Drawing.Point(395, 172);
             this.groupBox4.Name = "groupBox4";
             this.groupBox4.Size = new System.Drawing.Size(501, 138);
@@ -110,10 +110,10 @@ namespace TournamentManager
             // 
             // calculateControl
             // 
-            this.calculateControl.Location = new System.Drawing.Point(5, 22);
-            this.calculateControl.Name = "calculateControl";
-            this.calculateControl.Size = new System.Drawing.Size(491, 111);
-            this.calculateControl.TabIndex = 0;
+            this.computeControl.Location = new System.Drawing.Point(5, 22);
+            this.computeControl.Name = "computeControl";
+            this.computeControl.Size = new System.Drawing.Size(491, 111);
+            this.computeControl.TabIndex = 0;
             // 
             // groupBox5
             // 
@@ -154,6 +154,6 @@ namespace TournamentManager
         private src.GroupControl groupControl;
         private System.Windows.Forms.GroupBox groupBox4;
         private System.Windows.Forms.GroupBox groupBox5;
-        private src.CalculateControl calculateControl;
+        private src.ComputeControl computeControl;
     }
 }
\ No newline at end of file
diff --git a/src/ManageTournamentForm.cs b/src/ManageTournamentForm.cs
index a2797a4e4fe936bcd28924aeea255688de536f1a..abdbca62a85546ea008fb905eccc0eb0d0852398 100644
--- a/src/ManageTournamentForm.cs
+++ b/src/ManageTournamentForm.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
 using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
 using System.Windows.Forms;
 
 namespace TournamentManager
@@ -13,23 +15,29 @@ namespace TournamentManager
         private const string EditParticipantError = "Participant with this name is already signed in competition";
         private const string ErrorCaption = "Error";
         private readonly ObservableCollection<Participant> _participants = new();
-        private readonly ObservableCollection<Group> _groups = new();
+        private List<Group> _groups;
+        private PlayOffTree _playOff;
         
         public ManageTournamentForm(string path)
         {
             InitializeComponent();
+            
             enterantCntrl.SubmitParticipantClick += OnSubmitParticipantClicked;
             _participants.CollectionChanged += HandleParticipantsChanged;
             manageParticipantsControl.ParticipantsModified += HandleOnParticipantRemovedClicked;
-            calculateControl.CalculateGroups += HandleOnCalculateGroupsClicked;
+            computeControl.ComputeGroups += HandleOnComputeGroupsClicked;
+            computeControl.ComputePlayOff += HandleOnComputePlayOffClicked;
             groupControl.CbGroupItemSelected += HandleOnGroupSelected;
             groupControl.OpponentsSelected += HandleOnGroupOpponentsSelected;
             groupControl.SubmitClicked += HandleOnGroupControlSubmitClicked;
+            
             foreach (var p in _participants)
             {
                 manageParticipantsControl.CbAddParticipant($"{p.FirstName} {p.Surname}");
             }
         }
+
+        #region eventHandlers
         
         protected void OnSubmitParticipantClicked(object sender, EventArgs e)
         {
@@ -76,14 +84,14 @@ namespace TournamentManager
             
         }
 
-        private void HandleOnCalculateGroupsClicked(object sender, CalculateGroupsEventArgs e)
+        private void HandleOnComputeGroupsClicked(object sender, ComputeEventArgs e)
         {
-            var numberOfGroups = (_participants.Count - 1) / e.GroupSize + 1;
+            var numberOfGroups = (_participants.Count - 1) / e.Amount + 1;
             var groupIndex = 0;
             var orderedParticipants = _participants.OrderBy(x => x.Rating);
 
             groupControl.AddGroups(numberOfGroups);
-            
+            _groups = new List<Group>();
             for (int i = 0; i < numberOfGroups; i++)
             {
                 _groups.Add(new Group());
@@ -97,7 +105,30 @@ namespace TournamentManager
                     groupIndex = 0;
                 }
                 _groups[groupIndex].Members.Add(participant);
+            }
 
+            foreach (var group in _groups)
+            {
+                var memberCount = group.Members.Count;
+                group.Matches = new int[memberCount, memberCount];
+            }
+        }
+        
+        private async void HandleOnComputePlayOffClicked(object sender, ComputeEventArgs e)
+        {
+            try
+            {
+                var toKeep = (int)Math.Round(((double)_participants.Count / (double)100) * (double)(100 - e.Amount), 0);
+                var sortedParticipants = (await ComputeAllGroupOrders()).Take(toKeep).ToList();
+                _playOff = new PlayOffTree(sortedParticipants);
+            }
+            catch (Exception ex)
+            {
+                // This throws the exception in a UI thread as not to get "swallowed"
+
+                // Invoke -> runs the code on the UI thread as soon as possible, finishes executing only after
+                // the code invoked on the UI thread is finished
+                Invoke(new Action(() => throw ex));
             }
         }
 
@@ -122,14 +153,11 @@ namespace TournamentManager
                 return;
             }
 
-            var match = _groups[e.GroupIndex].Matches.FirstOrDefault(m =>
-                e.FirstOpponent.Equals($"{m.Opponents.Item1.FirstName} {m.Opponents.Item1.Surname}") &&
-                e.SecondOpponent.Equals($"{m.Opponents.Item2.FirstName} {m.Opponents.Item2.Surname}"));
-            if (match == null )
-            {
-                return;
-            }
-            groupControl.SetTextBoxes(match.Scores);
+            var group = _groups[e.GroupIndex];
+            var firstOpponent = group.ExtractGroupMember(e.FirstOpponent);
+            var secondOpponent = group.ExtractGroupMember(e.SecondOpponent);
+            
+            groupControl.SetTextBoxes(group.GetScore(firstOpponent, secondOpponent));
         }
         
         private void HandleOnGroupControlSubmitClicked(object sender, MatchSelectedEventArgs e)
@@ -142,13 +170,50 @@ namespace TournamentManager
             var group = _groups[e.GroupIndex];
             Func<string[], Participant> matchOpponent = x => group.Members
                 .FirstOrDefault(p => p.FirstName.Equals(x[0]) && p.Surname.Equals(x[1]));
-
-            var firstOpponentName = e.FirstOpponent.Split(" ");
-            var secondOpponentName = e.SecondOpponent.Split(" ");
-            group.Matches.Add(new Match(new Tuple<Participant, Participant>
-                (matchOpponent(firstOpponentName), matchOpponent(secondOpponentName)),
-                e.Score ));
             
+            var firstOpponent = matchOpponent(e.FirstOpponent.Split(" "));
+            var secondOpponent = matchOpponent(e.SecondOpponent.Split(" "));
+            group.Matches[group.GetIndex(firstOpponent), group.GetIndex(secondOpponent)] = e.Score.first;
+            group.Matches[group.GetIndex(secondOpponent), group.GetIndex(firstOpponent)] = e.Score.second;
+        }
+        #endregion
+        
+        #region HelperFunctions
+        
+        private Task<List<Participant>> ComputeAllGroupOrders()
+        {
+            return Task.Factory.StartNew(() =>
+            {
+                return _groups.AsParallel().SelectMany(x => ComputeGroupOrder(x))
+                    .OrderByDescending(x => x.Item2)
+                    .ThenByDescending(x => x.Item3)
+                    .Select(x => x.Item1)
+                    .ToList();
+            }, TaskCreationOptions.None);
+
         }
+        
+        private List<Tuple<Participant, int, int>> ComputeGroupOrder(Group group)
+        {
+            return group.Members.Select(m =>
+            {
+                var memberCount = group.Members.Count;
+                var index = group.GetIndex(m);
+                var victories = 0;
+                var points = 0;
+                for (int i = 0; i < memberCount; i++)
+                {
+                    points += group.Matches[index, i];
+                    if (group.Matches[index, i] > group.Matches[i, index])
+                    {
+                        victories++;
+                    }
+                }
+
+                return new Tuple<Participant, int, int>(m, victories, points);
+            }).ToList();
+        }
+
+        #endregion
     }
 }
\ No newline at end of file
diff --git a/src/Match.cs b/src/Match.cs
index a3858392d159555246c13a88316fa087885b1306..30fe410cda96bd78f80626ce25e8fe7054da95b6 100644
--- a/src/Match.cs
+++ b/src/Match.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Security.Cryptography;
 
 namespace TournamentManager
 {
@@ -7,6 +8,7 @@ namespace TournamentManager
         public Tuple<Participant, Participant> Opponents { get; set; }
         public (int first, int second) Scores { get; set; }
 
+        public Match() { }
         public Match(Tuple<Participant, Participant> opponents, (int first, int second) scores)
         {
             if (opponents.Item1.Equals(opponents.Item2))
@@ -16,8 +18,6 @@ namespace TournamentManager
 
             Opponents = opponents;
             Scores = scores;
-
-
         }
     }
     
diff --git a/src/PlayOff.cs b/src/PlayOff.cs
deleted file mode 100644
index f1cd8f088c12693b8a1d5dd6d134f9f169428a93..0000000000000000000000000000000000000000
--- a/src/PlayOff.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace TournamentManager
-{
-    public class PlayOff
-    {
-        
-    }
-}
\ No newline at end of file
diff --git a/src/PlayOffTree.cs b/src/PlayOffTree.cs
new file mode 100644
index 0000000000000000000000000000000000000000..030f351cb441f0a5a41ec1e0d2cbd07bdded91ba
--- /dev/null
+++ b/src/PlayOffTree.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace TournamentManager
+{
+    public class PlayOffTree
+    {
+        public PlayOffTreeNode Root { get; }
+
+        public PlayOffTree( List<Participant> participants)
+        {
+            Root = ComputeTree(participants);
+        }
+
+        private PlayOffTreeNode ComputeTree(List<Participant> participants)
+        {
+            var depth = CalculateTreeDepth(participants.Count);
+            var unevenHalf = (int)Math.Pow(2, depth - 1);
+            var participantsUpper = participants.Take(unevenHalf).ToList();
+            var participantsLower = participants.Skip(unevenHalf).ToList();
+            return ComputeTreeStep(ref participantsUpper, ref participantsLower, depth);
+        }
+
+        private PlayOffTreeNode ComputeTreeStep(ref List<Participant> participantsUpper,
+            ref List<Participant> participantsLower, int depth)
+        {
+            var match = new Match();
+            var node = new PlayOffTreeNode(match);
+            switch (depth)
+            {
+                case 1:
+                {
+                    var upper = participantsUpper.Last();
+                    var lower = participantsLower.FirstOrDefault();
+                    match.Opponents = new Tuple<Participant, Participant>(upper, lower);
+                    participantsUpper.Remove(upper);
+                    participantsLower.Remove(lower);
+                    break;
+                }
+                default:
+                {
+                    node.PredecessorLeft = ComputeTreeStep(ref participantsUpper, ref participantsLower, depth - 1);
+                    node.PredecessorRight = ComputeTreeStep(ref participantsUpper, ref participantsLower, depth - 1);
+                    break;
+                }
+            }
+
+            return node;
+        }
+
+        private int CalculateTreeDepth(int minSize)
+        {
+            var size = 1;
+            while (size < minSize)
+            {
+                size *= 2;
+            }
+
+            return (int)Math.Log2(size);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/src/PlayOffTreeNode.cs b/src/PlayOffTreeNode.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ef6388f56ab336f1aa301579aadd2a4b27eb8666
--- /dev/null
+++ b/src/PlayOffTreeNode.cs
@@ -0,0 +1,17 @@
+using System;
+using TournamentManager.src;
+
+namespace TournamentManager
+{
+    public class PlayOffTreeNode
+    {
+        public Match TreeMatch { get; set; }
+        public PlayOffTreeNode PredecessorLeft { get; set; }
+        public PlayOffTreeNode PredecessorRight { get; set; }
+
+        public PlayOffTreeNode( Match match)
+        {
+            TreeMatch = match;
+        }
+    }
+}
\ No newline at end of file