Integration of logic in code

Hello!

I am an absolute Python beginner… so maybe someone can help me with my problem:

I have a code where each two images (emblems) of sports teams are compared, and the user has to choose which team is better. In this process, each team competes against each other and the winner gets a point. After all duels are completed, a ranking is output based on the points scored.

This works quite well for a few teams, but when there are more, it gets to a number of duels that is not manageable for one user. Therefore, I would like to change the code to integrate some kind of logic that “unnecessary” duels, where the winner is already determined based on previous results, are omitted and the already determined winner automatically gets a point.

For example: team 1 wins against team 2, team 3 wins against team 4 and team 1 wins against team 3. So it is clear that team 1 also wins against team 4, so this duel should be omitted. The goal is to create a ranking with as few duels as possible. Can someone please help me change the code accordingly?

My code is as follows:

import random
from itertools import combinations
import tkinter as tk
from pathlib import Path
from PIL import ImageTk, Image

Path to the folder with the images

FOLDER_PATH = Path(“D:/Images”)

class GUI:
def init(self):
image_files = list(FOLDER_PATH.iterdir())
self.image_pairs = list(combinations(image_files, 2))
random.shuffle(self.image_pairs)
self.scores = {}
for image in image_files:
self.scores[image.name] = 0
self.selected_images = None

    self.root = tk.Tk()
    self.root.title("Image comparison")
    self.label1 = tk.Label(self.root)
    self.label2 = tk.Label(self.root)
    self.label1.pack(side=tk.LEFT)
    self.label2.pack(side=tk.RIGHT)

    self.total_pairs = len(self.image_pairs)
    self.progress_frame = tk.Frame(self.root)
    self.progress_frame.pack(side=tk.BOTTOM, pady=10)
    tk.Label(self.progress_frame, text="Progress:", font=("Arial", 12)).pack(side=tk.LEFT)
    self.progress_label = tk.Label(self.progress_frame, text=f"0/{self.total_pairs} (0%)", font=("Arial", 12))
    self.progress_label.pack(side=tk.LEFT)

    self.root.bind("<Left>", lambda event: self.select_image(0))
    self.root.bind("<Right>", lambda event: self.select_image(1))
    self.show_next_images()

def select_image(self, number):
    self.scores[self.selected_images[number].name] += 1
    self.show_next_images()

def show_next_images(self):
    if not self.image_pairs:
        self.label1['image'] = None
        self.label2['image'] = None
        print("All image pairs were loaded")
        return

    self.selected_images = self.image_pairs.pop()
    progress = self.total_pairs - len(self.image_pairs)
    self.progress_label.config(
        text=f"{progress}/{self.total_pairs} ({progress / self.total_pairs:.0%})")
    self.load_image(self.label1, self.selected_images[0])
    self.load_image(self.label2, self.selected_images[1])

def load_image(self, label, imagefile):
    image = Image.open(imagefile)
    # resize the image to a maximum of 800x800 while keeping the aspect ratio
    max_size = (800, 800)
    image.thumbnail(max_size, Image.LANCZOS)
    photo = ImageTk.PhotoImage(image)
    label['image'] = photo
    label.image = photo

def main():
gui = GUI()
gui.root.mainloop()

# Output of the points list
print("Points list:")
for image, score in sorted(gui.scores.items(), key=lambda x: x[1], reverse=True):
    print(f"{image}: {score}")

if name == “main”:
main()

1 Like

Let’s model your problem as a graph G, with a vertex for each team and directed edges x\to y to indicate that team x is better than team y.

Your example suggests that you are looking at the concept of transitive closure. You want that if x\to y\to z, then x\to z. Like in the transitive property of inequalities, if a>b>c, then a>c.

So, after each input from the user, you can compute the transitive closure of the graph with the newly added edge. Then you can ask the user for “who wins?” between two vertices that don’t have an edge between them, since those are the pairs of teams for which we don’t know who is better among them.

Networkx has transitive closure implemented. So, you could use it.

Actually, since the the graph will always get updated from a graph that was initially transitive, the problem is simpler than calling the full transitive closure every time.

Suppose that you have the directed transitive graph G (at the beginning this will be all the teams and no edges between them). Then the user inputs the edge x\to y (they said that x wins over y). You go over all pairs of vertices u,v of the graph. If the edge u\to v exists, we do nothing. If not, then we check if u\to x and y\to v exist. If those to edges exist, then we add the edge u\to v. Otherwise we do nothing to the pair of vertices u,v. After going over all pairs of vertices, we got the transitive closure of the updated graph.

Thank you for the reply! So how would the code look like?

# G is a directed graph with a vertex for each team
# It begins with no edges. A directed edge (u,v) will mean that team u is better than team v.
# We only stop when for all vertices u,v either the edge (u,v) or (v,u) is in the graph G.
while there is u,v such that neither (u,v) nor (v,u) are edges of G:
  ask user which team, u or v, is better
  if user says u:
    insert edge (u,v) in G
  elif says v is better:
    insert edge (v,u) in G
    # Let me assume that we did this step by swapping the names u and v
    # and inserting the edge (u,v) in G
  else:
    # I don't know if you want to consider incomparable teams or not
  # Making G transitively closed
  for each edge (x,y) in G:
    if (x,u) and (y,v) are both edges in G:
      insert edge (x,y) in G.

Thanks a lot for your answer!

But where do I insert this code? The following error message is displayed:

while there is u,v such that neither (u,v) nor (v,u) are edges of G:

What I wrote is not Python code, but pseudocode. To turn it into Python code you must choose how you are going to implement the graph G, how to check for and insert edges, etc.

I don’t really know how to do this… I’m an absolute beginner… :thinking:

Stepping back a bit, what you’re trying to do is to sort the teams with a minimum of comparison operations between teams. Sorting is an extremely famous problem in computer science and Python has a built-in sort() function implementing one of the possible efficient strategies. In particular, check out Sorting HOW TO — Python 3.11.3 documentation

2 Likes