{"id":"pygame-first-window","slug":"first-window","title":"A window of your own","text":"So far your programs have printed text and read what the user types. In this part you'll write programs with **graphics**: a window with pictures in it that move and react to the keyboard and the mouse. The tool for it is **pygame**, a library for writing games in Python. A **library** is a collection of modules that someone else has written for you to use. Unlike `math` and `random`, pygame doesn't come with Python: on your own computer you'd install it first with the command `pip install pygame-ce` (pygame-ce is the actively developed edition of pygame, and programs still say `import pygame`). On this site there's nothing to install. The site runs pygame for you and shows its window on the page.\n\n### A first window\n\nHere is a complete pygame program. It opens a window and fills it with dark blue:\n\n```python\nimport pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 120))\n    pygame.display.flip()\n```\n\n```window-shot\n{\"image\":\"lessons/windows/eebb0c026fb61b66.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":30,\"log\":\"fill (0, 0, 120)\",\"ended\":\"closed\",\"code\":\"import pygame\\n\\npygame.init()\\nwindow = pygame.display.set_mode((320, 240))\\n\\nwhile True:\\n    for event in pygame.event.get():\\n        if event.type == pygame.QUIT:\\n            exit()\\n\\n    window.fill((0, 0, 120))\\n    pygame.display.flip()\\n\",\"window\":{\"frames\":30,\"events\":[]}}\n```\n\nLine by line:\n\n- `import pygame` takes the library into use, and `pygame.init()` starts its parts. Call it once, at the start of the program.\n- `pygame.display.set_mode((320, 240))` opens a window 320 pixels wide and 240 pixels high. A **pixel** is one dot of the picture. Note the two pairs of parentheses: the size is one tuple, `(320, 240)`. The function returns the window, and the variable `window` keeps it, so that the program can draw in it.\n- `while True:` starts the **main loop**. A game runs until the player closes it, so its loop never ends on its own.\n- `pygame.event.get()` returns a list of the **events** that have happened since the program last asked: key presses, mouse clicks, and a click on the window's close button. Closing the window is an event of the type `pygame.QUIT`, and `exit()` ends the program right there. Without these lines the close button would do nothing.\n- `window.fill((0, 0, 120))` paints the whole window with one color.\n- `pygame.display.flip()` shows what has been drawn. The drawing happens out of sight, and `flip` shows the finished picture all at once, so the player never sees a half-drawn one. Each picture shown is a **frame**.\n\nSo every round of the main loop does three things: it handles the events, draws the picture and shows it. Here the picture is the same in every frame. In the next module it changes a little from one frame to the next, and that's animation.\n\nYou may see pygame programs that draw their picture once, before the main loop, and then only wait for events. That works here too: the window keeps showing that picture until it's closed. But games redraw in every round, because their picture changes, and the programs in these lessons do the same from the start.\n\n### Colors\n\nA color is a tuple of three numbers from 0 to 255: how much **red**, **green** and **blue** light it has. It's called an **RGB** color.\n\n| Color | RGB |\n|---|---|\n| black | `(0, 0, 0)` |\n| white | `(255, 255, 255)` |\n| red | `(255, 0, 0)` |\n| green | `(0, 255, 0)` |\n| blue | `(0, 0, 255)` |\n| yellow | `(255, 255, 0)` |\n| gray | `(128, 128, 128)` |\n\nThe colors mix like light, not like paint: red and green light together make yellow. Smaller numbers make darker colors, so `(0, 0, 120)` is a dark blue.\n\npygame also knows the names of many colors. `pygame.Color` turns a name into its RGB numbers:\n\n```python\nimport pygame\n\norange = pygame.Color(\"orange\")\nprint(orange)\nprint(orange.r, orange.g, orange.b)\n```\n\n```output\nColor(255, 165, 0, 255)\n255 165 0\n```\n\nThe fourth number is the color's **alpha**, how solid it is: 255 means not see-through at all. `window.fill(\"orange\")` works too, but with RGB numbers you can mix any color you like.\n\n### The window on this site\n\nThe window here has no screen of its own. The site runs your program for a number of frames and then closes the window: the program gets a `pygame.QUIT` event, and `exit()` ends it. Press Play under an example to watch its frames.\n\nThe site also keeps **the window as text**: a line for each thing drawn in the window since it was last filled with one color. The window above, as text, is:\n\n```text\nfill (0, 0, 120)\n```\n\nThe checks of a challenge compare the last frame of your window, as text, with the model solution's, and they compare how many frames it showed. That's what \"Your window should end like this\" on a task card is: the window your program should end with. Open \"The window as text\" under its picture to see exactly what your program should draw.\n","task":"Fill in the two blanks so the program fills the window with green, `(0, 160, 0)`, and shows it, frame after frame.\n","kind":"fill","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.[[fill]]((0, 160, 0))\n    pygame.display.[[flip]]()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 160, 0))\n    pygame.display.flip()\n","hints":["The first blank is the method that paints the whole window with one color. The second shows the finished picture.","The window's method is `fill`, and the function that shows a frame is `pygame.display.flip`."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":10,"events":[]},"expectWindow":{"frames":10,"log":"fill (0, 160, 0)","size":[320,240],"title":"pygame window","image":"lessons/windows/58e6d85cf37b40f3.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":25,"events":[]},"expectWindow":{"frames":25,"log":"fill (0, 160, 0)","size":[320,240],"title":"pygame window","image":"lessons/windows/58e6d85cf37b40f3.png"},"expect":"","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Write a whole pygame program yourself. It opens a window 400 pixels wide and 300 pixels high and fills it with orange, `(255, 140, 0)`, on every frame. Handle `pygame.QUIT` in the main loop, so that closing the window ends the program.\n\nThe window as text doesn't include the window's size, so the check looks for the size in your code: the numbers 400 and 300, with the width first if you write them as one tuple.\n","kind":"code","seed":"# A 400 x 300 window, orange, until it's closed.\nimport pygame\n","solution":"# A 400 x 300 window, orange, until it's closed.\nimport pygame\n\npygame.init()\nwindow = pygame.display.set_mode((400, 300))\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((255, 140, 0))\n    pygame.display.flip()\n","hints":["Start the program as the lesson does: `pygame.init()`, then `set_mode` with the size as one tuple, `(400, 300)`.","The main loop is `while True:`. In it, a `for` loop goes through `pygame.event.get()` and calls `exit()` when an event's `type` is `pygame.QUIT`.","After the event loop, still inside `while True:`, fill the window with the color and call `pygame.display.flip()`."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":20,"events":[]},"expectWindow":{"frames":20,"log":"fill (255, 140, 0)","size":[400,300],"title":"pygame window","image":"lessons/windows/6ce9616073cea972.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":7,"events":[]},"expectWindow":{"frames":7,"log":"fill (255, 140, 0)","size":[400,300],"title":"pygame window","image":"lessons/windows/6ce9616073cea972.png"},"expect":"","hidden":true}],"require":[{"pattern":"\\b400\\b[\\s\\S]*\\b300\\b|\\b300\\b[\\s\\S]*\\b400\\b","message":"Make the window 400 pixels wide and 300 high: `pygame.display.set_mode((400, 300))`."},{"pattern":"pygame\\.QUIT","message":"Handle the `pygame.QUIT` event, so that closing the window ends the program."}],"forbid":[{"pattern":"[(\\[]\\s*300\\s*,\\s*400\\s*[)\\]]","message":"The size is (width, height), so the width comes first: a window 400 wide and 300 high is `(400, 300)`."}]},{"task":"This program should fill a 320 x 240 window with white, but it stops with an error. Run it and read the message, fix that line, and then fix the next error the same way. Keep the window's size: the check finds it in your code, as in the challenge before.\n","kind":"code","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode(320, 240)\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill(255, 255, 255)\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((255, 255, 255))\n    pygame.display.flip()\n","hints":["The first message is `TypeError: size must be two numbers`. `set_mode` takes the size as one value, a tuple, but here it gets two separate numbers.","Put the size in its own parentheses: `set_mode((320, 240))`.","`fill` has the same problem. Given three numbers, it reads the second one as a rectangle to fill (`invalid rectstyle object`). The color is one tuple too."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":12,"events":[]},"expectWindow":{"frames":12,"log":"fill (255, 255, 255)","size":[320,240],"title":"pygame window","image":"lessons/windows/4d36330b54bd6d41.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":5,"events":[]},"expectWindow":{"frames":5,"log":"fill (255, 255, 255)","size":[320,240],"title":"pygame window","image":"lessons/windows/4d36330b54bd6d41.png"},"expect":"","hidden":true}],"require":[{"pattern":"\\b320\\b[\\s\\S]*\\b240\\b|\\b240\\b[\\s\\S]*\\b320\\b","message":"Keep the window 320 pixels wide and 240 high: `pygame.display.set_mode((320, 240))`. Without a size, pygame opens a window of its own default size."}],"forbid":[{"pattern":"[(\\[]\\s*240\\s*,\\s*320\\s*[)\\]]","message":"The size is (width, height), so the width comes first: a window 320 wide and 240 high is `(320, 240)`."}]}]}