diff --git a/rv_voting_calc/templates/rv_voting_calc/includes/option_list.html b/rv_voting_calc/templates/rv_voting_calc/includes/option_list.html
index 49acdf69f7841078f61bcacc1e70f1097cff11ec..642694ecd7aefc1e0f46716d9be6e5ab7c7b2b87 100644
--- a/rv_voting_calc/templates/rv_voting_calc/includes/option_list.html
+++ b/rv_voting_calc/templates/rv_voting_calc/includes/option_list.html
@@ -2,31 +2,33 @@
 
 <ul class="flex flex-col gap-2">
     {% for option_key, option in options.items %}
-        <h3 class="flex gap-2 items-end text-xl font-semibold">
-            {{ option_key }}
-            <span class="text-sm text-gray-600">
-                {{ option.ticket_count }} lístků, {{ option.vote_count }} hlasů
-            </span>
-            {% if show_has_support and not option.has_support %}
-                <span class="text-sm text-red-600">(Nemá nadpoloviční podporu)</span>
-            {% endif %}
-        </h3>
+        {% if option.has_support or show_has_support %}
+            <h3 class="flex gap-2 items-end text-xl font-semibold">
+                {{ option_key }}
+                <span class="text-sm text-gray-600">
+                    {{ option.ticket_count }} lístků, {{ option.vote_count }} hlasů
+                </span>
+                {% if show_has_support and not option.has_support %}
+                    <span class="text-sm text-red-600">(Nemá nadpoloviční podporu)</span>
+                {% endif %}
+            </h3>
 
-        {% if option.votes|length != 0 %}
-            <ul class="flex gap-3 mt-1">
-                {% for vote in option.votes %}
-                    <li class="flex">
-                        <div class="px-4 py-2 bg-gray-300">
-                            {{ vote.member }}
-                        </div>
-                        <ul class="px-4 py-2 flex gap-1 bg-gray-200">
-                            {% for option in options_by_member|index:vote.member %}
-                                <li>{{ option }}{% if not forloop.last %}, {% endif %}</li>
-                            {% endfor %}
-                        </ul>
-                    </li>
-                {% endfor %}
-            </ul>
+            {% if option.votes|length != 0 %}
+                <ul class="flex gap-3 mt-1 flex-wrap">
+                    {% for vote in option.votes %}
+                        <li class="flex">
+                            <div class="px-4 py-2 bg-gray-300">
+                                {{ rv_members|index:vote.member|index:"displayName" }}
+                            </div>
+                            <ul class="px-4 py-2 flex gap-1 bg-gray-200">
+                                {% for option in options_by_member|index:vote.member %}
+                                    <li>{{ option }}{% if not forloop.last %}, {% endif %}</li>
+                                {% endfor %}
+                            </ul>
+                        </li>
+                    {% endfor %}
+                </ul>
+            {% endif %}
         {% endif %}
     {% endfor %}
 </ul>
diff --git a/rv_voting_calc/templates/rv_voting_calc/steps/found_popularity_winner.html b/rv_voting_calc/templates/rv_voting_calc/steps/found_popularity_winner.html
new file mode 100644
index 0000000000000000000000000000000000000000..09738a53692c9e0ade2e236a00f5ff4a20fa0731
--- /dev/null
+++ b/rv_voting_calc/templates/rv_voting_calc/steps/found_popularity_winner.html
@@ -0,0 +1,3 @@
+<li class="bg-green-200 drop-shadow-md p-4 font-semibold text-center text-xl">
+    Možnost {{ option_key }} vyhrává s {{ option.vote_count }} hlasy.
+</li>
diff --git a/rv_voting_calc/templates/rv_voting_calc/steps/initial_sort.html b/rv_voting_calc/templates/rv_voting_calc/steps/initial_sort.html
index e93bb2ca594f605854e49a67a8e9455ac521daad..097d7606bc6f0f800cd4c3e79785fdaa9026fc47 100644
--- a/rv_voting_calc/templates/rv_voting_calc/steps/initial_sort.html
+++ b/rv_voting_calc/templates/rv_voting_calc/steps/initial_sort.html
@@ -7,5 +7,5 @@
         </small>
     </div>
 
-    {% include "rv_voting_calc/includes/option_list.html" with options=options options_by_member=options_by_member show_has_support=True %}
+    {% include "rv_voting_calc/includes/option_list.html" with options=options options_by_member=options_by_member show_proposers=True show_has_support=True %}
 </li>
