Games Computer Play

Spring 2025

Program 2: lotsa lists! (maze escape)

Due: Friday, March 7 at 5pm


Game Overview

We are implementing a maze-escape game featuring several different lists and a maze that is read from a file.

The player tries to reach an exit and avoid colliding with any NPCs. There can be more than one NPC, more than one exit, and even more than one player (see below).

The player cannot go through walls nor go past the edges of the screen (in the supplied maze, the edges all have walls or exits). The player moves in the cardinal directions using the arrow keys. The player wins if they reach an exit. The player loses if they collide with an NPC (regardless of which instigated contact).

The player may have one or more clones. The idea is that the human player can control one of the clones at any time; clicking on a clone switches control to that clone. The player controls the “active clone” which should be a similar yet distinguished color from the clone color. (In my example, clones are blue; the active player is cyan.)

NPCs move randomly, including diagonally. They cannot move past the edges of the screen. The cannot move through exits or through passive (inactive) clones (players that are not currently being controlled). If they move into the active player, the player loses. More interestingly, NPCs can move through walls - ghost-like.

Walls are fixed and do not change during game play. The row-columns dimensions of the graphics window, locations of walls and exits, and initial locations of players and NPCs are determined by a text file (see the supplied map.txt) - and see below.


general instructions


step-by-step instructions

  1. Read the code, try the code as it stands. Out of the box, the player can move to the right; the map is partially read, exits are drawn. But that’s it.

After each step below, try your work! Test your changes frequently!

The first phase is to get the player to move (the other directions) and be able to exit. At this point, assume we have only one player - and its location is stored in the 0th index of the g_players variable (g_players is a list of points).

  1. Examine handle_player_events and move_player - modify both so that the other arrow keys can be used to move the player. The idea is that move_player is called with two numbers - one representing how the player’s x-coordinate should change; the other for the y-coordinate.

  2. Winning: modify game_loop so that if the player’s location is in the list of exits then the player wins. Call the supplied game_over function and use break to leave the loop.

The next phase of implementation is to get the map to (mostly) display properly: so, in addition to exits, walls and NPCs should be read. Until you get past this phase; use the supplied map file.

  1. Modify parse_map so that every time an npc symbol (N) is encountered, an x-y coordinate pair is appended to the list of NPCs (g_npc) - follow the example use for exits. Modify draw_map to show all the NPCs - again, follow the example used to display the exits.

  2. Losing: Modify game_loop so that if the player’s location is in the list of NPCs then the player loses. (Follow model for winning.)

  3. Modify parse_map so that every time a wall symbol (#) is encountered, the g_walls list of lists is modified so that value at row y, column x is set to be true - representing the presence of a wall at that location. Modify draw_map to use nested loops to show all walls.

  4. Modify move_player so that the player cannot move through walls. (With the supplied map and the artifical starting point, the player should be unable to move until the next step.)

  5. Modify initialize so that g_players starts as an empty list (rather than at [(0, 0)]). Modify parse_map so that every time a player symbol (P) is encountered, an x-y coordinate pair is appended to the list of players (g_players) - follow the example use for exits and npcs. Modify draw_map to show all the players (clones).

At this point the game should be somewhat playable - the full map gets displayed; you can win and lose (by running into the currently immobile NPCs); you cannot move through walls.

  1. Copy the file map.txt to original-map.txt. Edit the contents of map.txt to be significantly different than the original. (Later, you may wish to adjust your newly created map to make the game more or less challenging.)

  2. Modify move_npcs so that each time the function is called each NPC moves. A skeleton of a loop for achieving that is supplied; you need to modify the loop’s body so that each NPC actually moves. You can use a model similar to previous assignments and exercises - randomly pick values (-1, 0 or 1) to change the x and y coordinates for each NPC. You can use code similar to what is in move_player to prevent NPCs from moving past edges or from moving through exits or moving through clones (players). For now, like the player, have NPCs be blocked by walls.

  3. Modify move_npcs and game_loop so that if an NPC moves into the active player (at this point that is still just g_players[0]) then the player loses. move_npcs needs to allow the move to happen; game_loop should cause the game_over to be called following previous parts of the assignment.

At this point, assuming you have thoroughly tested your code, you will met the minimal requirements. But do not stop here!

  1. Modify move_npcs so that NPCs can move like ghosts - through walls. (They should still be prevented from moving through passive clones and exits.) The basic change is easy… but it can have the unintended side effect of making it look like the wall has been eaten (disappeared) by the NPC. To prevent that, check if the space that the npc moves away from has a wall, if so, redraw the wall there rahter than unpainting the npc.

  2. Modify verify_quit so that if the player presses q, the status bar is used to ask the player if they truly want to quit; it should wait for a key, if that is a y then quitting can proceed (using the new raise SystemExit feature); but if not the status bar should be cleared and the game should resume (which will happen automatically by not having the program exit).

Finally, let’s make the clones work.

  1. Add a new global variable to initialize called g_active_player. Intialize it to be None. Write a new function called select_player which should get a mouse click and if that point is in the g_players list then it should change g_active_player to be the index (position) in that list which corresponds to the point clicked on. Modify initialize so that before that function ends, it repeatedly calls select_player until g_active_player is no longer None. You should use a status-bar message to tell the player they need to click on a player square to begin and then clear the status bar once they have. You need to modify all the places in your code (move_player, game_loop, move_npcs) that previously used g_players[0] so that the game works to move - and to allow winning and losing - based on the activated player. Create separate colors to distinguish the active player from the passive clones, adjust select_player and move_player accordingly.

  2. Modify handle_player_events so that if a key has not been pressed but the mouse has been clicked, then select_player is called; at this point it does not matter if the player clicks on something other than a palyer square, it can just be ingored - it shoudl not loop until they do. Important you no longer want to wait for a key in handle_player_events (think about why); so you need to modify the function so that it processes keys if one has been pressed and processes mouse clicks if the mouse has been clicked. This may make the game no longer be turn based - meaning suddently the NPCs may move blazingly fast. You have two choice heres - either add code to handle_player_events so that it always waits for either a key press or mouse click (thus restoring the game to its turn-based form); or add code in other parts of the program that are similar to how you handled interacivity for the previous assignment - so that NPCs move, but neither too fast nor too slow. (Recommended: keep it turn based.)

At this point you have built the full game! (Remove or adjust code that you have left in for testing purposes. Remove my comments that tell you where you need to work.)

  1. Remember to put a title, description and status update in the comments atop the program.