Matching Game: Pygame Memory in 126 Lines
A memory matching game is the simplest thing you can build in Pygame that still feels like a game. Sixteen cards in a four by four grid. Eight unique images, each appearing twice. Click a card to flip it. Click another. If they match, they stay face up. If they do not, they flip back after half a second. Win when all eight pairs are found.
The Card Generation
The clever part is also the simplest. Load eight images into a list. Duplicate the list so each image has a twin. Shuffle the combined list with random.shuffle. Assign each entry to one of sixteen card objects with a position, a reference to the image, and a boolean for revealed state. The grid is implicit. Card zero is top left. Card three is top right. The math to position them on screen is index multiplied by card size plus padding.
The shuffle is the entire game. A deterministic grid would be solvable by memory of positions alone. The random order forces the player to actually remember what they saw.
The Match Check
The Game class tracks selected cards. When the count hits two, check_match compares their image attributes. A match increments the pair counter and leaves both cards revealed. A mismatch calls pygame.time.wait(500) to give the player a moment to see the second card before hiding both.
The wait blocks the entire game loop for half a second. It works because nothing else happens during those five hundred milliseconds. Animations or sound effects would need a timer-based approach instead of a blocking delay.
What I Would Change
There is no restart button. Closing and relaunching is the only way to play again. There are no sound effects, no flip animation, no difficulty options, and no visual feedback beyond the card images themselves. The card backs are blue rectangles with a question mark drawn in text.
It is 126 lines of Pygame that compiles to a working memory game. That is exactly as much code as it needed and no more.