diff --git a/rv_voting_calc/templates/rv_voting_calc/steps/no_winner.html b/rv_voting_calc/templates/rv_voting_calc/steps/no_winner.html
new file mode 100644
index 0000000000000000000000000000000000000000..bb9560d3854f8013c2868f1c0005164684b5fb62
--- /dev/null
+++ b/rv_voting_calc/templates/rv_voting_calc/steps/no_winner.html
@@ -0,0 +1,3 @@
+<li class="bg-red-200 drop-shadow-md p-4 font-semibold text-center text-xl">
+    Ani jedna možnost nevyhrává.
+</li>
diff --git a/rv_voting_calc/templates/rv_voting_calc/steps/removed_option.html b/rv_voting_calc/templates/rv_voting_calc/steps/removed_option.html
new file mode 100644
index 0000000000000000000000000000000000000000..8bd68a2ff1d86d021dfcda961c692d00b0fe9a59
--- /dev/null
+++ b/rv_voting_calc/templates/rv_voting_calc/steps/removed_option.html
@@ -0,0 +1,6 @@
+<li class="bg-gray-100 drop-shadow-md p-4">
+    <div class="pb-2 mb-2 border-b border-gray-300">
+        <h2 class="text-2xl font-semibold font-bebas">{{ iteration|add:1 }}. vyřazovací kolo</h2>
+    </div>
+    <p>Odstraněna {% if randomly %}(losováním){% else %}nepopulární{% endif %} možnost {{ option_key }}</p>
+</li>
diff --git a/rv_voting_calc/templates/rv_voting_calc/steps/with_support.html b/rv_voting_calc/templates/rv_voting_calc/steps/with_support.html
index c90da9e6b049643818658b21f66f8bb6ae77bb99..f40b5dfee2e03d8f9fac30fe51fdbee34ee2fdab 100644
--- a/rv_voting_calc/templates/rv_voting_calc/steps/with_support.html
+++ b/rv_voting_calc/templates/rv_voting_calc/steps/with_support.html
@@ -3,5 +3,9 @@
         <h2 class="text-2xl font-semibold font-bebas">Po vyřazení možností bez nadpoloviční podpory</h2>
     </div>
 
-    {% include "rv_voting_calc/includes/option_list.html" with options=options options_by_member=options_by_member %}
+    {% if options|length != 0 %}
+        {% include "rv_voting_calc/includes/option_list.html" with options=options options_by_member=options_by_member %}
+    {% else %}
+        <span class="text-gray-800 mt-1">Žádné možnosti nemají nadpoloviční podporu.</span>
+    {% endif %}
 </li>
diff --git a/rv_voting_calc/views.py b/rv_voting_calc/views.py
index 752108c77d7702124ecbcf4a9b3d4b243fde5ed6..9143bedf6a58d5e606fe6114fa281115cff3b06d 100644
--- a/rv_voting_calc/views.py
+++ b/rv_voting_calc/views.py
@@ -1,5 +1,6 @@
 import json
 import math
+import random
 
 import gql
 import requests
@@ -76,6 +77,257 @@ def index(request):
     )
 
 
