Simon game / Four tiles game
Missing the specs

You're missing a very important rule of the game:


  The pattern gets longer each time the player completes the pattern. If the player presses a wrong button, the game ends.


You implemented only a one-shot round, which is not so interesting.

Mutually exclusive conditions

These conditions are mutually exclusive:


if n == 1:
    # ...
if n == 2:
    # ...
if n == 3:
    # ...



So you should use elif for the 2nd and later conditions.

Use consistent names

It's odd to name some constants with all caps, and others with all lowercase like this:


WHITE = (255, 255, 255)
RED = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)



Be consistent, name all of them all caps!

Avoid hard-coding

This function relies on having 4 buttons:


def generate_correct_sequence(length):
    return [random.randint(1, 4) for _ in range(length)]



It would be better to avoid hardcoding the number 4.
You could for example use len(COLORS) instead.
Even better would be to use a dedicated constant,
and derive both the elements of colors from it,
and use it everywhere else where it's relevant, as in this function.

Use local variables to explain logic

In this code:


if mouse_pos[0] &lt; WIDTH / 2 and mouse_pos[1] &lt; HEIGHT / 2:
    return 1

if mouse_pos[0] &gt; WIDTH / 2 and mouse_pos[1] &lt; HEIGHT / 2:
    return 2
# ...



mouse_pos[0] and mouse_pos[1] are repeated many times,
which is tedious, and not as clear as it can be.
I don't actually have tkinter now,
but I'm guessing these stand for x and y coordinates.

I would either change the method to take parameters named x and y,
or introduce the local variables x and y early in the method:

x = mouse_pos[0]
y = mouse_pos[1]


The rest of the code would become shorter, and clearer.

Why not use 0-base indexing everywhere?

This method is slightly more complex than it needs to be due to the 1-based indexing:


def draw_buttons():
    for i in range(1, 5):
        draw_button(i, COLORS[i - 1])



I bet you could change to this simpler implementation,
and adjust the rest of the code to work with it without sacrificing anything:

def draw_buttons():
    for i in range(4):
        draw_button(i, COLORS[i])


Notice the hardcoded number 4 again. This highlights again the importance to avoid hardcoding. The range(1, 5) came from the fact of the hard limit 4,
and if you decided to change 4 at some point, searching in the code for "4" you would never find range(1, 5).

So, really, replace the number 4 with a constant. len(COLORS) may look tempting, but as I explained above, I suggest to use something else as the single authoritative point of control.