+def do_step_b_through_d(
+    request,
+    iteration: int,
+    steps: list,
+    options: dict,
+    options_by_member: dict,
+    options_without_support: list,
+    rv_members: dict,
+    winner_treshold: int,
+) -> tuple:
+    ## BEGIN Step B
+
+    #print("start", options)
+
+    for option in options.values():
+        votes_to_remove = []
+
+        for vote_list_position, vote in enumerate(option["votes"]):
+            if vote.get("was_moved", False):
+                continue
+
+            for other_acceptable_option_position, other_acceptable_option in (
+                enumerate(options_by_member[vote["member"]])
+            ):
+                if not options[other_acceptable_option]["has_support"]:
+                    continue
+
+                if (
+                    other_acceptable_option_position >= vote["position"]
+                    and option["has_support"]
+                ):
+                    break
+
+                already_voted_for_acceptable_option = False
+
+                for other_acceptable_option_vote in options[other_acceptable_option]["votes"]:
+                    if other_acceptable_option_vote["member"] == vote["member"]:
+                        already_voted_for_acceptable_option = True
+
+                if already_voted_for_acceptable_option:
+                    votes_to_remove.append(vote_list_position)
+                    break
+
+                vote["was_moved"] = True
+                options[other_acceptable_option]["votes"].append(vote)
+
+                break
+
+        index_offset = 0
+
+        for vote_list_position in votes_to_remove:
+            option["votes"].pop(vote_list_position - index_offset)
+
+            index_offset += 1
+
+    for option_key in options_without_support:
+        options.pop(option_key)
+
+    if len(options) == 0:
+        steps.append(
+            render_to_string(
+                "rv_voting_calc/steps/no_winner.html",
+                {},
+                request=request,
+            )
+        )
+
+        return options, True
+
+    ## END Step B
+
+    ## BEGIN Step C
+
+    total_vote_count = 0
+    lowest_vote_count = math.inf
+    highest_vote_count = 0
+
+    for option in options.values():
+        if option["vote_count"] < lowest_vote_count:
+            lowest_vote_count = option["vote_count"]
+
+        if option["vote_count"] > highest_vote_count:
+            highest_vote_count = option["vote_count"]
+
+        total_vote_count += option["vote_count"]
+
+        # Remove was_moved for next iteration
+        option.pop("was_moved", None)
+
+    options = {
+        key: value
+        for key, value
+        in sorted(
+            options.items(),
+            reverse=True,
+            key=lambda option: option[1]["vote_count"],
+        )
+    }
+
+    found_winner = False
+    winners = []
+
+    # Try to find the most popular option
+    for option_key, option in options.items():
+        option["is_popularity_winner"] = (option["vote_count"] >= winner_treshold)
+
+        if option["is_popularity_winner"]:
+            found_winner = True
+            winners.append(option_key)
+
+    # If more than 1 winners, delete one randomly
+    if found_winner:
+        if len(winners) == 1:
+            steps.append(
+                render_to_string(
+                    "rv_voting_calc/steps/found_popularity_winner.html",
+                    {
+                        "option_key": winners[0],
+                        "option": options[winners[0]],
+                    },
+                    request=request,
+                )
+            )
+
+            return options, True
+        else:
+            winners_to_eliminate = random.choices(winners, k=len(winners) - 1)
+
+            for eliminated_winner in winners_to_eliminate:
+                steps.append(
+                    render_to_string(
+                        "rv_voting_calc/steps/removed_option.html",
+                        {
+                            "iteration": iteration,
+                            "option_key": eliminated_winner,
+                            "option": options[eliminated_winner],
+                            "randomly": True
+                        },
+                        request=request,
+                    )
+                )
+
+                del options[eliminated_winner]
+
+            steps.append(
+                render_to_string(
+                    "rv_voting_calc/steps/found_popularity_winner.html",
+                    {
+                        "option_key": winners[0],
+                        "option": options[winners[0]]
+                    },
+                    request=request,
+                )
+            )
+
+            return options, True
+
+    ## END Step C
+
+    ## BEGIN Step D
+
+    # If no most popular option was found, remove the least popular one
+    most_unpopular_options = []
+
+    for option_key, option in options.items():
+        if (
+            option["vote_count"] < highest_vote_count
+            and option["vote_count"] == lowest_vote_count
+        ):
+            most_unpopular_options.append(option_key)
+
+    if len(most_unpopular_options) == 1:
+        steps.append(
+            render_to_string(
+                "rv_voting_calc/steps/removed_option.html",
+                {
+                    "iteration": iteration,
+                    "option_key": option_key,
+                    "option": option
+                },
+                request=request,
+            )
+        )
+
+        del options[most_unpopular_options[0]]
+
+        if len(options) > 1:
+            # Continue through to next loop
+            return options, False
+
+        steps.append(
+            render_to_string(
+                "rv_voting_calc/steps/found_popularity_winner.html",
+                {
+                    "option_key": option_key,
+                    "option": option
+                },
+                request=request,
+            )
+        )
+
+        return options, True
+
+    # Remove options with least tickets
+    min_unpopular_option_ticket_count = math.inf
+
+    for unpopular_option in most_unpopular_options:
+        if options[unpopular_option]["ticket_count"] < min_unpopular_option_ticket_count:
+            min_unpopular_option_ticket_count = options[unpopular_option]["ticket_count"]
+
+    unpopular_options_to_remove = []
+
+    for unpopular_option in most_unpopular_options:
+        if options[unpopular_option]["ticket_count"] == min_unpopular_option_ticket_count:
+            unpopular_options_to_remove.append(unpopular_option)
+
+    for option in unpopular_options_to_remove:
+        steps.append(
+            render_to_string(
+                "rv_voting_calc/steps/removed_option.html",
+                {
+                    "iteration": iteration,
+                    "option_key": option,
+                    "option": options[option]
+                },
+                request=request,
+            )
+        )
+
+        del options[option]
+
+    ## END Step D
+
+    if len(options) == 0:
+        steps.append(
+            render_to_string(
+                "rv_voting_calc/steps/no_winner.html",
+                {},
+                request=request,
+            )
+        )
+
+        return options, True
+
+    #print(options)
+    #import time
+    #time.sleep(1)
+
+    return options, False
+
+
 def get_calculated_votes(request):
     options_by_member = request.GET.get("votes")
 
@@ -118,7 +370,8 @@ def get_calculated_votes(request):
 
     # END Input validation
 
-    # BEGIN Sorting
+    ## BEGIN Step A
+    # Sorting
 
     steps = []
 
@@ -144,6 +397,7 @@ def get_calculated_votes(request):
                     "ticket_count": 0,
                     "vote_count": 0,
                     "points": 0,
+                    "is_popularity_winner": False,
                     "votes": [],
                     "has_support": False
                 }
@@ -160,19 +414,17 @@ def get_calculated_votes(request):
 
             option_is_ticket = False
 
-    # END Sorting
-
-    # BEGIN Filtering out options without enough support and figuring out
+    # Filtering out options without enough support and figuring out
     # the most popular options
 
-    options_to_remove = []
+    options_without_support = []
 
     for option_key, option in options.items():
         if option["vote_count"] >= has_support_treshold:
             option["has_support"] = True
 
         if not option["has_support"]:
-            options_to_remove.append(option_key)
+            options_without_support.append(option_key)
             continue
 
         option["points"] += option["ticket_count"] * (max_vote_position + 1)
@@ -194,52 +446,26 @@ def get_calculated_votes(request):
         )
     }
 
-    for option in options.values():
+    first_step_options = options.copy()
+
+    for option in first_step_options.values():
         votes_to_remove = []
 
         for vote_list_position, vote in enumerate(option["votes"]):
-            if vote.get("was_moved", False):
-                continue
-
-            for other_acceptable_option_position, other_acceptable_option in (
-                enumerate(options_by_member[vote["member"]])
-            ):
-                if not options[other_acceptable_option]["has_support"]:
-                    continue
-
-                if (
-                    other_acceptable_option_position >= vote["position"]
-                    and option["has_support"]
-                ):
-                    break
-
-                already_voted_for_acceptable_option = False
-
-                for other_acceptable_option_vote in options[other_acceptable_option]["votes"]:
-                    if other_acceptable_option_vote["member"] == vote["member"]:
-                        already_voted_for_acceptable_option = True
-
-                if already_voted_for_acceptable_option:
-                    votes_to_remove.append(vote_list_position)
-                    break
-
-                vote["was_moved"] = True
-                options[other_acceptable_option]["votes"].append(vote)
-
-                break
+            if vote["position"] != 0:
+                votes_to_remove.append(vote_list_position)
 
         index_offset = 0
 
         for vote_list_position in votes_to_remove:
             option["votes"].pop(vote_list_position - index_offset)
-
             index_offset += 1
 
     steps.append(
         render_to_string(
             "rv_voting_calc/steps/initial_sort.html",
             {
-                "options": options,
+                "options": first_step_options,
                 "options_by_member": options_by_member,
                 "rv_members": rv_members,
                 "total_ticket_count": total_ticket_count,
@@ -249,8 +475,7 @@ def get_calculated_votes(request):
         )
     )
 
-    for option_key in options_to_remove:
-        options.pop(option_key)
+    del first_step_options
 
     steps.append(
         render_to_string(
@@ -264,50 +489,24 @@ def get_calculated_votes(request):
         )
     )
 
-    # END Filtering out options without enough support and figuring out
-    # the most popular options
-
-    return HttpResponse("\n".join(steps))
-
-    #acceptable_options = []
-    #voting_member_count = len(options_by_member)
-
-    #for option, members in members_by_option.items():
-        #if len(members) >= math.floor(voting_member_count * 0.5):
-            #acceptable_options.append(option)
-
-    #steps = []
-
-    #if len(acceptable_options) == 0:
-        #result = {
-            #"type": "final:no_acceptable_options",
-            #"voting_member_count": voting_member_count,
-            #"options": [],
-        #}
+    ## END Step A
 
-        #for option, members in members_by_option.items():
-            #result["options"].append({
-                #"name": option,
-                #"vote_count": len(members),
-            #})
+    iteration = 0
 
-        #steps.append(result)
-
-        #return JsonResponse(steps, safe=False)
-
-    #acceptable_options_step = {
-        #"type": "progress:acceptable_options",
-        #"voting_member_count": voting_member_count,
-        #"options": []
-    #}
-
-    #for option, members in members_by_option.items():
-        #if option in acceptable_options:
-            #acceptable_options_step["options"].append({
-                #"name": option,
-                #"vote_count": len(members),
-            #})
+    while True:
+        options, ended = do_step_b_through_d(
+            request,
+            iteration,
+            steps,
+            options,
+            options_by_member,
+            options_without_support,
+            rv_members,
+            has_support_treshold,
+        )
 
-    #steps.append(acceptable_options_step)
+        if ended:
+            return HttpResponse("\n".join(steps))
 
-    # END   Acceptable options
+        # Step E
+        iteration += 1