From ade293719f70c5f9b2732579dfc7ed84ac3a3979 Mon Sep 17 00:00:00 2001 From: Arjun Patel Date: Wed, 20 Feb 2019 15:24:24 -0800 Subject: [PATCH] getting right starter files --- VERSION | 2 +- autograder.py | 147 ++-- commands.txt | 21 - eightpuzzle.py | 281 ------ game.py | 267 +++--- ghostAgents.py | 58 +- grading.py | 431 ++++----- graphicsDisplay.py | 345 +++++--- graphicsUtils.py | 135 ++- keyboardAgents.py | 45 +- layout.py | 68 +- layouts/bigCorners.lay | 37 - layouts/bigMaze.lay | 37 - layouts/bigSafeSearch.lay | 8 - layouts/bigSearch.lay | 15 - layouts/boxSearch.lay | 14 - layouts/contoursMaze.lay | 11 - layouts/greedySearch.lay | 8 - layouts/mediumCorners.lay | 14 - layouts/mediumDottedMaze.lay | 18 - layouts/mediumMaze.lay | 18 - layouts/mediumSafeSearch.lay | 6 - layouts/mediumScaryMaze.lay | 18 - layouts/mediumSearch.lay | 8 - layouts/oddSearch.lay | 7 - layouts/openMaze.lay | 23 - layouts/openSearch.lay | 7 - layouts/smallMaze.lay | 10 - layouts/smallSafeSearch.lay | 15 - layouts/smallSearch.lay | 5 - layouts/testMaze.lay | 3 - layouts/testSearch.lay | 5 - layouts/tinyCorners.lay | 8 - layouts/tinyMaze.lay | 7 - layouts/tinySafeSearch.lay | 7 - layouts/tinySearch.lay | 7 - layouts/trickySearch.lay | 7 - multiAgents.py | 178 ++++ multiagentTestClasses.py | 578 ++++++++++++ pacman.py | 334 ++++--- pacmanAgents.py | 29 +- projectParams.py | 8 +- search.py | 119 --- searchAgents.py | 542 ------------ searchTestClasses.py | 823 ------------------ submission_autograder.py | 2 +- testClasses.py | 18 +- testParser.py | 3 +- test_cases/CONFIG | 2 +- test_cases/{q7 => extra}/CONFIG | 3 +- test_cases/extra/grade-agent.test | 11 + test_cases/q1/CONFIG | 4 +- test_cases/q1/grade-agent.solution | 2 + test_cases/q1/grade-agent.test | 18 + test_cases/q1/graph_backtrack.solution | 7 - test_cases/q1/graph_backtrack.test | 32 - test_cases/q1/graph_bfs_vs_dfs.solution | 7 - test_cases/q1/graph_bfs_vs_dfs.test | 30 - test_cases/q1/graph_infinite.solution | 7 - test_cases/q1/graph_infinite.test | 30 - test_cases/q1/graph_manypaths.solution | 7 - test_cases/q1/graph_manypaths.test | 39 - test_cases/q1/pacman_1.solution | 40 - test_cases/q1/pacman_1.test | 27 - .../q2/0-eval-function-lose-states-1.solution | 3 + .../q2/0-eval-function-lose-states-1.test | 30 + .../q2/0-eval-function-lose-states-2.solution | 3 + .../q2/0-eval-function-lose-states-2.test | 30 + .../q2/0-eval-function-win-states-1.solution | 3 + .../q2/0-eval-function-win-states-1.test | 30 + .../q2/0-eval-function-win-states-2.solution | 3 + .../q2/0-eval-function-win-states-2.test | 30 + test_cases/q2/0-lecture-6-tree.solution | 3 + test_cases/q2/0-lecture-6-tree.test | 50 ++ test_cases/q2/0-small-tree.solution | 3 + test_cases/q2/0-small-tree.test | 36 + test_cases/q2/1-1-minmax.solution | 3 + test_cases/q2/1-1-minmax.test | 47 + test_cases/q2/1-2-minmax.solution | 3 + test_cases/q2/1-2-minmax.test | 47 + test_cases/q2/1-3-minmax.solution | 3 + test_cases/q2/1-3-minmax.test | 47 + test_cases/q2/1-4-minmax.solution | 3 + test_cases/q2/1-4-minmax.test | 47 + test_cases/q2/1-5-minmax.solution | 3 + test_cases/q2/1-5-minmax.test | 75 ++ test_cases/q2/1-6-minmax.solution | 3 + test_cases/q2/1-6-minmax.test | 75 ++ test_cases/q2/1-7-minmax.solution | 3 + test_cases/q2/1-7-minmax.test | 75 ++ test_cases/q2/1-8-minmax.solution | 3 + test_cases/q2/1-8-minmax.test | 75 ++ test_cases/q2/2-1a-vary-depth.solution | 3 + test_cases/q2/2-1a-vary-depth.test | 52 ++ test_cases/q2/2-1b-vary-depth.solution | 3 + test_cases/q2/2-1b-vary-depth.test | 52 ++ test_cases/q2/2-2a-vary-depth.solution | 3 + test_cases/q2/2-2a-vary-depth.test | 52 ++ test_cases/q2/2-2b-vary-depth.solution | 3 + test_cases/q2/2-2b-vary-depth.test | 52 ++ test_cases/q2/2-3a-vary-depth.solution | 3 + test_cases/q2/2-3a-vary-depth.test | 52 ++ test_cases/q2/2-3b-vary-depth.solution | 3 + test_cases/q2/2-3b-vary-depth.test | 52 ++ test_cases/q2/2-4a-vary-depth.solution | 3 + test_cases/q2/2-4a-vary-depth.test | 52 ++ test_cases/q2/2-4b-vary-depth.solution | 3 + test_cases/q2/2-4b-vary-depth.test | 52 ++ test_cases/q2/2-one-ghost-3level.solution | 3 + test_cases/q2/2-one-ghost-3level.test | 52 ++ test_cases/q2/3-one-ghost-4level.solution | 3 + test_cases/q2/3-one-ghost-4level.test | 79 ++ test_cases/q2/4-two-ghosts-3level.solution | 3 + test_cases/q2/4-two-ghosts-3level.test | 52 ++ test_cases/q2/5-two-ghosts-4level.solution | 3 + test_cases/q2/5-two-ghosts-4level.test | 79 ++ test_cases/q2/6-tied-root.solution | 3 + test_cases/q2/6-tied-root.test | 31 + .../q2/7-1a-check-depth-one-ghost.solution | 3 + test_cases/q2/7-1a-check-depth-one-ghost.test | 83 ++ .../q2/7-1b-check-depth-one-ghost.solution | 3 + test_cases/q2/7-1b-check-depth-one-ghost.test | 83 ++ .../q2/7-1c-check-depth-one-ghost.solution | 3 + test_cases/q2/7-1c-check-depth-one-ghost.test | 83 ++ .../q2/7-2a-check-depth-two-ghosts.solution | 3 + .../q2/7-2a-check-depth-two-ghosts.test | 110 +++ .../q2/7-2b-check-depth-two-ghosts.solution | 3 + .../q2/7-2b-check-depth-two-ghosts.test | 110 +++ .../q2/7-2c-check-depth-two-ghosts.solution | 3 + .../q2/7-2c-check-depth-two-ghosts.test | 110 +++ test_cases/q2/8-pacman-game.solution | 444 ++++++++++ test_cases/q2/8-pacman-game.test | 19 + test_cases/q2/CONFIG | 2 +- test_cases/q2/graph_backtrack.solution | 7 - test_cases/q2/graph_backtrack.test | 32 - test_cases/q2/graph_bfs_vs_dfs.solution | 7 - test_cases/q2/graph_bfs_vs_dfs.test | 30 - test_cases/q2/graph_infinite.solution | 7 - test_cases/q2/graph_infinite.test | 30 - test_cases/q2/graph_manypaths.solution | 7 - test_cases/q2/graph_manypaths.test | 39 - test_cases/q2/pacman_1.solution | 22 - test_cases/q2/pacman_1.test | 27 - .../q3/0-eval-function-lose-states-1.solution | 3 + .../q3/0-eval-function-lose-states-1.test | 30 + .../q3/0-eval-function-lose-states-2.solution | 3 + .../q3/0-eval-function-lose-states-2.test | 30 + .../q3/0-eval-function-win-states-1.solution | 3 + .../q3/0-eval-function-win-states-1.test | 30 + .../q3/0-eval-function-win-states-2.solution | 3 + .../q3/0-eval-function-win-states-2.test | 30 + test_cases/q3/0-lecture-6-tree.solution | 3 + test_cases/q3/0-lecture-6-tree.test | 50 ++ test_cases/q3/0-small-tree.solution | 3 + test_cases/q3/0-small-tree.test | 36 + test_cases/q3/1-1-minmax.solution | 3 + test_cases/q3/1-1-minmax.test | 47 + test_cases/q3/1-2-minmax.solution | 3 + test_cases/q3/1-2-minmax.test | 47 + test_cases/q3/1-3-minmax.solution | 3 + test_cases/q3/1-3-minmax.test | 47 + test_cases/q3/1-4-minmax.solution | 3 + test_cases/q3/1-4-minmax.test | 47 + test_cases/q3/1-5-minmax.solution | 3 + test_cases/q3/1-5-minmax.test | 75 ++ test_cases/q3/1-6-minmax.solution | 3 + test_cases/q3/1-6-minmax.test | 75 ++ test_cases/q3/1-7-minmax.solution | 3 + test_cases/q3/1-7-minmax.test | 75 ++ test_cases/q3/1-8-minmax.solution | 3 + test_cases/q3/1-8-minmax.test | 75 ++ test_cases/q3/2-1a-vary-depth.solution | 3 + test_cases/q3/2-1a-vary-depth.test | 52 ++ test_cases/q3/2-1b-vary-depth.solution | 3 + test_cases/q3/2-1b-vary-depth.test | 52 ++ test_cases/q3/2-2a-vary-depth.solution | 3 + test_cases/q3/2-2a-vary-depth.test | 52 ++ test_cases/q3/2-2b-vary-depth.solution | 3 + test_cases/q3/2-2b-vary-depth.test | 52 ++ test_cases/q3/2-3a-vary-depth.solution | 3 + test_cases/q3/2-3a-vary-depth.test | 52 ++ test_cases/q3/2-3b-vary-depth.solution | 3 + test_cases/q3/2-3b-vary-depth.test | 52 ++ test_cases/q3/2-4a-vary-depth.solution | 3 + test_cases/q3/2-4a-vary-depth.test | 52 ++ test_cases/q3/2-4b-vary-depth.solution | 3 + test_cases/q3/2-4b-vary-depth.test | 52 ++ test_cases/q3/2-one-ghost-3level.solution | 3 + test_cases/q3/2-one-ghost-3level.test | 52 ++ test_cases/q3/3-one-ghost-4level.solution | 3 + test_cases/q3/3-one-ghost-4level.test | 79 ++ test_cases/q3/4-two-ghosts-3level.solution | 3 + test_cases/q3/4-two-ghosts-3level.test | 52 ++ test_cases/q3/5-two-ghosts-4level.solution | 3 + test_cases/q3/5-two-ghosts-4level.test | 79 ++ test_cases/q3/6-tied-root.solution | 3 + test_cases/q3/6-tied-root.test | 31 + .../q3/7-1a-check-depth-one-ghost.solution | 3 + test_cases/q3/7-1a-check-depth-one-ghost.test | 83 ++ .../q3/7-1b-check-depth-one-ghost.solution | 3 + test_cases/q3/7-1b-check-depth-one-ghost.test | 83 ++ .../q3/7-1c-check-depth-one-ghost.solution | 3 + test_cases/q3/7-1c-check-depth-one-ghost.test | 83 ++ .../q3/7-2a-check-depth-two-ghosts.solution | 3 + .../q3/7-2a-check-depth-two-ghosts.test | 110 +++ .../q3/7-2b-check-depth-two-ghosts.solution | 3 + .../q3/7-2b-check-depth-two-ghosts.test | 110 +++ .../q3/7-2c-check-depth-two-ghosts.solution | 3 + .../q3/7-2c-check-depth-two-ghosts.test | 110 +++ test_cases/q3/8-pacman-game.solution | 444 ++++++++++ test_cases/q3/8-pacman-game.test | 19 + test_cases/q3/CONFIG | 2 +- test_cases/q3/graph_backtrack.solution | 7 - test_cases/q3/graph_backtrack.test | 32 - test_cases/q3/graph_bfs_vs_dfs.solution | 7 - test_cases/q3/graph_bfs_vs_dfs.test | 30 - test_cases/q3/graph_infinite.solution | 7 - test_cases/q3/graph_infinite.test | 30 - test_cases/q3/graph_manypaths.solution | 7 - test_cases/q3/graph_manypaths.test | 39 - test_cases/q3/ucs_0_graph.solution | 7 - test_cases/q3/ucs_0_graph.test | 39 - test_cases/q3/ucs_1_problemC.solution | 22 - test_cases/q3/ucs_1_problemC.test | 28 - test_cases/q3/ucs_2_problemE.solution | 22 - test_cases/q3/ucs_2_problemE.test | 28 - test_cases/q3/ucs_3_problemW.solution | 34 - test_cases/q3/ucs_3_problemW.test | 28 - test_cases/q3/ucs_4_testSearch.solution | 12 - test_cases/q3/ucs_4_testSearch.test | 16 - test_cases/q3/ucs_5_goalAtDequeue.solution | 7 - test_cases/q3/ucs_5_goalAtDequeue.test | 29 - .../q4/0-eval-function-lose-states-1.solution | 3 + .../q4/0-eval-function-lose-states-1.test | 30 + .../q4/0-eval-function-lose-states-2.solution | 3 + .../q4/0-eval-function-lose-states-2.test | 30 + .../q4/0-eval-function-win-states-1.solution | 3 + .../q4/0-eval-function-win-states-1.test | 30 + .../q4/0-eval-function-win-states-2.solution | 3 + .../q4/0-eval-function-win-states-2.test | 30 + test_cases/q4/0-expectimax1.solution | 3 + test_cases/q4/0-expectimax1.test | 48 + test_cases/q4/1-expectimax2.solution | 3 + test_cases/q4/1-expectimax2.test | 48 + test_cases/q4/2-one-ghost-3level.solution | 3 + test_cases/q4/2-one-ghost-3level.test | 52 ++ test_cases/q4/3-one-ghost-4level.solution | 3 + test_cases/q4/3-one-ghost-4level.test | 79 ++ test_cases/q4/4-two-ghosts-3level.solution | 3 + test_cases/q4/4-two-ghosts-3level.test | 52 ++ test_cases/q4/5-two-ghosts-4level.solution | 3 + test_cases/q4/5-two-ghosts-4level.test | 79 ++ .../q4/6-1a-check-depth-one-ghost.solution | 3 + test_cases/q4/6-1a-check-depth-one-ghost.test | 83 ++ .../q4/6-1b-check-depth-one-ghost.solution | 3 + test_cases/q4/6-1b-check-depth-one-ghost.test | 83 ++ .../q4/6-1c-check-depth-one-ghost.solution | 3 + test_cases/q4/6-1c-check-depth-one-ghost.test | 83 ++ .../q4/6-2a-check-depth-two-ghosts.solution | 3 + .../q4/6-2a-check-depth-two-ghosts.test | 110 +++ .../q4/6-2b-check-depth-two-ghosts.solution | 3 + .../q4/6-2b-check-depth-two-ghosts.test | 110 +++ .../q4/6-2c-check-depth-two-ghosts.solution | 3 + .../q4/6-2c-check-depth-two-ghosts.test | 110 +++ test_cases/q4/7-pacman-game.solution | 444 ++++++++++ test_cases/q4/7-pacman-game.test | 19 + test_cases/q4/CONFIG | 2 +- test_cases/q4/astar_0.solution | 7 - test_cases/q4/astar_0.test | 39 - .../q4/astar_1_graph_heuristic.solution | 7 - test_cases/q4/astar_1_graph_heuristic.test | 54 -- test_cases/q4/astar_2_manhattan.solution | 22 - test_cases/q4/astar_2_manhattan.test | 27 - test_cases/q4/astar_3_goalAtDequeue.solution | 7 - test_cases/q4/astar_3_goalAtDequeue.test | 29 - test_cases/q4/graph_backtrack.solution | 7 - test_cases/q4/graph_backtrack.test | 32 - test_cases/q4/graph_manypaths.solution | 7 - test_cases/q4/graph_manypaths.test | 39 - test_cases/q5/CONFIG | 5 +- test_cases/q5/corner_tiny_corner.solution | 2 - test_cases/q5/corner_tiny_corner.test | 14 - test_cases/q5/grade-agent.solution | 2 + test_cases/q5/grade-agent.test | 18 + test_cases/q6/CONFIG | 3 - test_cases/q6/corner_sanity_1.solution | 7 - test_cases/q6/corner_sanity_1.test | 12 - test_cases/q6/corner_sanity_2.solution | 7 - test_cases/q6/corner_sanity_2.test | 12 - test_cases/q6/corner_sanity_3.solution | 9 - test_cases/q6/corner_sanity_3.test | 15 - test_cases/q6/medium_corners.solution | 16 - test_cases/q6/medium_corners.test | 19 - test_cases/q7/food_heuristic_1.solution | 2 - test_cases/q7/food_heuristic_1.test | 13 - test_cases/q7/food_heuristic_10.solution | 2 - test_cases/q7/food_heuristic_10.test | 13 - test_cases/q7/food_heuristic_11.solution | 2 - test_cases/q7/food_heuristic_11.test | 13 - test_cases/q7/food_heuristic_12.solution | 2 - test_cases/q7/food_heuristic_12.test | 13 - test_cases/q7/food_heuristic_13.solution | 2 - test_cases/q7/food_heuristic_13.test | 13 - test_cases/q7/food_heuristic_14.solution | 2 - test_cases/q7/food_heuristic_14.test | 19 - test_cases/q7/food_heuristic_15.solution | 2 - test_cases/q7/food_heuristic_15.test | 32 - test_cases/q7/food_heuristic_16.solution | 2 - test_cases/q7/food_heuristic_16.test | 15 - test_cases/q7/food_heuristic_17.solution | 2 - test_cases/q7/food_heuristic_17.test | 14 - test_cases/q7/food_heuristic_2.solution | 2 - test_cases/q7/food_heuristic_2.test | 32 - test_cases/q7/food_heuristic_3.solution | 2 - test_cases/q7/food_heuristic_3.test | 15 - test_cases/q7/food_heuristic_4.solution | 2 - test_cases/q7/food_heuristic_4.test | 14 - test_cases/q7/food_heuristic_5.solution | 2 - test_cases/q7/food_heuristic_5.test | 13 - test_cases/q7/food_heuristic_6.solution | 2 - test_cases/q7/food_heuristic_6.test | 13 - test_cases/q7/food_heuristic_7.solution | 2 - test_cases/q7/food_heuristic_7.test | 13 - test_cases/q7/food_heuristic_8.solution | 2 - test_cases/q7/food_heuristic_8.test | 13 - test_cases/q7/food_heuristic_9.solution | 2 - test_cases/q7/food_heuristic_9.test | 13 - .../q7/food_heuristic_grade_tricky.solution | 2 - .../q7/food_heuristic_grade_tricky.test | 19 - test_cases/q8/CONFIG | 2 - test_cases/q8/closest_dot_1.solution | 2 - test_cases/q8/closest_dot_1.test | 11 - test_cases/q8/closest_dot_10.solution | 2 - test_cases/q8/closest_dot_10.test | 17 - test_cases/q8/closest_dot_11.solution | 2 - test_cases/q8/closest_dot_11.test | 30 - test_cases/q8/closest_dot_12.solution | 2 - test_cases/q8/closest_dot_12.test | 13 - test_cases/q8/closest_dot_13.solution | 2 - test_cases/q8/closest_dot_13.test | 12 - test_cases/q8/closest_dot_2.solution | 2 - test_cases/q8/closest_dot_2.test | 11 - test_cases/q8/closest_dot_3.solution | 2 - test_cases/q8/closest_dot_3.test | 11 - test_cases/q8/closest_dot_4.solution | 2 - test_cases/q8/closest_dot_4.test | 11 - test_cases/q8/closest_dot_5.solution | 2 - test_cases/q8/closest_dot_5.test | 11 - test_cases/q8/closest_dot_6.solution | 2 - test_cases/q8/closest_dot_6.test | 11 - test_cases/q8/closest_dot_7.solution | 2 - test_cases/q8/closest_dot_7.test | 11 - test_cases/q8/closest_dot_8.solution | 2 - test_cases/q8/closest_dot_8.test | 11 - test_cases/q8/closest_dot_9.solution | 2 - test_cases/q8/closest_dot_9.test | 11 - textDisplay.py | 20 +- util.py | 361 ++++---- 358 files changed, 8770 insertions(+), 4878 deletions(-) delete mode 100644 commands.txt delete mode 100644 eightpuzzle.py delete mode 100644 layouts/bigCorners.lay delete mode 100644 layouts/bigMaze.lay delete mode 100644 layouts/bigSafeSearch.lay delete mode 100644 layouts/bigSearch.lay delete mode 100644 layouts/boxSearch.lay delete mode 100644 layouts/contoursMaze.lay delete mode 100644 layouts/greedySearch.lay delete mode 100644 layouts/mediumCorners.lay delete mode 100644 layouts/mediumDottedMaze.lay delete mode 100644 layouts/mediumMaze.lay delete mode 100644 layouts/mediumSafeSearch.lay delete mode 100644 layouts/mediumScaryMaze.lay delete mode 100644 layouts/mediumSearch.lay delete mode 100644 layouts/oddSearch.lay delete mode 100644 layouts/openMaze.lay delete mode 100644 layouts/openSearch.lay delete mode 100644 layouts/smallMaze.lay delete mode 100644 layouts/smallSafeSearch.lay delete mode 100644 layouts/smallSearch.lay delete mode 100644 layouts/testMaze.lay delete mode 100644 layouts/testSearch.lay delete mode 100644 layouts/tinyCorners.lay delete mode 100644 layouts/tinyMaze.lay delete mode 100644 layouts/tinySafeSearch.lay delete mode 100644 layouts/tinySearch.lay delete mode 100644 layouts/trickySearch.lay create mode 100644 multiAgents.py create mode 100644 multiagentTestClasses.py delete mode 100644 search.py delete mode 100644 searchAgents.py delete mode 100644 searchTestClasses.py rename test_cases/{q7 => extra}/CONFIG (51%) create mode 100644 test_cases/extra/grade-agent.test create mode 100644 test_cases/q1/grade-agent.solution create mode 100644 test_cases/q1/grade-agent.test delete mode 100644 test_cases/q1/graph_backtrack.solution delete mode 100644 test_cases/q1/graph_backtrack.test delete mode 100644 test_cases/q1/graph_bfs_vs_dfs.solution delete mode 100644 test_cases/q1/graph_bfs_vs_dfs.test delete mode 100644 test_cases/q1/graph_infinite.solution delete mode 100644 test_cases/q1/graph_infinite.test delete mode 100644 test_cases/q1/graph_manypaths.solution delete mode 100644 test_cases/q1/graph_manypaths.test delete mode 100644 test_cases/q1/pacman_1.solution delete mode 100644 test_cases/q1/pacman_1.test create mode 100644 test_cases/q2/0-eval-function-lose-states-1.solution create mode 100644 test_cases/q2/0-eval-function-lose-states-1.test create mode 100644 test_cases/q2/0-eval-function-lose-states-2.solution create mode 100644 test_cases/q2/0-eval-function-lose-states-2.test create mode 100644 test_cases/q2/0-eval-function-win-states-1.solution create mode 100644 test_cases/q2/0-eval-function-win-states-1.test create mode 100644 test_cases/q2/0-eval-function-win-states-2.solution create mode 100644 test_cases/q2/0-eval-function-win-states-2.test create mode 100644 test_cases/q2/0-lecture-6-tree.solution create mode 100644 test_cases/q2/0-lecture-6-tree.test create mode 100644 test_cases/q2/0-small-tree.solution create mode 100644 test_cases/q2/0-small-tree.test create mode 100644 test_cases/q2/1-1-minmax.solution create mode 100644 test_cases/q2/1-1-minmax.test create mode 100644 test_cases/q2/1-2-minmax.solution create mode 100644 test_cases/q2/1-2-minmax.test create mode 100644 test_cases/q2/1-3-minmax.solution create mode 100644 test_cases/q2/1-3-minmax.test create mode 100644 test_cases/q2/1-4-minmax.solution create mode 100644 test_cases/q2/1-4-minmax.test create mode 100644 test_cases/q2/1-5-minmax.solution create mode 100644 test_cases/q2/1-5-minmax.test create mode 100644 test_cases/q2/1-6-minmax.solution create mode 100644 test_cases/q2/1-6-minmax.test create mode 100644 test_cases/q2/1-7-minmax.solution create mode 100644 test_cases/q2/1-7-minmax.test create mode 100644 test_cases/q2/1-8-minmax.solution create mode 100644 test_cases/q2/1-8-minmax.test create mode 100644 test_cases/q2/2-1a-vary-depth.solution create mode 100644 test_cases/q2/2-1a-vary-depth.test create mode 100644 test_cases/q2/2-1b-vary-depth.solution create mode 100644 test_cases/q2/2-1b-vary-depth.test create mode 100644 test_cases/q2/2-2a-vary-depth.solution create mode 100644 test_cases/q2/2-2a-vary-depth.test create mode 100644 test_cases/q2/2-2b-vary-depth.solution create mode 100644 test_cases/q2/2-2b-vary-depth.test create mode 100644 test_cases/q2/2-3a-vary-depth.solution create mode 100644 test_cases/q2/2-3a-vary-depth.test create mode 100644 test_cases/q2/2-3b-vary-depth.solution create mode 100644 test_cases/q2/2-3b-vary-depth.test create mode 100644 test_cases/q2/2-4a-vary-depth.solution create mode 100644 test_cases/q2/2-4a-vary-depth.test create mode 100644 test_cases/q2/2-4b-vary-depth.solution create mode 100644 test_cases/q2/2-4b-vary-depth.test create mode 100644 test_cases/q2/2-one-ghost-3level.solution create mode 100644 test_cases/q2/2-one-ghost-3level.test create mode 100644 test_cases/q2/3-one-ghost-4level.solution create mode 100644 test_cases/q2/3-one-ghost-4level.test create mode 100644 test_cases/q2/4-two-ghosts-3level.solution create mode 100644 test_cases/q2/4-two-ghosts-3level.test create mode 100644 test_cases/q2/5-two-ghosts-4level.solution create mode 100644 test_cases/q2/5-two-ghosts-4level.test create mode 100644 test_cases/q2/6-tied-root.solution create mode 100644 test_cases/q2/6-tied-root.test create mode 100644 test_cases/q2/7-1a-check-depth-one-ghost.solution create mode 100644 test_cases/q2/7-1a-check-depth-one-ghost.test create mode 100644 test_cases/q2/7-1b-check-depth-one-ghost.solution create mode 100644 test_cases/q2/7-1b-check-depth-one-ghost.test create mode 100644 test_cases/q2/7-1c-check-depth-one-ghost.solution create mode 100644 test_cases/q2/7-1c-check-depth-one-ghost.test create mode 100644 test_cases/q2/7-2a-check-depth-two-ghosts.solution create mode 100644 test_cases/q2/7-2a-check-depth-two-ghosts.test create mode 100644 test_cases/q2/7-2b-check-depth-two-ghosts.solution create mode 100644 test_cases/q2/7-2b-check-depth-two-ghosts.test create mode 100644 test_cases/q2/7-2c-check-depth-two-ghosts.solution create mode 100644 test_cases/q2/7-2c-check-depth-two-ghosts.test create mode 100644 test_cases/q2/8-pacman-game.solution create mode 100644 test_cases/q2/8-pacman-game.test delete mode 100644 test_cases/q2/graph_backtrack.solution delete mode 100644 test_cases/q2/graph_backtrack.test delete mode 100644 test_cases/q2/graph_bfs_vs_dfs.solution delete mode 100644 test_cases/q2/graph_bfs_vs_dfs.test delete mode 100644 test_cases/q2/graph_infinite.solution delete mode 100644 test_cases/q2/graph_infinite.test delete mode 100644 test_cases/q2/graph_manypaths.solution delete mode 100644 test_cases/q2/graph_manypaths.test delete mode 100644 test_cases/q2/pacman_1.solution delete mode 100644 test_cases/q2/pacman_1.test create mode 100644 test_cases/q3/0-eval-function-lose-states-1.solution create mode 100644 test_cases/q3/0-eval-function-lose-states-1.test create mode 100644 test_cases/q3/0-eval-function-lose-states-2.solution create mode 100644 test_cases/q3/0-eval-function-lose-states-2.test create mode 100644 test_cases/q3/0-eval-function-win-states-1.solution create mode 100644 test_cases/q3/0-eval-function-win-states-1.test create mode 100644 test_cases/q3/0-eval-function-win-states-2.solution create mode 100644 test_cases/q3/0-eval-function-win-states-2.test create mode 100644 test_cases/q3/0-lecture-6-tree.solution create mode 100644 test_cases/q3/0-lecture-6-tree.test create mode 100644 test_cases/q3/0-small-tree.solution create mode 100644 test_cases/q3/0-small-tree.test create mode 100644 test_cases/q3/1-1-minmax.solution create mode 100644 test_cases/q3/1-1-minmax.test create mode 100644 test_cases/q3/1-2-minmax.solution create mode 100644 test_cases/q3/1-2-minmax.test create mode 100644 test_cases/q3/1-3-minmax.solution create mode 100644 test_cases/q3/1-3-minmax.test create mode 100644 test_cases/q3/1-4-minmax.solution create mode 100644 test_cases/q3/1-4-minmax.test create mode 100644 test_cases/q3/1-5-minmax.solution create mode 100644 test_cases/q3/1-5-minmax.test create mode 100644 test_cases/q3/1-6-minmax.solution create mode 100644 test_cases/q3/1-6-minmax.test create mode 100644 test_cases/q3/1-7-minmax.solution create mode 100644 test_cases/q3/1-7-minmax.test create mode 100644 test_cases/q3/1-8-minmax.solution create mode 100644 test_cases/q3/1-8-minmax.test create mode 100644 test_cases/q3/2-1a-vary-depth.solution create mode 100644 test_cases/q3/2-1a-vary-depth.test create mode 100644 test_cases/q3/2-1b-vary-depth.solution create mode 100644 test_cases/q3/2-1b-vary-depth.test create mode 100644 test_cases/q3/2-2a-vary-depth.solution create mode 100644 test_cases/q3/2-2a-vary-depth.test create mode 100644 test_cases/q3/2-2b-vary-depth.solution create mode 100644 test_cases/q3/2-2b-vary-depth.test create mode 100644 test_cases/q3/2-3a-vary-depth.solution create mode 100644 test_cases/q3/2-3a-vary-depth.test create mode 100644 test_cases/q3/2-3b-vary-depth.solution create mode 100644 test_cases/q3/2-3b-vary-depth.test create mode 100644 test_cases/q3/2-4a-vary-depth.solution create mode 100644 test_cases/q3/2-4a-vary-depth.test create mode 100644 test_cases/q3/2-4b-vary-depth.solution create mode 100644 test_cases/q3/2-4b-vary-depth.test create mode 100644 test_cases/q3/2-one-ghost-3level.solution create mode 100644 test_cases/q3/2-one-ghost-3level.test create mode 100644 test_cases/q3/3-one-ghost-4level.solution create mode 100644 test_cases/q3/3-one-ghost-4level.test create mode 100644 test_cases/q3/4-two-ghosts-3level.solution create mode 100644 test_cases/q3/4-two-ghosts-3level.test create mode 100644 test_cases/q3/5-two-ghosts-4level.solution create mode 100644 test_cases/q3/5-two-ghosts-4level.test create mode 100644 test_cases/q3/6-tied-root.solution create mode 100644 test_cases/q3/6-tied-root.test create mode 100644 test_cases/q3/7-1a-check-depth-one-ghost.solution create mode 100644 test_cases/q3/7-1a-check-depth-one-ghost.test create mode 100644 test_cases/q3/7-1b-check-depth-one-ghost.solution create mode 100644 test_cases/q3/7-1b-check-depth-one-ghost.test create mode 100644 test_cases/q3/7-1c-check-depth-one-ghost.solution create mode 100644 test_cases/q3/7-1c-check-depth-one-ghost.test create mode 100644 test_cases/q3/7-2a-check-depth-two-ghosts.solution create mode 100644 test_cases/q3/7-2a-check-depth-two-ghosts.test create mode 100644 test_cases/q3/7-2b-check-depth-two-ghosts.solution create mode 100644 test_cases/q3/7-2b-check-depth-two-ghosts.test create mode 100644 test_cases/q3/7-2c-check-depth-two-ghosts.solution create mode 100644 test_cases/q3/7-2c-check-depth-two-ghosts.test create mode 100644 test_cases/q3/8-pacman-game.solution create mode 100644 test_cases/q3/8-pacman-game.test delete mode 100644 test_cases/q3/graph_backtrack.solution delete mode 100644 test_cases/q3/graph_backtrack.test delete mode 100644 test_cases/q3/graph_bfs_vs_dfs.solution delete mode 100644 test_cases/q3/graph_bfs_vs_dfs.test delete mode 100644 test_cases/q3/graph_infinite.solution delete mode 100644 test_cases/q3/graph_infinite.test delete mode 100644 test_cases/q3/graph_manypaths.solution delete mode 100644 test_cases/q3/graph_manypaths.test delete mode 100644 test_cases/q3/ucs_0_graph.solution delete mode 100644 test_cases/q3/ucs_0_graph.test delete mode 100644 test_cases/q3/ucs_1_problemC.solution delete mode 100644 test_cases/q3/ucs_1_problemC.test delete mode 100644 test_cases/q3/ucs_2_problemE.solution delete mode 100644 test_cases/q3/ucs_2_problemE.test delete mode 100644 test_cases/q3/ucs_3_problemW.solution delete mode 100644 test_cases/q3/ucs_3_problemW.test delete mode 100644 test_cases/q3/ucs_4_testSearch.solution delete mode 100644 test_cases/q3/ucs_4_testSearch.test delete mode 100644 test_cases/q3/ucs_5_goalAtDequeue.solution delete mode 100644 test_cases/q3/ucs_5_goalAtDequeue.test create mode 100644 test_cases/q4/0-eval-function-lose-states-1.solution create mode 100644 test_cases/q4/0-eval-function-lose-states-1.test create mode 100644 test_cases/q4/0-eval-function-lose-states-2.solution create mode 100644 test_cases/q4/0-eval-function-lose-states-2.test create mode 100644 test_cases/q4/0-eval-function-win-states-1.solution create mode 100644 test_cases/q4/0-eval-function-win-states-1.test create mode 100644 test_cases/q4/0-eval-function-win-states-2.solution create mode 100644 test_cases/q4/0-eval-function-win-states-2.test create mode 100644 test_cases/q4/0-expectimax1.solution create mode 100644 test_cases/q4/0-expectimax1.test create mode 100644 test_cases/q4/1-expectimax2.solution create mode 100644 test_cases/q4/1-expectimax2.test create mode 100644 test_cases/q4/2-one-ghost-3level.solution create mode 100644 test_cases/q4/2-one-ghost-3level.test create mode 100644 test_cases/q4/3-one-ghost-4level.solution create mode 100644 test_cases/q4/3-one-ghost-4level.test create mode 100644 test_cases/q4/4-two-ghosts-3level.solution create mode 100644 test_cases/q4/4-two-ghosts-3level.test create mode 100644 test_cases/q4/5-two-ghosts-4level.solution create mode 100644 test_cases/q4/5-two-ghosts-4level.test create mode 100644 test_cases/q4/6-1a-check-depth-one-ghost.solution create mode 100644 test_cases/q4/6-1a-check-depth-one-ghost.test create mode 100644 test_cases/q4/6-1b-check-depth-one-ghost.solution create mode 100644 test_cases/q4/6-1b-check-depth-one-ghost.test create mode 100644 test_cases/q4/6-1c-check-depth-one-ghost.solution create mode 100644 test_cases/q4/6-1c-check-depth-one-ghost.test create mode 100644 test_cases/q4/6-2a-check-depth-two-ghosts.solution create mode 100644 test_cases/q4/6-2a-check-depth-two-ghosts.test create mode 100644 test_cases/q4/6-2b-check-depth-two-ghosts.solution create mode 100644 test_cases/q4/6-2b-check-depth-two-ghosts.test create mode 100644 test_cases/q4/6-2c-check-depth-two-ghosts.solution create mode 100644 test_cases/q4/6-2c-check-depth-two-ghosts.test create mode 100644 test_cases/q4/7-pacman-game.solution create mode 100644 test_cases/q4/7-pacman-game.test delete mode 100644 test_cases/q4/astar_0.solution delete mode 100644 test_cases/q4/astar_0.test delete mode 100644 test_cases/q4/astar_1_graph_heuristic.solution delete mode 100644 test_cases/q4/astar_1_graph_heuristic.test delete mode 100644 test_cases/q4/astar_2_manhattan.solution delete mode 100644 test_cases/q4/astar_2_manhattan.test delete mode 100644 test_cases/q4/astar_3_goalAtDequeue.solution delete mode 100644 test_cases/q4/astar_3_goalAtDequeue.test delete mode 100644 test_cases/q4/graph_backtrack.solution delete mode 100644 test_cases/q4/graph_backtrack.test delete mode 100644 test_cases/q4/graph_manypaths.solution delete mode 100644 test_cases/q4/graph_manypaths.test delete mode 100644 test_cases/q5/corner_tiny_corner.solution delete mode 100644 test_cases/q5/corner_tiny_corner.test create mode 100644 test_cases/q5/grade-agent.solution create mode 100644 test_cases/q5/grade-agent.test delete mode 100644 test_cases/q6/CONFIG delete mode 100644 test_cases/q6/corner_sanity_1.solution delete mode 100644 test_cases/q6/corner_sanity_1.test delete mode 100644 test_cases/q6/corner_sanity_2.solution delete mode 100644 test_cases/q6/corner_sanity_2.test delete mode 100644 test_cases/q6/corner_sanity_3.solution delete mode 100644 test_cases/q6/corner_sanity_3.test delete mode 100644 test_cases/q6/medium_corners.solution delete mode 100644 test_cases/q6/medium_corners.test delete mode 100644 test_cases/q7/food_heuristic_1.solution delete mode 100644 test_cases/q7/food_heuristic_1.test delete mode 100644 test_cases/q7/food_heuristic_10.solution delete mode 100644 test_cases/q7/food_heuristic_10.test delete mode 100644 test_cases/q7/food_heuristic_11.solution delete mode 100644 test_cases/q7/food_heuristic_11.test delete mode 100644 test_cases/q7/food_heuristic_12.solution delete mode 100644 test_cases/q7/food_heuristic_12.test delete mode 100644 test_cases/q7/food_heuristic_13.solution delete mode 100644 test_cases/q7/food_heuristic_13.test delete mode 100644 test_cases/q7/food_heuristic_14.solution delete mode 100644 test_cases/q7/food_heuristic_14.test delete mode 100644 test_cases/q7/food_heuristic_15.solution delete mode 100644 test_cases/q7/food_heuristic_15.test delete mode 100644 test_cases/q7/food_heuristic_16.solution delete mode 100644 test_cases/q7/food_heuristic_16.test delete mode 100644 test_cases/q7/food_heuristic_17.solution delete mode 100644 test_cases/q7/food_heuristic_17.test delete mode 100644 test_cases/q7/food_heuristic_2.solution delete mode 100644 test_cases/q7/food_heuristic_2.test delete mode 100644 test_cases/q7/food_heuristic_3.solution delete mode 100644 test_cases/q7/food_heuristic_3.test delete mode 100644 test_cases/q7/food_heuristic_4.solution delete mode 100644 test_cases/q7/food_heuristic_4.test delete mode 100644 test_cases/q7/food_heuristic_5.solution delete mode 100644 test_cases/q7/food_heuristic_5.test delete mode 100644 test_cases/q7/food_heuristic_6.solution delete mode 100644 test_cases/q7/food_heuristic_6.test delete mode 100644 test_cases/q7/food_heuristic_7.solution delete mode 100644 test_cases/q7/food_heuristic_7.test delete mode 100644 test_cases/q7/food_heuristic_8.solution delete mode 100644 test_cases/q7/food_heuristic_8.test delete mode 100644 test_cases/q7/food_heuristic_9.solution delete mode 100644 test_cases/q7/food_heuristic_9.test delete mode 100644 test_cases/q7/food_heuristic_grade_tricky.solution delete mode 100644 test_cases/q7/food_heuristic_grade_tricky.test delete mode 100644 test_cases/q8/CONFIG delete mode 100644 test_cases/q8/closest_dot_1.solution delete mode 100644 test_cases/q8/closest_dot_1.test delete mode 100644 test_cases/q8/closest_dot_10.solution delete mode 100644 test_cases/q8/closest_dot_10.test delete mode 100644 test_cases/q8/closest_dot_11.solution delete mode 100644 test_cases/q8/closest_dot_11.test delete mode 100644 test_cases/q8/closest_dot_12.solution delete mode 100644 test_cases/q8/closest_dot_12.test delete mode 100644 test_cases/q8/closest_dot_13.solution delete mode 100644 test_cases/q8/closest_dot_13.test delete mode 100644 test_cases/q8/closest_dot_2.solution delete mode 100644 test_cases/q8/closest_dot_2.test delete mode 100644 test_cases/q8/closest_dot_3.solution delete mode 100644 test_cases/q8/closest_dot_3.test delete mode 100644 test_cases/q8/closest_dot_4.solution delete mode 100644 test_cases/q8/closest_dot_4.test delete mode 100644 test_cases/q8/closest_dot_5.solution delete mode 100644 test_cases/q8/closest_dot_5.test delete mode 100644 test_cases/q8/closest_dot_6.solution delete mode 100644 test_cases/q8/closest_dot_6.test delete mode 100644 test_cases/q8/closest_dot_7.solution delete mode 100644 test_cases/q8/closest_dot_7.test delete mode 100644 test_cases/q8/closest_dot_8.solution delete mode 100644 test_cases/q8/closest_dot_8.test delete mode 100644 test_cases/q8/closest_dot_9.solution delete mode 100644 test_cases/q8/closest_dot_9.test diff --git a/VERSION b/VERSION index 7c7fa2f..15a3c19 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.001 +v1.004 diff --git a/autograder.py b/autograder.py index 21f7d3b..268f8c6 100644 --- a/autograder.py +++ b/autograder.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -22,63 +22,65 @@ import sys import projectParams import random random.seed(0) -try: +try: from pacman import GameState except: pass # register arguments and set default values def readCommand(argv): - parser = optparse.OptionParser(description = 'Run public tests on student code') - parser.set_defaults(generateSolutions=False, edxOutput=False, gsOutput=False, muteOutput=False, printTestCase=False, noGraphics=False) + parser = optparse.OptionParser( + description='Run public tests on student code') + parser.set_defaults(generateSolutions=False, edxOutput=False, gsOutput=False, + muteOutput=False, printTestCase=False, noGraphics=False) parser.add_option('--test-directory', - dest = 'testRoot', - default = 'test_cases', - help = 'Root test directory which contains subdirectories corresponding to each question') + dest='testRoot', + default='test_cases', + help='Root test directory which contains subdirectories corresponding to each question') parser.add_option('--student-code', - dest = 'studentCode', - default = projectParams.STUDENT_CODE_DEFAULT, - help = 'comma separated list of student code files') + dest='studentCode', + default=projectParams.STUDENT_CODE_DEFAULT, + help='comma separated list of student code files') parser.add_option('--code-directory', - dest = 'codeRoot', - default = "", - help = 'Root directory containing the student and testClass code') + dest='codeRoot', + default="", + help='Root directory containing the student and testClass code') parser.add_option('--test-case-code', - dest = 'testCaseCode', - default = projectParams.PROJECT_TEST_CLASSES, - help = 'class containing testClass classes for this project') + dest='testCaseCode', + default=projectParams.PROJECT_TEST_CLASSES, + help='class containing testClass classes for this project') parser.add_option('--generate-solutions', - dest = 'generateSolutions', - action = 'store_true', - help = 'Write solutions generated to .solution file') + dest='generateSolutions', + action='store_true', + help='Write solutions generated to .solution file') parser.add_option('--edx-output', - dest = 'edxOutput', - action = 'store_true', - help = 'Generate edX output files') + dest='edxOutput', + action='store_true', + help='Generate edX output files') parser.add_option('--gradescope-output', - dest = 'gsOutput', - action = 'store_true', - help = 'Generate GradeScope output files') + dest='gsOutput', + action='store_true', + help='Generate GradeScope output files') parser.add_option('--mute', - dest = 'muteOutput', - action = 'store_true', - help = 'Mute output from executing tests') + dest='muteOutput', + action='store_true', + help='Mute output from executing tests') parser.add_option('--print-tests', '-p', - dest = 'printTestCase', - action = 'store_true', - help = 'Print each test case before running them.') + dest='printTestCase', + action='store_true', + help='Print each test case before running them.') parser.add_option('--test', '-t', - dest = 'runTest', - default = None, - help = 'Run one particular test. Relative to test root.') + dest='runTest', + default=None, + help='Run one particular test. Relative to test root.') parser.add_option('--question', '-q', - dest = 'gradeQuestion', - default = None, - help = 'Grade one particular question.') + dest='gradeQuestion', + default=None, + help='Grade one particular question.') parser.add_option('--no-graphics', - dest = 'noGraphics', - action = 'store_true', - help = 'No graphics display for pacman games.') + dest='noGraphics', + action='store_true', + help='No graphics display for pacman games.') (options, args) = parser.parse_args(argv) return options @@ -107,14 +109,15 @@ def setModuleName(module, filename): for i in dir(module): o = getattr(module, i) - if hasattr(o, '__file__'): continue + if hasattr(o, '__file__'): + continue if type(o) == functionType: setattr(o, '__file__', filename) elif type(o) == classType: setattr(o, '__file__', filename) # TODO: assign member __file__'s? - #print(i, type(o)) + # print i, type(o) #from cStringIO import StringIO @@ -126,12 +129,14 @@ def loadModuleString(moduleSource): #f = StringIO(moduleCodeDict[k]) #tmp = imp.load_module(k, f, k, (".py", "r", imp.PY_SOURCE)) tmp = imp.new_module(k) - exec(moduleCodeDict[k] in tmp.__dict__) + exec(moduleCodeDict[k], tmp.__dict__) setModuleName(tmp, k) return tmp + import py_compile + def loadModuleFile(moduleName, filePath): with open(filePath, 'r') as f: return imp.load_module(moduleName, f, "%s.py" % moduleName, (".py", "r", imp.PY_SOURCE)) @@ -149,8 +154,8 @@ def readFile(path, root=""): # TODO: use these ERROR_HINT_MAP = { - 'q1': { - "": """ + 'q1': { + "": """ We noticed that your project threw an IndexError on q1. While many things may cause this, it may have been from assuming a certain number of successors from a state space @@ -158,9 +163,9 @@ ERROR_HINT_MAP = { state. Try making your code more general (no hardcoded indices) and submit again! """ - }, - 'q3': { - "": """ + }, + 'q3': { + "": """ We noticed that your project threw an AttributeError on q3. While many things may cause this, it may have been from assuming a certain size or structure to the state space. For example, if you have @@ -169,11 +174,12 @@ ERROR_HINT_MAP = { making your code more general and submit again! """ - } + } } import pprint + def splitStrings(d): d2 = dict(d) for k in d: @@ -215,14 +221,15 @@ def runTest(testName, moduleDict, printTestCase=False, display=None): printTest(testDict, solutionDict) # This is a fragile hack to create a stub grades object - grades = grading.Grades(projectParams.PROJECT_NAME, [(None,0)]) + grades = grading.Grades(projectParams.PROJECT_NAME, [(None, 0)]) testCase.execute(grades, moduleDict, solutionDict) # returns all the tests you need to run in order to run question def getDepends(testParser, testRoot, question): allDeps = [question] - questionDict = testParser.TestParser(os.path.join(testRoot, question, 'CONFIG')).parse() + questionDict = testParser.TestParser( + os.path.join(testRoot, question, 'CONFIG')).parse() if 'depends' in questionDict: depends = questionDict['depends'].split() for d in depends: @@ -232,11 +239,13 @@ def getDepends(testParser, testRoot, question): # get list of questions to grade def getTestSubdirs(testParser, testRoot, questionToGrade): - problemDict = testParser.TestParser(os.path.join(testRoot, 'CONFIG')).parse() + problemDict = testParser.TestParser( + os.path.join(testRoot, 'CONFIG')).parse() if questionToGrade != None: questions = getDepends(testParser, testRoot, questionToGrade) if len(questions) > 1: - print('Note: due to dependencies, the following tests will be run: %s' % ' '.join(questions)) + print('Note: due to dependencies, the following tests will be run: %s' % + ' '.join(questions)) return questions if 'order' in problemDict: return problemDict['order'].split() @@ -246,7 +255,7 @@ def getTestSubdirs(testParser, testRoot, questionToGrade): # evaluate student code def evaluate(generateSolutions, testRoot, moduleDict, exceptionMap=ERROR_HINT_MAP, edxOutput=False, muteOutput=False, gsOutput=False, - printTestCase=False, questionToGrade=None, display=None): + printTestCase=False, questionToGrade=None, display=None): # imports of testbench code. note that the testClasses import must follow # the import of student code due to dependencies import testParser @@ -263,14 +272,16 @@ def evaluate(generateSolutions, testRoot, moduleDict, exceptionMap=ERROR_HINT_MA continue # create a question object - questionDict = testParser.TestParser(os.path.join(subdir_path, 'CONFIG')).parse() + questionDict = testParser.TestParser( + os.path.join(subdir_path, 'CONFIG')).parse() questionClass = getattr(testClasses, questionDict['class']) question = questionClass(questionDict, display) questionDicts[q] = questionDict # load test cases into question - tests = filter(lambda t: re.match('[^#~.].*\.test\Z', t), os.listdir(subdir_path)) - tests = map(lambda t: re.match('(.*)\.test\Z', t).group(1), tests) + tests = [t for t in os.listdir( + subdir_path) if re.match('[^#~.].*\.test\Z', t)] + tests = [re.match('(.*)\.test\Z', t).group(1) for t in tests] for t in sorted(tests): test_file = os.path.join(subdir_path, '%s.test' % t) solution_file = os.path.join(subdir_path, '%s.solution' % t) @@ -281,6 +292,7 @@ def evaluate(generateSolutions, testRoot, moduleDict, exceptionMap=ERROR_HINT_MA testDict['test_out_file'] = test_out_file testClass = getattr(projectTestClasses, testDict['class']) testCase = testClass(question, testDict) + def makefun(testCase, solution_file): if generateSolutions: # write solution file to disk @@ -308,11 +320,10 @@ def evaluate(generateSolutions, testRoot, moduleDict, exceptionMap=ERROR_HINT_MA for prereq in questionDicts[q].get('depends', '').split(): grades.addPrereq(q, prereq) - grades.grade(sys.modules[__name__], bonusPic = projectParams.BONUS_PIC) + grades.grade(sys.modules[__name__], bonusPic=projectParams.BONUS_PIC) return grades.points - def getDisplay(graphicsByDefault, options=None): graphics = graphicsByDefault if options is not None and options.noGraphics: @@ -327,8 +338,6 @@ def getDisplay(graphicsByDefault, options=None): return textDisplay.NullGraphics() - - if __name__ == '__main__': options = readCommand(sys.argv) if options.generateSolutions: @@ -344,15 +353,17 @@ if __name__ == '__main__': moduleDict = {} for cp in codePaths: moduleName = re.match('.*?([^/]*)\.py', cp).group(1) - moduleDict[moduleName] = loadModuleFile(moduleName, os.path.join(options.codeRoot, cp)) + moduleDict[moduleName] = loadModuleFile( + moduleName, os.path.join(options.codeRoot, cp)) moduleName = re.match('.*?([^/]*)\.py', options.testCaseCode).group(1) - moduleDict['projectTestClasses'] = loadModuleFile(moduleName, os.path.join(options.codeRoot, options.testCaseCode)) - + moduleDict['projectTestClasses'] = loadModuleFile( + moduleName, os.path.join(options.codeRoot, options.testCaseCode)) if options.runTest != None: - runTest(options.runTest, moduleDict, printTestCase=options.printTestCase, display=getDisplay(True, options)) + runTest(options.runTest, moduleDict, printTestCase=options.printTestCase, + display=getDisplay(True, options)) else: evaluate(options.generateSolutions, options.testRoot, moduleDict, - gsOutput=options.gsOutput, - edxOutput=options.edxOutput, muteOutput=options.muteOutput, printTestCase=options.printTestCase, - questionToGrade=options.gradeQuestion, display=getDisplay(options.gradeQuestion!=None, options)) + gsOutput=options.gsOutput, + edxOutput=options.edxOutput, muteOutput=options.muteOutput, printTestCase=options.printTestCase, + questionToGrade=options.gradeQuestion, display=getDisplay(options.gradeQuestion != None, options)) diff --git a/commands.txt b/commands.txt deleted file mode 100644 index 21683ac..0000000 --- a/commands.txt +++ /dev/null @@ -1,21 +0,0 @@ -python pacman.py -python pacman.py --layout testMaze --pacman GoWestAgent -python pacman.py --layout tinyMaze --pacman GoWestAgent -python pacman.py -h -python pacman.py -l tinyMaze -p SearchAgent -a fn=tinyMazeSearch -python pacman.py -l tinyMaze -p SearchAgent -python pacman.py -l mediumMaze -p SearchAgent -python pacman.py -l bigMaze -z .5 -p SearchAgent -python pacman.py -l mediumMaze -p SearchAgent -a fn=bfs -python pacman.py -l bigMaze -p SearchAgent -a fn=bfs -z .5 -python eightpuzzle.py -python pacman.py -l mediumMaze -p SearchAgent -a fn=ucs -python pacman.py -l mediumDottedMaze -p StayEastSearchAgent -python pacman.py -l mediumScaryMaze -p StayWestSearchAgent -python pacman.py -l bigMaze -z .5 -p SearchAgent -a fn=astar,heuristic=manhattanHeuristic -python pacman.py -l tinyCorners -p SearchAgent -a fn=bfs,prob=CornersProblem -python pacman.py -l mediumCorners -p SearchAgent -a fn=bfs,prob=CornersProblem -python pacman.py -l mediumCorners -p AStarCornersAgent -z 0.5 -python pacman.py -l testSearch -p AStarFoodSearchAgent -python pacman.py -l trickySearch -p AStarFoodSearchAgent -python pacman.py -l bigSearch -p ClosestDotSearchAgent -z .5 diff --git a/eightpuzzle.py b/eightpuzzle.py deleted file mode 100644 index bb8ea6f..0000000 --- a/eightpuzzle.py +++ /dev/null @@ -1,281 +0,0 @@ -# eightpuzzle.py -# -------------- -# Licensing Information: You are free to use or extend these projects for -# educational purposes provided that (1) you do not distribute or publish -# solutions, (2) you retain this notice, and (3) you provide clear -# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# -# Attribution Information: The Pacman AI projects were developed at UC Berkeley. -# The core projects and autograders were primarily created by John DeNero -# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). -# Student side autograding was added by Brad Miller, Nick Hay, and -# Pieter Abbeel (pabbeel@cs.berkeley.edu). - - -import search -import random - -# Module Classes - -class EightPuzzleState: - """ - The Eight Puzzle is described in the course textbook on - page 64. - - This class defines the mechanics of the puzzle itself. The - task of recasting this puzzle as a search problem is left to - the EightPuzzleSearchProblem class. - """ - - def __init__( self, numbers ): - """ - Constructs a new eight puzzle from an ordering of numbers. - - numbers: a list of integers from 0 to 8 representing an - instance of the eight puzzle. 0 represents the blank - space. Thus, the list - - [1, 0, 2, 3, 4, 5, 6, 7, 8] - - represents the eight puzzle: - ------------- - | 1 | | 2 | - ------------- - | 3 | 4 | 5 | - ------------- - | 6 | 7 | 8 | - ------------ - - The configuration of the puzzle is stored in a 2-dimensional - list (a list of lists) 'cells'. - """ - self.cells = [] - numbers = numbers[:] # Make a copy so as not to cause side-effects. - numbers.reverse() - for row in range( 3 ): - self.cells.append( [] ) - for col in range( 3 ): - self.cells[row].append( numbers.pop() ) - if self.cells[row][col] == 0: - self.blankLocation = row, col - - def isGoal( self ): - """ - Checks to see if the puzzle is in its goal state. - - ------------- - | | 1 | 2 | - ------------- - | 3 | 4 | 5 | - ------------- - | 6 | 7 | 8 | - ------------- - - >>> EightPuzzleState([0, 1, 2, 3, 4, 5, 6, 7, 8]).isGoal() - True - - >>> EightPuzzleState([1, 0, 2, 3, 4, 5, 6, 7, 8]).isGoal() - False - """ - current = 0 - for row in range( 3 ): - for col in range( 3 ): - if current != self.cells[row][col]: - return False - current += 1 - return True - - def legalMoves( self ): - """ - Returns a list of legal moves from the current state. - - Moves consist of moving the blank space up, down, left or right. - These are encoded as 'up', 'down', 'left' and 'right' respectively. - - >>> EightPuzzleState([0, 1, 2, 3, 4, 5, 6, 7, 8]).legalMoves() - ['down', 'right'] - """ - moves = [] - row, col = self.blankLocation - if(row != 0): - moves.append('up') - if(row != 2): - moves.append('down') - if(col != 0): - moves.append('left') - if(col != 2): - moves.append('right') - return moves - - def result(self, move): - """ - Returns a new eightPuzzle with the current state and blankLocation - updated based on the provided move. - - The move should be a string drawn from a list returned by legalMoves. - Illegal moves will raise an exception, which may be an array bounds - exception. - - NOTE: This function *does not* change the current object. Instead, - it returns a new object. - """ - row, col = self.blankLocation - if(move == 'up'): - newrow = row - 1 - newcol = col - elif(move == 'down'): - newrow = row + 1 - newcol = col - elif(move == 'left'): - newrow = row - newcol = col - 1 - elif(move == 'right'): - newrow = row - newcol = col + 1 - else: - raise "Illegal Move" - - # Create a copy of the current eightPuzzle - newPuzzle = EightPuzzleState([0, 0, 0, 0, 0, 0, 0, 0, 0]) - newPuzzle.cells = [values[:] for values in self.cells] - # And update it to reflect the move - newPuzzle.cells[row][col] = self.cells[newrow][newcol] - newPuzzle.cells[newrow][newcol] = self.cells[row][col] - newPuzzle.blankLocation = newrow, newcol - - return newPuzzle - - # Utilities for comparison and display - def __eq__(self, other): - """ - Overloads '==' such that two eightPuzzles with the same configuration - are equal. - - >>> EightPuzzleState([0, 1, 2, 3, 4, 5, 6, 7, 8]) == \ - EightPuzzleState([1, 0, 2, 3, 4, 5, 6, 7, 8]).result('left') - True - """ - for row in range( 3 ): - if self.cells[row] != other.cells[row]: - return False - return True - - def __hash__(self): - return hash(str(self.cells)) - - def __getAsciiString(self): - """ - Returns a display string for the maze - """ - lines = [] - horizontalLine = ('-' * (13)) - lines.append(horizontalLine) - for row in self.cells: - rowLine = '|' - for col in row: - if col == 0: - col = ' ' - rowLine = rowLine + ' ' + col.__str__() + ' |' - lines.append(rowLine) - lines.append(horizontalLine) - return '\n'.join(lines) - - def __str__(self): - return self.__getAsciiString() - -# TODO: Implement The methods in this class - -class EightPuzzleSearchProblem(search.SearchProblem): - """ - Implementation of a SearchProblem for the Eight Puzzle domain - - Each state is represented by an instance of an eightPuzzle. - """ - def __init__(self,puzzle): - "Creates a new EightPuzzleSearchProblem which stores search information." - self.puzzle = puzzle - - def getStartState(self): - return puzzle - - def isGoalState(self,state): - return state.isGoal() - - def getSuccessors(self,state): - """ - Returns list of (successor, action, stepCost) pairs where - each succesor is either left, right, up, or down - from the original state and the cost is 1.0 for each - """ - succ = [] - for a in state.legalMoves(): - succ.append((state.result(a), a, 1)) - return succ - - def getCostOfActions(self, actions): - """ - actions: A list of actions to take - - This method returns the total cost of a particular sequence of actions. The sequence must - be composed of legal moves - """ - return len(actions) - -EIGHT_PUZZLE_DATA = [[1, 0, 2, 3, 4, 5, 6, 7, 8], - [1, 7, 8, 2, 3, 4, 5, 6, 0], - [4, 3, 2, 7, 0, 5, 1, 6, 8], - [5, 1, 3, 4, 0, 2, 6, 7, 8], - [1, 2, 5, 7, 6, 8, 0, 4, 3], - [0, 3, 1, 6, 8, 2, 7, 5, 4]] - -def loadEightPuzzle(puzzleNumber): - """ - puzzleNumber: The number of the eight puzzle to load. - - Returns an eight puzzle object generated from one of the - provided puzzles in EIGHT_PUZZLE_DATA. - - puzzleNumber can range from 0 to 5. - - >>> print(loadEightPuzzle(0)) - ------------- - | 1 | | 2 | - ------------- - | 3 | 4 | 5 | - ------------- - | 6 | 7 | 8 | - ------------- - """ - return EightPuzzleState(EIGHT_PUZZLE_DATA[puzzleNumber]) - -def createRandomEightPuzzle(moves=100): - """ - moves: number of random moves to apply - - Creates a random eight puzzle by applying - a series of 'moves' random moves to a solved - puzzle. - """ - puzzle = EightPuzzleState([0,1,2,3,4,5,6,7,8]) - for i in range(moves): - # Execute a random legal move - puzzle = puzzle.result(random.sample(puzzle.legalMoves(), 1)[0]) - return puzzle - -if __name__ == '__main__': - puzzle = createRandomEightPuzzle(25) - print('A random puzzle:') - print(puzzle) - - problem = EightPuzzleSearchProblem(puzzle) - path = search.breadthFirstSearch(problem) - print('BFS found a path of %d moves: %s' % (len(path), str(path))) - curr = puzzle - i = 1 - for a in path: - curr = curr.result(a) - print('After %d move%s: %s' % (i, ("", "s")[i>1], a)) - print(curr) - - input("Press return for the next state...") # wait for key stroke - i += 1 diff --git a/game.py b/game.py index 3950f27..39af72f 100644 --- a/game.py +++ b/game.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -21,7 +21,8 @@ # For more info, see http://inst.eecs.berkeley.edu/~cs188/sp09/pacman.html from util import * -import time, os +import time +import os import traceback import sys @@ -29,6 +30,7 @@ import sys # Parts worth reading # ####################### + class Agent: """ An agent must define a getAction method, but may also define the @@ -36,6 +38,7 @@ class Agent: def registerInitialState(self, state): # inspects the starting state """ + def __init__(self, index=0): self.index = index @@ -46,6 +49,7 @@ class Agent: """ raiseNotDefined() + class Directions: NORTH = 'North' SOUTH = 'South' @@ -53,13 +57,13 @@ class Directions: WEST = 'West' STOP = 'Stop' - LEFT = {NORTH: WEST, - SOUTH: EAST, - EAST: NORTH, - WEST: SOUTH, - STOP: STOP} + LEFT = {NORTH: WEST, + SOUTH: EAST, + EAST: NORTH, + WEST: SOUTH, + STOP: STOP} - RIGHT = dict([(y,x) for x, y in LEFT.items()]) + RIGHT = dict([(y, x) for x, y in list(LEFT.items())]) REVERSE = {NORTH: SOUTH, SOUTH: NORTH, @@ -67,6 +71,7 @@ class Directions: WEST: EAST, STOP: STOP} + class Configuration: """ A Configuration holds the (x,y) coordinate of a character, along with its @@ -87,11 +92,12 @@ class Configuration: return self.direction def isInteger(self): - x,y = self.pos + x, y = self.pos return x == int(x) and y == int(y) def __eq__(self, other): - if other == None: return False + if other == None: + return False return (self.pos == other.pos and self.direction == other.direction) def __hash__(self): @@ -110,33 +116,35 @@ class Configuration: Actions are movement vectors. """ - x, y= self.pos + x, y = self.pos dx, dy = vector direction = Actions.vectorToDirection(vector) if direction == Directions.STOP: - direction = self.direction # There is no stop direction + direction = self.direction # There is no stop direction return Configuration((x + dx, y+dy), direction) + class AgentState: """ AgentStates hold the state of an agent (configuration, speed, scared, etc). """ - def __init__( self, startConfiguration, isPacman ): + def __init__(self, startConfiguration, isPacman): self.start = startConfiguration self.configuration = startConfiguration self.isPacman = isPacman self.scaredTimer = 0 + # state below potentially used for contest only self.numCarrying = 0 self.numReturned = 0 - def __str__( self ): + def __str__(self): if self.isPacman: - return "Pacman: " + str( self.configuration ) + return "Pacman: " + str(self.configuration) else: - return "Ghost: " + str( self.configuration ) + return "Ghost: " + str(self.configuration) - def __eq__( self, other ): + def __eq__(self, other): if other == None: return False return self.configuration == other.configuration and self.scaredTimer == other.scaredTimer @@ -144,8 +152,8 @@ class AgentState: def __hash__(self): return hash(hash(self.configuration) + 13 * hash(self.scaredTimer)) - def copy( self ): - state = AgentState( self.start, self.isPacman ) + def copy(self): + state = AgentState(self.start, self.isPacman) state.configuration = self.configuration state.scaredTimer = self.scaredTimer state.numCarrying = self.numCarrying @@ -153,12 +161,14 @@ class AgentState: return state def getPosition(self): - if self.configuration == None: return None + if self.configuration == None: + return None return self.configuration.getPosition() def getDirection(self): return self.configuration.getDirection() + class Grid: """ A 2-dimensional array of objects backed by a list of lists. Data is accessed @@ -167,13 +177,16 @@ class Grid: The __str__ method constructs an output that is oriented like a pacman board. """ + def __init__(self, width, height, initialValue=False, bitRepresentation=None): - if initialValue not in [False, True]: raise Exception('Grids can only contain booleans') + if initialValue not in [False, True]: + raise Exception('Grids can only contain booleans') self.CELLS_PER_INT = 30 self.width = width self.height = height - self.data = [[initialValue for y in range(height)] for x in range(width)] + self.data = [[initialValue for y in range( + height)] for x in range(width)] if bitRepresentation: self._unpackBits(bitRepresentation) @@ -184,12 +197,14 @@ class Grid: self.data[key] = item def __str__(self): - out = [[str(self.data[x][y])[0] for x in range(self.width)] for y in range(self.height)] + out = [[str(self.data[x][y])[0] for x in range(self.width)] + for y in range(self.height)] out.reverse() return '\n'.join([''.join(x) for x in out]) def __eq__(self, other): - if other == None: return False + if other == None: + return False return self.data == other.data def __hash__(self): @@ -216,14 +231,15 @@ class Grid: g.data = self.data return g - def count(self, item =True ): + def count(self, item=True): return sum([x.count(item) for x in self.data]) - def asList(self, key = True): + def asList(self, key=True): list = [] for x in range(self.width): for y in range(self.height): - if self[x][y] == key: list.append( (x,y) ) + if self[x][y] == key: + list.append((x, y)) return list def packBits(self): @@ -246,7 +262,7 @@ class Grid: return tuple(bits) def _cellIndexToPosition(self, index): - x = index // self.height + x = index / self.height y = index % self.height return x, y @@ -257,14 +273,16 @@ class Grid: cell = 0 for packed in bits: for bit in self._unpackInt(packed, self.CELLS_PER_INT): - if cell == self.width * self.height: break + if cell == self.width * self.height: + break x, y = self._cellIndexToPosition(cell) self[x][y] = bit cell += 1 def _unpackInt(self, packed, size): bools = [] - if packed < 0: raise ValueError("must be a positive integer") + if packed < 0: + raise ValueError("must be a positive integer") for i in range(size): n = 2 ** (self.CELLS_PER_INT - i - 1) if packed >= n: @@ -274,28 +292,30 @@ class Grid: bools.append(False) return bools + def reconstituteGrid(bitRep): - if type(bitRep) is not type((1,2)): + if type(bitRep) is not type((1, 2)): return bitRep width, height = bitRep[:2] - return Grid(width, height, bitRepresentation= bitRep[2:]) + return Grid(width, height, bitRepresentation=bitRep[2:]) #################################### # Parts you shouldn't have to read # #################################### + class Actions: """ A collection of static methods for manipulating move actions. """ # Directions - _directions = {Directions.NORTH: (0, 1), - Directions.SOUTH: (0, -1), + _directions = {Directions.WEST: (-1, 0), + Directions.STOP: (0, 0), Directions.EAST: (1, 0), - Directions.WEST: (-1, 0), - Directions.STOP: (0, 0)} + Directions.NORTH: (0, 1), + Directions.SOUTH: (0, -1)} - _directionsAsList = _directions.items() + _directionsAsList = [('West', (-1, 0)), ('Stop', (0, 0)), ('East', (1, 0)), ('North', (0, 1)), ('South', (0, -1))] TOLERANCE = .001 @@ -324,8 +344,8 @@ class Actions: return Directions.STOP vectorToDirection = staticmethod(vectorToDirection) - def directionToVector(direction, speed = 1.0): - dx, dy = Actions._directions[direction] + def directionToVector(direction, speed=1.0): + dx, dy = Actions._directions[direction] return (dx * speed, dy * speed) directionToVector = staticmethod(directionToVector) @@ -335,30 +355,34 @@ class Actions: x_int, y_int = int(x + 0.5), int(y + 0.5) # In between grid points, all agents must continue straight - if (abs(x - x_int) + abs(y - y_int) > Actions.TOLERANCE): + if (abs(x - x_int) + abs(y - y_int) > Actions.TOLERANCE): return [config.getDirection()] for dir, vec in Actions._directionsAsList: dx, dy = vec next_y = y_int + dy next_x = x_int + dx - if not walls[next_x][next_y]: possible.append(dir) + if not walls[next_x][next_y]: + possible.append(dir) return possible getPossibleActions = staticmethod(getPossibleActions) def getLegalNeighbors(position, walls): - x,y = position + x, y = position x_int, y_int = int(x + 0.5), int(y + 0.5) neighbors = [] for dir, vec in Actions._directionsAsList: dx, dy = vec next_x = x_int + dx - if next_x < 0 or next_x == walls.width: continue + if next_x < 0 or next_x == walls.width: + continue next_y = y_int + dy - if next_y < 0 or next_y == walls.height: continue - if not walls[next_x][next_y]: neighbors.append((next_x, next_y)) + if next_y < 0 or next_y == walls.height: + continue + if not walls[next_x][next_y]: + neighbors.append((next_x, next_y)) return neighbors getLegalNeighbors = staticmethod(getLegalNeighbors) @@ -368,18 +392,17 @@ class Actions: return (x + dx, y + dy) getSuccessor = staticmethod(getSuccessor) -class GameStateData: - """ - """ - def __init__( self, prevState = None ): +class GameStateData: + + def __init__(self, prevState=None): """ Generates a new data packet by copying information from its predecessor. """ if prevState != None: self.food = prevState.food.shallowCopy() self.capsules = prevState.capsules[:] - self.agentStates = self.copyAgentStates( prevState.agentStates ) + self.agentStates = self.copyAgentStates(prevState.agentStates) self.layout = prevState.layout self._eaten = prevState._eaten self.score = prevState.score @@ -392,8 +415,8 @@ class GameStateData: self._win = False self.scoreChange = 0 - def deepCopy( self ): - state = GameStateData( self ) + def deepCopy(self): + state = GameStateData(self) state.food = self.food.deepCopy() state.layout = self.layout.deepCopy() state._agentMoved = self._agentMoved @@ -402,40 +425,45 @@ class GameStateData: state._capsuleEaten = self._capsuleEaten return state - def copyAgentStates( self, agentStates ): + def copyAgentStates(self, agentStates): copiedStates = [] for agentState in agentStates: - copiedStates.append( agentState.copy() ) + copiedStates.append(agentState.copy()) return copiedStates - def __eq__( self, other ): + def __eq__(self, other): """ Allows two states to be compared. """ - if other == None: return False + if other == None: + return False # TODO Check for type of other - if not self.agentStates == other.agentStates: return False - if not self.food == other.food: return False - if not self.capsules == other.capsules: return False - if not self.score == other.score: return False + if not self.agentStates == other.agentStates: + return False + if not self.food == other.food: + return False + if not self.capsules == other.capsules: + return False + if not self.score == other.score: + return False return True - def __hash__( self ): + def __hash__(self): """ Allows states to be keys of dictionaries. """ - for i, state in enumerate( self.agentStates ): + for i, state in enumerate(self.agentStates): try: int(hash(state)) except TypeError as e: print(e) - #hash(state) - return int((hash(tuple(self.agentStates)) + 13*hash(self.food) + 113* hash(tuple(self.capsules)) + 7 * hash(self.score)) % 1048575 ) + # hash(state) + return int((hash(tuple(self.agentStates)) + 13*hash(self.food) + 113 * hash(tuple(self.capsules)) + 7 * hash(self.score)) % 1048575) - def __str__( self ): + def __str__(self): width, height = self.layout.width, self.layout.height map = Grid(width, height) - if type(self.food) == type((1,2)): + if type(self.food) == type((1, 2)): self.food = reconstituteGrid(self.food) for x in range(width): for y in range(height): @@ -443,21 +471,23 @@ class GameStateData: map[x][y] = self._foodWallStr(food[x][y], walls[x][y]) for agentState in self.agentStates: - if agentState == None: continue - if agentState.configuration == None: continue - x,y = [int( i ) for i in nearestPoint( agentState.configuration.pos )] + if agentState == None: + continue + if agentState.configuration == None: + continue + x, y = [int(i) for i in nearestPoint(agentState.configuration.pos)] agent_dir = agentState.configuration.direction if agentState.isPacman: - map[x][y] = self._pacStr( agent_dir ) + map[x][y] = self._pacStr(agent_dir) else: - map[x][y] = self._ghostStr( agent_dir ) + map[x][y] = self._ghostStr(agent_dir) for x, y in self.capsules: map[x][y] = 'o' return str(map) + ("\nScore: %d\n" % self.score) - def _foodWallStr( self, hasFood, hasWall ): + def _foodWallStr(self, hasFood, hasWall): if hasFood: return '.' elif hasWall: @@ -465,7 +495,7 @@ class GameStateData: else: return ' ' - def _pacStr( self, dir ): + def _pacStr(self, dir): if dir == Directions.NORTH: return 'v' if dir == Directions.SOUTH: @@ -474,7 +504,7 @@ class GameStateData: return '>' return '<' - def _ghostStr( self, dir ): + def _ghostStr(self, dir): return 'G' if dir == Directions.NORTH: return 'M' @@ -484,7 +514,7 @@ class GameStateData: return '3' return 'E' - def initialize( self, layout, numGhostAgents ): + def initialize(self, layout, numGhostAgents): """ Creates an initial game state from a layout array (see layout.py). """ @@ -499,23 +529,28 @@ class GameStateData: numGhosts = 0 for isPacman, pos in layout.agentPositions: if not isPacman: - if numGhosts == numGhostAgents: continue # Max ghosts reached already - else: numGhosts += 1 - self.agentStates.append( AgentState( Configuration( pos, Directions.STOP), isPacman) ) + if numGhosts == numGhostAgents: + continue # Max ghosts reached already + else: + numGhosts += 1 + self.agentStates.append(AgentState( + Configuration(pos, Directions.STOP), isPacman)) self._eaten = [False for a in self.agentStates] + try: import boinc _BOINC_ENABLED = True except: _BOINC_ENABLED = False + class Game: """ The Game manages the control flow, soliciting actions from agents. """ - def __init__( self, agents, display, rules, startingIndex=0, muteAgents=False, catchExceptions=False ): + def __init__(self, agents, display, rules, startingIndex=0, muteAgents=False, catchExceptions=False): self.agentCrashed = False self.agents = agents self.display = display @@ -537,9 +572,10 @@ class Game: else: return self.rules.getProgress(self) - def _agentCrash( self, agentIndex, quiet=False): + def _agentCrash(self, agentIndex, quiet=False): "Helper method for handling agent crashes" - if not quiet: traceback.print_exc() + if not quiet: + traceback.print_exc() self.gameOver = True self.agentCrashed = True self.rules.agentCrash(self, agentIndex) @@ -548,7 +584,8 @@ class Game: OLD_STDERR = None def mute(self, agentIndex): - if not self.muteAgents: return + if not self.muteAgents: + return global OLD_STDOUT, OLD_STDERR import io OLD_STDOUT = sys.stdout @@ -557,21 +594,21 @@ class Game: sys.stderr = self.agentOutput[agentIndex] def unmute(self): - if not self.muteAgents: return + if not self.muteAgents: + return global OLD_STDOUT, OLD_STDERR # Revert stdout/stderr to originals sys.stdout = OLD_STDOUT sys.stderr = OLD_STDERR - - def run( self ): + def run(self): """ Main control loop for game play. """ self.display.initialize(self.state.data) self.numMoves = 0 - ###self.display.initialize(self.state.makeObservation(1).data) + # self.display.initialize(self.state.makeObservation(1).data) # inform learning agents of the game start for i in range(len(self.agents)): agent = self.agents[i] @@ -587,14 +624,16 @@ class Game: self.mute(i) if self.catchExceptions: try: - timed_func = TimeoutFunction(agent.registerInitialState, int(self.rules.getMaxStartupTime(i))) + timed_func = TimeoutFunction( + agent.registerInitialState, int(self.rules.getMaxStartupTime(i))) try: start_time = time.time() timed_func(self.state.deepCopy()) time_taken = time.time() - start_time self.totalAgentTimes[i] += time_taken except TimeoutFunctionException: - print("Agent %d ran out of time on startup!" % i, file=sys.stderr) + print("Agent %d ran out of time on startup!" % + i, file=sys.stderr) self.unmute() self.agentTimeout = True self._agentCrash(i, quiet=True) @@ -605,11 +644,11 @@ class Game: return else: agent.registerInitialState(self.state.deepCopy()) - ## TODO: could this exceed the total time + # TODO: could this exceed the total time self.unmute() agentIndex = self.startingIndex - numAgents = len( self.agents ) + numAgents = len(self.agents) while not self.gameOver: # Fetch the next agent @@ -617,11 +656,12 @@ class Game: move_time = 0 skip_action = False # Generate an observation of the state - if 'observationFunction' in dir( agent ): + if 'observationFunction' in dir(agent): self.mute(agentIndex) if self.catchExceptions: try: - timed_func = TimeoutFunction(agent.observationFunction, int(self.rules.getMoveTimeout(agentIndex))) + timed_func = TimeoutFunction(agent.observationFunction, int( + self.rules.getMoveTimeout(agentIndex))) try: start_time = time.time() observation = timed_func(self.state.deepCopy()) @@ -634,7 +674,8 @@ class Game: self.unmute() return else: - observation = agent.observationFunction(self.state.deepCopy()) + observation = agent.observationFunction( + self.state.deepCopy()) self.unmute() else: observation = self.state.deepCopy() @@ -644,14 +685,16 @@ class Game: self.mute(agentIndex) if self.catchExceptions: try: - timed_func = TimeoutFunction(agent.getAction, int(self.rules.getMoveTimeout(agentIndex)) - int(move_time)) + timed_func = TimeoutFunction(agent.getAction, int( + self.rules.getMoveTimeout(agentIndex)) - int(move_time)) try: start_time = time.time() if skip_action: raise TimeoutFunctionException() - action = timed_func( observation ) + action = timed_func(observation) except TimeoutFunctionException: - print("Agent %d timed out on a single move!" % agentIndex, file=sys.stderr) + print("Agent %d timed out on a single move!" % + agentIndex, file=sys.stderr) self.agentTimeout = True self._agentCrash(agentIndex, quiet=True) self.unmute() @@ -661,18 +704,21 @@ class Game: if move_time > self.rules.getMoveWarningTime(agentIndex): self.totalAgentTimeWarnings[agentIndex] += 1 - print("Agent %d took too long to make a move! This is warning %d" % (agentIndex, self.totalAgentTimeWarnings[agentIndex]), file=sys.stderr) + print("Agent %d took too long to make a move! This is warning %d" % ( + agentIndex, self.totalAgentTimeWarnings[agentIndex]), file=sys.stderr) if self.totalAgentTimeWarnings[agentIndex] > self.rules.getMaxTimeWarnings(agentIndex): - print("Agent %d exceeded the maximum number of warnings: %d" % (agentIndex, self.totalAgentTimeWarnings[agentIndex]), file=sys.stderr) + print("Agent %d exceeded the maximum number of warnings: %d" % ( + agentIndex, self.totalAgentTimeWarnings[agentIndex]), file=sys.stderr) self.agentTimeout = True self._agentCrash(agentIndex, quiet=True) self.unmute() return self.totalAgentTimes[agentIndex] += move_time - #print("Agent: %d, time: %f, total: %f" % (agentIndex, move_time, self.totalAgentTimes[agentIndex])) + # print "Agent: %d, time: %f, total: %f" % (agentIndex, move_time, self.totalAgentTimes[agentIndex]) if self.totalAgentTimes[agentIndex] > self.rules.getMaxTotalTime(agentIndex): - print("Agent %d ran out of time! (time: %1.2f)" % (agentIndex, self.totalAgentTimes[agentIndex]), file=sys.stderr) + print("Agent %d ran out of time! (time: %1.2f)" % ( + agentIndex, self.totalAgentTimes[agentIndex]), file=sys.stderr) self.agentTimeout = True self._agentCrash(agentIndex, quiet=True) self.unmute() @@ -687,42 +733,45 @@ class Game: self.unmute() # Execute the action - self.moveHistory.append( (agentIndex, action) ) + self.moveHistory.append((agentIndex, action)) if self.catchExceptions: try: - self.state = self.state.generateSuccessor( agentIndex, action ) + self.state = self.state.generateSuccessor( + agentIndex, action) except Exception as data: self.mute(agentIndex) self._agentCrash(agentIndex) self.unmute() return else: - self.state = self.state.generateSuccessor( agentIndex, action ) + self.state = self.state.generateSuccessor(agentIndex, action) # Change the display - self.display.update( self.state.data ) + self.display.update(self.state.data) ###idx = agentIndex - agentIndex % 2 + 1 ###self.display.update( self.state.makeObservation(idx).data ) # Allow for game specific conditions (winning, losing, etc.) self.rules.process(self.state, self) # Track progress - if agentIndex == numAgents + 1: self.numMoves += 1 + if agentIndex == numAgents + 1: + self.numMoves += 1 # Next agent - agentIndex = ( agentIndex + 1 ) % numAgents + agentIndex = (agentIndex + 1) % numAgents if _BOINC_ENABLED: boinc.set_fraction_done(self.getProgress()) # inform a learning agent of the game result for agentIndex, agent in enumerate(self.agents): - if "final" in dir( agent ) : + if "final" in dir(agent): try: self.mute(agentIndex) - agent.final( self.state ) + agent.final(self.state) self.unmute() except Exception as data: - if not self.catchExceptions: raise data + if not self.catchExceptions: + raise self._agentCrash(agentIndex) self.unmute() return diff --git a/ghostAgents.py b/ghostAgents.py index c3afe1f..c7ebbca 100644 --- a/ghostAgents.py +++ b/ghostAgents.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -19,63 +19,75 @@ import random from util import manhattanDistance import util -class GhostAgent( Agent ): - def __init__( self, index ): + +class GhostAgent(Agent): + def __init__(self, index): self.index = index - def getAction( self, state ): + def getAction(self, state): dist = self.getDistribution(state) if len(dist) == 0: return Directions.STOP else: - return util.chooseFromDistribution( dist ) + return util.chooseFromDistribution(dist) def getDistribution(self, state): "Returns a Counter encoding a distribution over actions from the provided state." util.raiseNotDefined() -class RandomGhost( GhostAgent ): + +class RandomGhost(GhostAgent): "A ghost that chooses a legal action uniformly at random." - def getDistribution( self, state ): + + def getDistribution(self, state): dist = util.Counter() - for a in state.getLegalActions( self.index ): dist[a] = 1.0 + for a in state.getLegalActions(self.index): + dist[a] = 1.0 dist.normalize() return dist -class DirectionalGhost( GhostAgent ): + +class DirectionalGhost(GhostAgent): "A ghost that prefers to rush Pacman, or flee when scared." - def __init__( self, index, prob_attack=0.8, prob_scaredFlee=0.8 ): + + def __init__(self, index, prob_attack=0.8, prob_scaredFlee=0.8): self.index = index self.prob_attack = prob_attack self.prob_scaredFlee = prob_scaredFlee - def getDistribution( self, state ): + def getDistribution(self, state): # Read variables from state - ghostState = state.getGhostState( self.index ) - legalActions = state.getLegalActions( self.index ) - pos = state.getGhostPosition( self.index ) + ghostState = state.getGhostState(self.index) + legalActions = state.getLegalActions(self.index) + pos = state.getGhostPosition(self.index) isScared = ghostState.scaredTimer > 0 speed = 1 - if isScared: speed = 0.5 + if isScared: + speed = 0.5 - actionVectors = [Actions.directionToVector( a, speed ) for a in legalActions] - newPositions = [( pos[0]+a[0], pos[1]+a[1] ) for a in actionVectors] + actionVectors = [Actions.directionToVector( + a, speed) for a in legalActions] + newPositions = [(pos[0]+a[0], pos[1]+a[1]) for a in actionVectors] pacmanPosition = state.getPacmanPosition() # Select best actions given the state - distancesToPacman = [manhattanDistance( pos, pacmanPosition ) for pos in newPositions] + distancesToPacman = [manhattanDistance( + pos, pacmanPosition) for pos in newPositions] if isScared: - bestScore = max( distancesToPacman ) + bestScore = max(distancesToPacman) bestProb = self.prob_scaredFlee else: - bestScore = min( distancesToPacman ) + bestScore = min(distancesToPacman) bestProb = self.prob_attack - bestActions = [action for action, distance in zip( legalActions, distancesToPacman ) if distance == bestScore] + bestActions = [action for action, distance in zip( + legalActions, distancesToPacman) if distance == bestScore] # Construct distribution dist = util.Counter() - for a in bestActions: dist[a] = bestProb / len(bestActions) - for a in legalActions: dist[a] += ( 1-bestProb ) / len(legalActions) + for a in bestActions: + dist[a] = bestProb / len(bestActions) + for a in legalActions: + dist[a] += (1-bestProb) / len(legalActions) dist.normalize() return dist diff --git a/grading.py b/grading.py index 6384a56..eeca956 100644 --- a/grading.py +++ b/grading.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -23,83 +23,88 @@ import pdb from collections import defaultdict import util + class Grades: - "A data structure for project grades, along with formatting code to display them" - def __init__(self, projectName, questionsAndMaxesList, - gsOutput=False, edxOutput=False, muteOutput=False): - """ - Defines the grading scheme for a project - projectName: project name - questionsAndMaxesDict: a list of (question name, max points per question) - """ - self.questions = [el[0] for el in questionsAndMaxesList] - self.maxes = dict(questionsAndMaxesList) - self.points = Counter() - self.messages = dict([(q, []) for q in self.questions]) - self.project = projectName - self.start = time.localtime()[1:6] - self.sane = True # Sanity checks - self.currentQuestion = None # Which question we're grading - self.edxOutput = edxOutput - self.gsOutput = gsOutput # GradeScope output - self.mute = muteOutput - self.prereqs = defaultdict(set) + "A data structure for project grades, along with formatting code to display them" - #print('Autograder transcript for %s' % self.project) - print('Starting on %d-%d at %d:%02d:%02d' % self.start) + def __init__(self, projectName, questionsAndMaxesList, + gsOutput=False, edxOutput=False, muteOutput=False): + """ + Defines the grading scheme for a project + projectName: project name + questionsAndMaxesDict: a list of (question name, max points per question) + """ + self.questions = [el[0] for el in questionsAndMaxesList] + self.maxes = dict(questionsAndMaxesList) + self.points = Counter() + self.messages = dict([(q, []) for q in self.questions]) + self.project = projectName + self.start = time.localtime()[1:6] + self.sane = True # Sanity checks + self.currentQuestion = None # Which question we're grading + self.edxOutput = edxOutput + self.gsOutput = gsOutput # GradeScope output + self.mute = muteOutput + self.prereqs = defaultdict(set) - def addPrereq(self, question, prereq): - self.prereqs[question].add(prereq) + # print 'Autograder transcript for %s' % self.project + print('Starting on %d-%d at %d:%02d:%02d' % self.start) - def grade(self, gradingModule, exceptionMap = {}, bonusPic = False): - """ - Grades each question - gradingModule: the module with all the grading functions (pass in with sys.modules[__name__]) - """ + def addPrereq(self, question, prereq): + self.prereqs[question].add(prereq) - completedQuestions = set([]) - for q in self.questions: - print('\nQuestion %s' % q) - print('=' * (9 + len(q))) - print - self.currentQuestion = q + def grade(self, gradingModule, exceptionMap={}, bonusPic=False): + """ + Grades each question + gradingModule: the module with all the grading functions (pass in with sys.modules[__name__]) + """ - incompleted = self.prereqs[q].difference(completedQuestions) - if len(incompleted) > 0: - prereq = incompleted.pop() - print( -"""*** NOTE: Make sure to complete Question %s before working on Question %s, + completedQuestions = set([]) + for q in self.questions: + print('\nQuestion %s' % q) + print('=' * (9 + len(q))) + print() + self.currentQuestion = q + + incompleted = self.prereqs[q].difference(completedQuestions) + if len(incompleted) > 0: + prereq = incompleted.pop() + print("""*** NOTE: Make sure to complete Question %s before working on Question %s, *** because Question %s builds upon your answer for Question %s. """ % (prereq, q, q, prereq)) - continue + continue - if self.mute: util.mutePrint() - try: - util.TimeoutFunction(getattr(gradingModule, q),1800)(self) # Call the question's function - #TimeoutFunction(getattr(gradingModule, q),1200)(self) # Call the question's function - except Exception as inst: - self.addExceptionMessage(q, inst, traceback) - self.addErrorHints(exceptionMap, inst, q[1]) - except: - self.fail('FAIL: Terminated with a string exception.') - finally: - if self.mute: util.unmutePrint() + if self.mute: + util.mutePrint() + try: + util.TimeoutFunction(getattr(gradingModule, q), 1800)( + self) # Call the question's function + # TimeoutFunction(getattr(gradingModule, q),1200)(self) # Call the question's function + except Exception as inst: + self.addExceptionMessage(q, inst, traceback) + self.addErrorHints(exceptionMap, inst, q[1]) + except: + self.fail('FAIL: Terminated with a string exception.') + finally: + if self.mute: + util.unmutePrint() - if self.points[q] >= self.maxes[q]: - completedQuestions.add(q) + if self.points[q] >= self.maxes[q]: + completedQuestions.add(q) - print('\n### Question %s: %d/%d ###\n' % (q, self.points[q], self.maxes[q])) + print('\n### Question %s: %d/%d ###\n' % + (q, self.points[q], self.maxes[q])) + print('\nFinished at %d:%02d:%02d' % time.localtime()[3:6]) + print("\nProvisional grades\n==================") - print('\nFinished at %d:%02d:%02d' % time.localtime()[3:6]) - print("\nProvisional grades\n==================") - - for q in self.questions: - print('Question %s: %d/%d' % (q, self.points[q], self.maxes[q])) - print('------------------') - print('Total: %d/%d' % (self.points.totalCount(), sum(self.maxes.values()))) - if bonusPic and self.points.totalCount() == 25: - print(""" + for q in self.questions: + print('Question %s: %d/%d' % (q, self.points[q], self.maxes[q])) + print('------------------') + print('Total: %d/%d' % + (self.points.totalCount(), sum(self.maxes.values()))) + if bonusPic and self.points.totalCount() == 25: + print(""" ALL HAIL GRANDPAC. LONG LIVE THE GHOSTBUSTING KING. @@ -131,115 +136,116 @@ class Grades: @@@@@@@@@@@@@@@@@@ """) - print(""" + print(""" Your grades are NOT yet registered. To register your grades, make sure to follow your instructor's guidelines to receive credit on your project. """) - if self.edxOutput: - self.produceOutput() - if self.gsOutput: - self.produceGradeScopeOutput() + if self.edxOutput: + self.produceOutput() + if self.gsOutput: + self.produceGradeScopeOutput() - def addExceptionMessage(self, q, inst, traceback): - """ - Method to format the exception message, this is more complicated because - we need to cgi.escape the traceback but wrap the exception in a
 tag
-    """
-    self.fail('FAIL: Exception raised: %s' % inst)
-    self.addMessage('')
-    for line in traceback.format_exc().split('\n'):
-        self.addMessage(line)
+    def addExceptionMessage(self, q, inst, traceback):
+        """
+        Method to format the exception message, this is more complicated because
+        we need to cgi.escape the traceback but wrap the exception in a 
 tag
+        """
+        self.fail('FAIL: Exception raised: %s' % inst)
+        self.addMessage('')
+        for line in traceback.format_exc().split('\n'):
+            self.addMessage(line)
 
-  def addErrorHints(self, exceptionMap, errorInstance, questionNum):
-    typeOf = str(type(errorInstance))
-    questionName = 'q' + questionNum
-    errorHint = ''
+    def addErrorHints(self, exceptionMap, errorInstance, questionNum):
+        typeOf = str(type(errorInstance))
+        questionName = 'q' + questionNum
+        errorHint = ''
 
-    # question specific error hints
-    if exceptionMap.get(questionName):
-      questionMap = exceptionMap.get(questionName)
-      if (questionMap.get(typeOf)):
-        errorHint = questionMap.get(typeOf)
-    # fall back to general error messages if a question specific
-    # one does not exist
-    if (exceptionMap.get(typeOf)):
-      errorHint = exceptionMap.get(typeOf)
+        # question specific error hints
+        if exceptionMap.get(questionName):
+            questionMap = exceptionMap.get(questionName)
+            if (questionMap.get(typeOf)):
+                errorHint = questionMap.get(typeOf)
+        # fall back to general error messages if a question specific
+        # one does not exist
+        if (exceptionMap.get(typeOf)):
+            errorHint = exceptionMap.get(typeOf)
 
-    # dont include the HTML if we have no error hint
-    if not errorHint:
-      return ''
+        # dont include the HTML if we have no error hint
+        if not errorHint:
+            return ''
 
-    for line in errorHint.split('\n'):
-      self.addMessage(line)
+        for line in errorHint.split('\n'):
+            self.addMessage(line)
 
-  def produceGradeScopeOutput(self):
-    out_dct = {}
+    def produceGradeScopeOutput(self):
+        out_dct = {}
 
-    # total of entire submission
-    total_possible = sum(self.maxes.values())
-    total_score = sum(self.points.values())
-    out_dct['score'] = total_score
-    out_dct['max_score'] = total_possible
-    out_dct['output'] = "Total score (%d / %d)" % (total_score, total_possible)
+        # total of entire submission
+        total_possible = sum(self.maxes.values())
+        total_score = sum(self.points.values())
+        out_dct['score'] = total_score
+        out_dct['max_score'] = total_possible
+        out_dct['output'] = "Total score (%d / %d)" % (
+            total_score, total_possible)
 
-    # individual tests
-    tests_out = []
-    for name in self.questions:
-      test_out = {}
-      # test name
-      test_out['name'] = name
-      # test score
-      test_out['score'] = self.points[name]
-      test_out['max_score'] = self.maxes[name]
-      # others
-      is_correct = self.points[name] >= self.maxes[name]
-      test_out['output'] = "  Question {num} ({points}/{max}) {correct}".format(
-          num=(name[1] if len(name) == 2 else name),
-          points=test_out['score'],
-          max=test_out['max_score'],
-          correct=('X' if not is_correct else ''),
-      )
-      test_out['tags'] = []
-      tests_out.append(test_out)
-    out_dct['tests'] = tests_out
+        # individual tests
+        tests_out = []
+        for name in self.questions:
+            test_out = {}
+            # test name
+            test_out['name'] = name
+            # test score
+            test_out['score'] = self.points[name]
+            test_out['max_score'] = self.maxes[name]
+            # others
+            is_correct = self.points[name] >= self.maxes[name]
+            test_out['output'] = "  Question {num} ({points}/{max}) {correct}".format(
+                num=(name[1] if len(name) == 2 else name),
+                points=test_out['score'],
+                max=test_out['max_score'],
+                correct=('X' if not is_correct else ''),
+            )
+            test_out['tags'] = []
+            tests_out.append(test_out)
+        out_dct['tests'] = tests_out
 
-    # file output
-    with open('gradescope_response.json', 'w') as outfile:
-        json.dump(out_dct, outfile)
-    return
+        # file output
+        with open('gradescope_response.json', 'w') as outfile:
+            json.dump(out_dct, outfile)
+        return
 
-  def produceOutput(self):
-    edxOutput = open('edx_response.html', 'w')
-    edxOutput.write("
") + def produceOutput(self): + edxOutput = open('edx_response.html', 'w') + edxOutput.write("
") - # first sum - total_possible = sum(self.maxes.values()) - total_score = sum(self.points.values()) - checkOrX = '' - if (total_score >= total_possible): - checkOrX = '' - header = """ + # first sum + total_possible = sum(self.maxes.values()) + total_score = sum(self.points.values()) + checkOrX = '' + if (total_score >= total_possible): + checkOrX = '' + header = """

Total score ({total_score} / {total_possible})

- """.format(total_score = total_score, - total_possible = total_possible, - checkOrX = checkOrX - ) - edxOutput.write(header) + """.format(total_score=total_score, + total_possible=total_possible, + checkOrX=checkOrX + ) + edxOutput.write(header) - for q in self.questions: - if len(q) == 2: - name = q[1] - else: - name = q - checkOrX = '' - if (self.points[q] >= self.maxes[q]): - checkOrX = '' - #messages = '\n
\n'.join(self.messages[q]) - messages = "
%s
" % '\n'.join(self.messages[q]) - output = """ + for q in self.questions: + if len(q) == 2: + name = q[1] + else: + name = q + checkOrX = '' + if (self.points[q] >= self.maxes[q]): + checkOrX = '' + #messages = '\n
\n'.join(self.messages[q]) + messages = "
%s
" % '\n'.join(self.messages[q]) + output = """
@@ -250,74 +256,73 @@ to follow your instructor's guidelines to receive credit on your project.
- """.format(q = name, - max = self.maxes[q], - messages = messages, - checkOrX = checkOrX, - points = self.points[q] - ) - # print("*** output for Question %s " % q[1]) - # print(output) - edxOutput.write(output) - edxOutput.write("
") - edxOutput.close() - edxOutput = open('edx_grade', 'w') - edxOutput.write(str(self.points.totalCount())) - edxOutput.close() + """.format(q=name, + max=self.maxes[q], + messages=messages, + checkOrX=checkOrX, + points=self.points[q] + ) + # print "*** output for Question %s " % q[1] + # print output + edxOutput.write(output) + edxOutput.write("
") + edxOutput.close() + edxOutput = open('edx_grade', 'w') + edxOutput.write(str(self.points.totalCount())) + edxOutput.close() - def fail(self, message, raw=False): - "Sets sanity check bit to false and outputs a message" - self.sane = False - self.assignZeroCredit() - self.addMessage(message, raw) + def fail(self, message, raw=False): + "Sets sanity check bit to false and outputs a message" + self.sane = False + self.assignZeroCredit() + self.addMessage(message, raw) - def assignZeroCredit(self): - self.points[self.currentQuestion] = 0 + def assignZeroCredit(self): + self.points[self.currentQuestion] = 0 - def addPoints(self, amt): - self.points[self.currentQuestion] += amt + def addPoints(self, amt): + self.points[self.currentQuestion] += amt - def deductPoints(self, amt): - self.points[self.currentQuestion] -= amt - - def assignFullCredit(self, message="", raw=False): - self.points[self.currentQuestion] = self.maxes[self.currentQuestion] - if message != "": - self.addMessage(message, raw) - - def addMessage(self, message, raw=False): - if not raw: - # We assume raw messages, formatted for HTML, are printed separately - if self.mute: util.unmutePrint() - print('*** ' + message) - if self.mute: util.mutePrint() - message = cgi.escape(message) - self.messages[self.currentQuestion].append(message) - - def addMessageToEmail(self, message): - print("WARNING**** addMessageToEmail is deprecated %s" % message) - for line in message.split('\n'): - pass - #print('%%% ' + line + ' %%%') - #self.messages[self.currentQuestion].append(line) + def deductPoints(self, amt): + self.points[self.currentQuestion] -= amt + def assignFullCredit(self, message="", raw=False): + self.points[self.currentQuestion] = self.maxes[self.currentQuestion] + if message != "": + self.addMessage(message, raw) + def addMessage(self, message, raw=False): + if not raw: + # We assume raw messages, formatted for HTML, are printed separately + if self.mute: + util.unmutePrint() + print('*** ' + message) + if self.mute: + util.mutePrint() + message = cgi.escape(message) + self.messages[self.currentQuestion].append(message) + def addMessageToEmail(self, message): + print("WARNING**** addMessageToEmail is deprecated %s" % message) + for line in message.split('\n'): + pass + # print '%%% ' + line + ' %%%' + # self.messages[self.currentQuestion].append(line) class Counter(dict): - """ - Dict with default 0 - """ - def __getitem__(self, idx): - try: - return dict.__getitem__(self, idx) - except KeyError: - return 0 - - def totalCount(self): """ - Returns the sum of counts for all keys. + Dict with default 0 """ - return sum(self.values()) + def __getitem__(self, idx): + try: + return dict.__getitem__(self, idx) + except KeyError: + return 0 + + def totalCount(self): + """ + Returns the sum of counts for all keys. + """ + return sum(self.values()) diff --git a/graphicsDisplay.py b/graphicsDisplay.py index bd53e9a..b63efc7 100644 --- a/graphicsDisplay.py +++ b/graphicsDisplay.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -13,7 +13,8 @@ from graphicsUtils import * -import math, time +import math +import time from game import Directions ########################### @@ -25,60 +26,61 @@ from game import Directions DEFAULT_GRID_SIZE = 30.0 INFO_PANE_HEIGHT = 35 -BACKGROUND_COLOR = formatColor(0,0,0) +BACKGROUND_COLOR = formatColor(0, 0, 0) WALL_COLOR = formatColor(0.0/255.0, 51.0/255.0, 255.0/255.0) -INFO_PANE_COLOR = formatColor(.4,.4,0) +INFO_PANE_COLOR = formatColor(.4, .4, 0) SCORE_COLOR = formatColor(.9, .9, .9) PACMAN_OUTLINE_WIDTH = 2 PACMAN_CAPTURE_OUTLINE_WIDTH = 4 GHOST_COLORS = [] -GHOST_COLORS.append(formatColor(.9,0,0)) # Red -GHOST_COLORS.append(formatColor(0,.3,.9)) # Blue -GHOST_COLORS.append(formatColor(.98,.41,.07)) # Orange -GHOST_COLORS.append(formatColor(.1,.75,.7)) # Green -GHOST_COLORS.append(formatColor(1.0,0.6,0.0)) # Yellow -GHOST_COLORS.append(formatColor(.4,0.13,0.91)) # Purple +GHOST_COLORS.append(formatColor(.9, 0, 0)) # Red +GHOST_COLORS.append(formatColor(0, .3, .9)) # Blue +GHOST_COLORS.append(formatColor(.98, .41, .07)) # Orange +GHOST_COLORS.append(formatColor(.1, .75, .7)) # Green +GHOST_COLORS.append(formatColor(1.0, 0.6, 0.0)) # Yellow +GHOST_COLORS.append(formatColor(.4, 0.13, 0.91)) # Purple TEAM_COLORS = GHOST_COLORS[:2] GHOST_SHAPE = [ - ( 0, 0.3 ), - ( 0.25, 0.75 ), - ( 0.5, 0.3 ), - ( 0.75, 0.75 ), - ( 0.75, -0.5 ), - ( 0.5, -0.75 ), - (-0.5, -0.75 ), - (-0.75, -0.5 ), - (-0.75, 0.75 ), - (-0.5, 0.3 ), - (-0.25, 0.75 ) - ] + (0, 0.3), + (0.25, 0.75), + (0.5, 0.3), + (0.75, 0.75), + (0.75, -0.5), + (0.5, -0.75), + (-0.5, -0.75), + (-0.75, -0.5), + (-0.75, 0.75), + (-0.5, 0.3), + (-0.25, 0.75) +] GHOST_SIZE = 0.65 -SCARED_COLOR = formatColor(1,1,1) +SCARED_COLOR = formatColor(1, 1, 1) -GHOST_VEC_COLORS = [colorToVector(c) for c in GHOST_COLORS] +GHOST_VEC_COLORS = list(map(colorToVector, GHOST_COLORS)) -PACMAN_COLOR = formatColor(255.0/255.0,255.0/255.0,61.0/255) +PACMAN_COLOR = formatColor(255.0/255.0, 255.0/255.0, 61.0/255) PACMAN_SCALE = 0.5 #pacman_speed = 0.25 # Food -FOOD_COLOR = formatColor(1,1,1) +FOOD_COLOR = formatColor(1, 1, 1) FOOD_SIZE = 0.1 # Laser -LASER_COLOR = formatColor(1,0,0) +LASER_COLOR = formatColor(1, 0, 0) LASER_SIZE = 0.02 # Capsule graphics -CAPSULE_COLOR = formatColor(1,1,1) +CAPSULE_COLOR = formatColor(1, 1, 1) CAPSULE_SIZE = 0.25 # Drawing walls WALL_RADIUS = 0.15 + class InfoPane: def __init__(self, layout, gridSize): self.gridSize = gridSize @@ -89,21 +91,22 @@ class InfoPane: self.textColor = PACMAN_COLOR self.drawPane() - def toScreen(self, pos, y = None): + def toScreen(self, pos, y=None): """ Translates a point relative from the bottom left of the info pane. """ if y == None: - x,y = pos + x, y = pos else: x = pos - x = self.gridSize + x # Margin + x = self.gridSize + x # Margin y = self.base + y - return x,y + return x, y def drawPane(self): - self.scoreText = text( self.toScreen(0, 0 ), self.textColor, "SCORE: 0", "Times", self.fontSize, "bold") + self.scoreText = text(self.toScreen( + 0, 0), self.textColor, "SCORE: 0", "Times", self.fontSize, "bold") def initializeGhostDistances(self, distances): self.ghostDistanceText = [] @@ -115,7 +118,8 @@ class InfoPane: size = 10 for i, d in enumerate(distances): - t = text( self.toScreen(self.width//2 + self.width//8 * i, 0), GHOST_COLORS[i+1], d, "Times", size, "bold") + t = text(self.toScreen(self.width/2 + self.width/8 * i, 0), + GHOST_COLORS[i+1], d, "Times", size, "bold") self.ghostDistanceText.append(t) def updateScore(self, score): @@ -123,12 +127,16 @@ class InfoPane: def setTeam(self, isBlue): text = "RED TEAM" - if isBlue: text = "BLUE TEAM" - self.teamText = text( self.toScreen(300, 0 ), self.textColor, text, "Times", self.fontSize, "bold") + if isBlue: + text = "BLUE TEAM" + self.teamText = text(self.toScreen( + 300, 0), self.textColor, text, "Times", self.fontSize, "bold") def updateGhostDistances(self, distances): - if len(distances) == 0: return - if 'ghostDistanceText' not in dir(self): self.initializeGhostDistances(distances) + if len(distances) == 0: + return + if 'ghostDistanceText' not in dir(self): + self.initializeGhostDistances(distances) else: for i, d in enumerate(distances): changeText(self.ghostDistanceText[i], d) @@ -165,7 +173,7 @@ class PacmanGraphics: def checkNullDisplay(self): return False - def initialize(self, state, isBlue = False): + def initialize(self, state, isBlue=False): self.isBlue = isBlue self.startGraphics(state) @@ -193,11 +201,11 @@ class PacmanGraphics: distx = [] dist.append(distx) for y in range(walls.height): - ( screen_x, screen_y ) = self.to_screen( (x, y) ) - block = square( (screen_x, screen_y), - 0.5 * self.gridSize, - color = BACKGROUND_COLOR, - filled = 1, behind=2) + (screen_x, screen_y) = self.to_screen((x, y)) + block = square((screen_x, screen_y), + 0.5 * self.gridSize, + color=BACKGROUND_COLOR, + filled=1, behind=2) distx.append(block) self.distributionImages = dist @@ -209,14 +217,14 @@ class PacmanGraphics: refresh() def drawAgentObjects(self, state): - self.agentImages = [] # (agentState, image) + self.agentImages = [] # (agentState, image) for index, agent in enumerate(state.agentStates): if agent.isPacman: image = self.drawPacman(agent, index) - self.agentImages.append( (agent, image) ) + self.agentImages.append((agent, image)) else: image = self.drawGhost(agent, index) - self.agentImages.append( (agent, image) ) + self.agentImages.append((agent, image)) refresh() def swapImages(self, agentIndex, newState): @@ -224,20 +232,22 @@ class PacmanGraphics: Changes an image from a ghost to a pacman or vis versa (for capture) """ prevState, prevImage = self.agentImages[agentIndex] - for item in prevImage: remove_from_screen(item) + for item in prevImage: + remove_from_screen(item) if newState.isPacman: image = self.drawPacman(newState, agentIndex) - self.agentImages[agentIndex] = (newState, image ) + self.agentImages[agentIndex] = (newState, image) else: image = self.drawGhost(newState, agentIndex) - self.agentImages[agentIndex] = (newState, image ) + self.agentImages[agentIndex] = (newState, image) refresh() def update(self, newState): agentIndex = newState._agentMoved agentState = newState.agentStates[agentIndex] - if self.agentImages[agentIndex][0].isPacman != agentState.isPacman: self.swapImages(agentIndex, agentState) + if self.agentImages[agentIndex][0].isPacman != agentState.isPacman: + self.swapImages(agentIndex, agentState) prevState, prevImage = self.agentImages[agentIndex] if agentState.isPacman: self.animatePacman(agentState, prevState, prevImage) @@ -279,14 +289,14 @@ class PacmanGraphics: width = PACMAN_CAPTURE_OUTLINE_WIDTH return [circle(screen_point, PACMAN_SCALE * self.gridSize, - fillColor = fillColor, outlineColor = outlineColor, - endpoints = endpoints, - width = width)] + fillColor=fillColor, outlineColor=outlineColor, + endpoints=endpoints, + width=width)] - def getEndpoints(self, direction, position=(0,0)): + def getEndpoints(self, direction, position=(0, 0)): x, y = position pos = x - int(x) + y - int(y) - width = 30 + 80 * math.sin(math.pi* pos) + width = 30 + 80 * math.sin(math.pi * pos) delta = width / 2 if (direction == 'West'): @@ -301,7 +311,7 @@ class PacmanGraphics: def movePacman(self, position, direction, image): screenPosition = self.to_screen(position) - endpoints = self.getEndpoints( direction, position ) + endpoints = self.getEndpoints(direction, position) r = PACMAN_SCALE * self.gridSize moveCircle(image[0], screenPosition, r, endpoints) refresh() @@ -317,13 +327,15 @@ class PacmanGraphics: fx, fy = self.getPosition(prevPacman) px, py = self.getPosition(pacman) frames = 4.0 - for i in range(1,int(frames) + 1): - pos = px*i/frames + fx*(frames-i)/frames, py*i/frames + fy*(frames-i)/frames + for i in range(1, int(frames) + 1): + pos = px*i/frames + fx * \ + (frames-i)/frames, py*i/frames + fy*(frames-i)/frames self.movePacman(pos, self.getDirection(pacman), image) refresh() sleep(abs(self.frameTime) / frames) else: - self.movePacman(self.getPosition(pacman), self.getDirection(pacman), image) + self.movePacman(self.getPosition(pacman), + self.getDirection(pacman), image) refresh() def getGhostColor(self, ghost, ghostIndex): @@ -335,13 +347,14 @@ class PacmanGraphics: def drawGhost(self, ghost, agentIndex): pos = self.getPosition(ghost) dir = self.getDirection(ghost) - (screen_x, screen_y) = (self.to_screen(pos) ) + (screen_x, screen_y) = (self.to_screen(pos)) coords = [] for (x, y) in GHOST_SHAPE: - coords.append((x*self.gridSize*GHOST_SIZE + screen_x, y*self.gridSize*GHOST_SIZE + screen_y)) + coords.append((x*self.gridSize*GHOST_SIZE + screen_x, + y*self.gridSize*GHOST_SIZE + screen_y)) colour = self.getGhostColor(ghost, agentIndex) - body = polygon(coords, colour, filled = 1) + body = polygon(coords, colour, filled=1) WHITE = formatColor(1.0, 1.0, 1.0) BLACK = formatColor(0.0, 0.0, 0.0) @@ -355,10 +368,14 @@ class PacmanGraphics: dx = 0.2 if dir == 'West': dx = -0.2 - leftEye = circle((screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2, WHITE, WHITE) - rightEye = circle((screen_x+self.gridSize*GHOST_SIZE*(0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2, WHITE, WHITE) - leftPupil = circle((screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08, BLACK, BLACK) - rightPupil = circle((screen_x+self.gridSize*GHOST_SIZE*(0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08, BLACK, BLACK) + leftEye = circle((screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx/1.5), screen_y - + self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2, WHITE, WHITE) + rightEye = circle((screen_x+self.gridSize*GHOST_SIZE*(0.3+dx/1.5), screen_y - + self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2, WHITE, WHITE) + leftPupil = circle((screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx), screen_y - + self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08, BLACK, BLACK) + rightPupil = circle((screen_x+self.gridSize*GHOST_SIZE*(0.3+dx), screen_y - + self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08, BLACK, BLACK) ghostImageParts = [] ghostImageParts.append(body) ghostImageParts.append(leftEye) @@ -369,7 +386,7 @@ class PacmanGraphics: return ghostImageParts def moveEyes(self, pos, dir, eyes): - (screen_x, screen_y) = (self.to_screen(pos) ) + (screen_x, screen_y) = (self.to_screen(pos)) dx = 0 dy = 0 if dir == 'North': @@ -380,10 +397,14 @@ class PacmanGraphics: dx = 0.2 if dir == 'West': dx = -0.2 - moveCircle(eyes[0],(screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2) - moveCircle(eyes[1],(screen_x+self.gridSize*GHOST_SIZE*(0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2) - moveCircle(eyes[2],(screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08) - moveCircle(eyes[3],(screen_x+self.gridSize*GHOST_SIZE*(0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08) + moveCircle(eyes[0], (screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx/1.5), screen_y - + self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2) + moveCircle(eyes[1], (screen_x+self.gridSize*GHOST_SIZE*(0.3+dx/1.5), screen_y - + self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2) + moveCircle(eyes[2], (screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx), screen_y - + self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08) + moveCircle(eyes[3], (screen_x+self.gridSize*GHOST_SIZE*(0.3+dx), screen_y - + self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08) def moveGhost(self, ghost, ghostIndex, prevGhost, ghostImageParts): old_x, old_y = self.to_screen(self.getPosition(prevGhost)) @@ -399,43 +420,48 @@ class PacmanGraphics: else: color = GHOST_COLORS[ghostIndex] edit(ghostImageParts[0], ('fill', color), ('outline', color)) - self.moveEyes(self.getPosition(ghost), self.getDirection(ghost), ghostImageParts[-4:]) + self.moveEyes(self.getPosition(ghost), + self.getDirection(ghost), ghostImageParts[-4:]) refresh() def getPosition(self, agentState): - if agentState.configuration == None: return (-1000, -1000) + if agentState.configuration == None: + return (-1000, -1000) return agentState.getPosition() def getDirection(self, agentState): - if agentState.configuration == None: return Directions.STOP + if agentState.configuration == None: + return Directions.STOP return agentState.configuration.getDirection() def finish(self): end_graphics() def to_screen(self, point): - ( x, y ) = point + (x, y) = point #y = self.height - y x = (x + 1)*self.gridSize - y = (self.height - y)*self.gridSize - return ( x, y ) + y = (self.height - y)*self.gridSize + return (x, y) # Fixes some TK issue with off-center circles def to_screen2(self, point): - ( x, y ) = point + (x, y) = point #y = self.height - y x = (x + 1)*self.gridSize - y = (self.height - y)*self.gridSize - return ( x, y ) + y = (self.height - y)*self.gridSize + return (x, y) def drawWalls(self, wallMatrix): wallColor = WALL_COLOR for xNum, x in enumerate(wallMatrix): - if self.capture and (xNum * 2) < wallMatrix.width: wallColor = TEAM_COLORS[0] - if self.capture and (xNum * 2) >= wallMatrix.width: wallColor = TEAM_COLORS[1] + if self.capture and (xNum * 2) < wallMatrix.width: + wallColor = TEAM_COLORS[0] + if self.capture and (xNum * 2) >= wallMatrix.width: + wallColor = TEAM_COLORS[1] for yNum, cell in enumerate(x): - if cell: # There's a wall here + if cell: # There's a wall here pos = (xNum, yNum) screen = self.to_screen(pos) screen2 = self.to_screen2(pos) @@ -453,66 +479,90 @@ class PacmanGraphics: # NE quadrant if (not nIsWall) and (not eIsWall): # inner circle - circle(screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (0,91), 'arc') + circle(screen2, WALL_RADIUS * self.gridSize, + wallColor, wallColor, (0, 91), 'arc') if (nIsWall) and (not eIsWall): # vertical line - line(add(screen, (self.gridSize*WALL_RADIUS, 0)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-0.5)-1)), wallColor) + line(add(screen, (self.gridSize*WALL_RADIUS, 0)), add(screen, + (self.gridSize*WALL_RADIUS, self.gridSize*(-0.5)-1)), wallColor) if (not nIsWall) and (eIsWall): # horizontal line - line(add(screen, (0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+1, self.gridSize*(-1)*WALL_RADIUS)), wallColor) + line(add(screen, (0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, + (self.gridSize*0.5+1, self.gridSize*(-1)*WALL_RADIUS)), wallColor) if (nIsWall) and (eIsWall) and (not neIsWall): # outer circle - circle(add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (180,271), 'arc') - line(add(screen, (self.gridSize*2*WALL_RADIUS-1, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+1, self.gridSize*(-1)*WALL_RADIUS)), wallColor) - line(add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS+1)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-0.5))), wallColor) + circle(add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), + WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (180, 271), 'arc') + line(add(screen, (self.gridSize*2*WALL_RADIUS-1, self.gridSize*(-1)*WALL_RADIUS)), + add(screen, (self.gridSize*0.5+1, self.gridSize*(-1)*WALL_RADIUS)), wallColor) + line(add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS+1)), + add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-0.5))), wallColor) # NW quadrant if (not nIsWall) and (not wIsWall): # inner circle - circle(screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (90,181), 'arc') + circle(screen2, WALL_RADIUS * self.gridSize, + wallColor, wallColor, (90, 181), 'arc') if (nIsWall) and (not wIsWall): # vertical line - line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, 0)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-0.5)-1)), wallColor) + line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, 0)), add(screen, + (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-0.5)-1)), wallColor) if (not nIsWall) and (wIsWall): # horizontal line - line(add(screen, (0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5)-1, self.gridSize*(-1)*WALL_RADIUS)), wallColor) + line(add(screen, (0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, + (self.gridSize*(-0.5)-1, self.gridSize*(-1)*WALL_RADIUS)), wallColor) if (nIsWall) and (wIsWall) and (not nwIsWall): # outer circle - circle(add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (270,361), 'arc') - line(add(screen, (self.gridSize*(-2)*WALL_RADIUS+1, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5), self.gridSize*(-1)*WALL_RADIUS)), wallColor) - line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS+1)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-0.5))), wallColor) + circle(add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), + WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (270, 361), 'arc') + line(add(screen, (self.gridSize*(-2)*WALL_RADIUS+1, self.gridSize*(-1)*WALL_RADIUS)), + add(screen, (self.gridSize*(-0.5), self.gridSize*(-1)*WALL_RADIUS)), wallColor) + line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS+1)), + add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-0.5))), wallColor) # SE quadrant if (not sIsWall) and (not eIsWall): # inner circle - circle(screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (270,361), 'arc') + circle(screen2, WALL_RADIUS * self.gridSize, + wallColor, wallColor, (270, 361), 'arc') if (sIsWall) and (not eIsWall): # vertical line - line(add(screen, (self.gridSize*WALL_RADIUS, 0)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(0.5)+1)), wallColor) + line(add(screen, (self.gridSize*WALL_RADIUS, 0)), add(screen, + (self.gridSize*WALL_RADIUS, self.gridSize*(0.5)+1)), wallColor) if (not sIsWall) and (eIsWall): # horizontal line - line(add(screen, (0, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+1, self.gridSize*(1)*WALL_RADIUS)), wallColor) + line(add(screen, (0, self.gridSize*(1)*WALL_RADIUS)), add(screen, + (self.gridSize*0.5+1, self.gridSize*(1)*WALL_RADIUS)), wallColor) if (sIsWall) and (eIsWall) and (not seIsWall): # outer circle - circle(add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (90,181), 'arc') - line(add(screen, (self.gridSize*2*WALL_RADIUS-1, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5, self.gridSize*(1)*WALL_RADIUS)), wallColor) - line(add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS-1)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(0.5))), wallColor) + circle(add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), + WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (90, 181), 'arc') + line(add(screen, (self.gridSize*2*WALL_RADIUS-1, self.gridSize*(1)*WALL_RADIUS)), + add(screen, (self.gridSize*0.5, self.gridSize*(1)*WALL_RADIUS)), wallColor) + line(add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS-1)), + add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(0.5))), wallColor) # SW quadrant if (not sIsWall) and (not wIsWall): # inner circle - circle(screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (180,271), 'arc') + circle(screen2, WALL_RADIUS * self.gridSize, + wallColor, wallColor, (180, 271), 'arc') if (sIsWall) and (not wIsWall): # vertical line - line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, 0)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(0.5)+1)), wallColor) + line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, 0)), add(screen, + (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(0.5)+1)), wallColor) if (not sIsWall) and (wIsWall): # horizontal line - line(add(screen, (0, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5)-1, self.gridSize*(1)*WALL_RADIUS)), wallColor) + line(add(screen, (0, self.gridSize*(1)*WALL_RADIUS)), add(screen, + (self.gridSize*(-0.5)-1, self.gridSize*(1)*WALL_RADIUS)), wallColor) if (sIsWall) and (wIsWall) and (not swIsWall): # outer circle - circle(add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (0,91), 'arc') - line(add(screen, (self.gridSize*(-2)*WALL_RADIUS+1, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5), self.gridSize*(1)*WALL_RADIUS)), wallColor) - line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS-1)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(0.5))), wallColor) + circle(add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), + WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (0, 91), 'arc') + line(add(screen, (self.gridSize*(-2)*WALL_RADIUS+1, self.gridSize*(1)*WALL_RADIUS)), + add(screen, (self.gridSize*(-0.5), self.gridSize*(1)*WALL_RADIUS)), wallColor) + line(add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS-1)), + add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(0.5))), wallColor) def isWall(self, x, y, walls): if x < 0 or y < 0: @@ -521,43 +571,45 @@ class PacmanGraphics: return False return walls[x][y] - def drawFood(self, foodMatrix ): + def drawFood(self, foodMatrix): foodImages = [] color = FOOD_COLOR for xNum, x in enumerate(foodMatrix): - if self.capture and (xNum * 2) <= foodMatrix.width: color = TEAM_COLORS[0] - if self.capture and (xNum * 2) > foodMatrix.width: color = TEAM_COLORS[1] + if self.capture and (xNum * 2) <= foodMatrix.width: + color = TEAM_COLORS[0] + if self.capture and (xNum * 2) > foodMatrix.width: + color = TEAM_COLORS[1] imageRow = [] foodImages.append(imageRow) for yNum, cell in enumerate(x): - if cell: # There's food here - screen = self.to_screen((xNum, yNum )) - dot = circle( screen, - FOOD_SIZE * self.gridSize, - outlineColor = color, fillColor = color, - width = 1) + if cell: # There's food here + screen = self.to_screen((xNum, yNum)) + dot = circle(screen, + FOOD_SIZE * self.gridSize, + outlineColor=color, fillColor=color, + width=1) imageRow.append(dot) else: imageRow.append(None) return foodImages - def drawCapsules(self, capsules ): + def drawCapsules(self, capsules): capsuleImages = {} for capsule in capsules: - ( screen_x, screen_y ) = self.to_screen(capsule) - dot = circle( (screen_x, screen_y), - CAPSULE_SIZE * self.gridSize, - outlineColor = CAPSULE_COLOR, - fillColor = CAPSULE_COLOR, - width = 1) + (screen_x, screen_y) = self.to_screen(capsule) + dot = circle((screen_x, screen_y), + CAPSULE_SIZE * self.gridSize, + outlineColor=CAPSULE_COLOR, + fillColor=CAPSULE_COLOR, + width=1) capsuleImages[capsule] = dot return capsuleImages - def removeFood(self, cell, foodImages ): + def removeFood(self, cell, foodImages): x, y = cell remove_from_screen(foodImages[x][y]) - def removeCapsule(self, cell, capsuleImages ): + def removeCapsule(self, cell, capsuleImages): x, y = cell remove_from_screen(capsuleImages[(x, y)]) @@ -570,12 +622,13 @@ class PacmanGraphics: self.clearExpandedCells() self.expandedCells = [] for k, cell in enumerate(cells): - screenPos = self.to_screen( cell) - cellColor = formatColor(*[(n-k) * c * .5 / n + .25 for c in baseColor]) + screenPos = self.to_screen(cell) + cellColor = formatColor( + *[(n-k) * c * .5 / n + .25 for c in baseColor]) block = square(screenPos, - 0.5 * self.gridSize, - color = cellColor, - filled = 1, behind=2) + 0.5 * self.gridSize, + color=cellColor, + filled=1, behind=2) self.expandedCells.append(block) if self.frameTime < 0: refresh() @@ -585,36 +638,38 @@ class PacmanGraphics: for cell in self.expandedCells: remove_from_screen(cell) - def updateDistributions(self, distributions): "Draws an agent's belief distributions" # copy all distributions so we don't change their state - distributions = map(lambda x: x.copy(), distributions) + distributions = [x.copy() for x in distributions] if self.distributionImages == None: self.drawDistributions(self.previousState) for x in range(len(self.distributionImages)): for y in range(len(self.distributionImages[0])): image = self.distributionImages[x][y] - weights = [dist[ (x,y) ] for dist in distributions] + weights = [dist[(x, y)] for dist in distributions] if sum(weights) != 0: pass # Fog of war - color = [0.0,0.0,0.0] - colors = GHOST_VEC_COLORS[1:] # With Pacman - if self.capture: colors = GHOST_VEC_COLORS + color = [0.0, 0.0, 0.0] + colors = GHOST_VEC_COLORS[1:] # With Pacman + if self.capture: + colors = GHOST_VEC_COLORS for weight, gcolor in zip(weights, colors): - color = [min(1.0, c + 0.95 * g * weight ** .3) for c,g in zip(color, gcolor)] + color = [min(1.0, c + 0.95 * g * weight ** .3) + for c, g in zip(color, gcolor)] changeColor(image, formatColor(*color)) refresh() + class FirstPersonPacmanGraphics(PacmanGraphics): - def __init__(self, zoom = 1.0, showGhosts = True, capture = False, frameTime=0): + def __init__(self, zoom=1.0, showGhosts=True, capture=False, frameTime=0): PacmanGraphics.__init__(self, zoom, frameTime=frameTime) self.showGhosts = showGhosts self.capture = capture - def initialize(self, state, isBlue = False): + def initialize(self, state, isBlue=False): self.isBlue = isBlue PacmanGraphics.startGraphics(self, state) @@ -654,6 +709,7 @@ class FirstPersonPacmanGraphics(PacmanGraphics): else: return PacmanGraphics.getPosition(self, ghostState) + def add(x, y): return (x[0] + y[0], x[1] + y[1]) @@ -669,11 +725,14 @@ POSTSCRIPT_OUTPUT_DIR = 'frames' FRAME_NUMBER = 0 import os + def saveFrame(): "Saves the current graphical output as a postscript file" global SAVE_POSTSCRIPT, FRAME_NUMBER, POSTSCRIPT_OUTPUT_DIR - if not SAVE_POSTSCRIPT: return - if not os.path.exists(POSTSCRIPT_OUTPUT_DIR): os.mkdir(POSTSCRIPT_OUTPUT_DIR) + if not SAVE_POSTSCRIPT: + return + if not os.path.exists(POSTSCRIPT_OUTPUT_DIR): + os.mkdir(POSTSCRIPT_OUTPUT_DIR) name = os.path.join(POSTSCRIPT_OUTPUT_DIR, 'frame_%08d.ps' % FRAME_NUMBER) FRAME_NUMBER += 1 - writePostscript(name) # writes the current canvas + writePostscript(name) # writes the current canvas diff --git a/graphicsUtils.py b/graphicsUtils.py index 22e6ae1..9a22066 100644 --- a/graphicsUtils.py +++ b/graphicsUtils.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -33,17 +33,21 @@ _canvas_col = None # Current colour (set to black below) _canvas_tsize = 12 _canvas_tserifs = 0 + def formatColor(r, g, b): return '#%02x%02x%02x' % (int(r * 255), int(g * 255), int(b * 255)) + def colorToVector(color): - return list(map(lambda x: int(x, 16) / 256.0, [color[1:3], color[3:5], color[5:7]])) + return [int(x, 16) / 256.0 for x in [color[1:3], color[3:5], color[5:7]]] + if _Windows: _canvas_tfonts = ['times new roman', 'lucida console'] else: _canvas_tfonts = ['times', 'lucidasans-24'] - pass # XXX need defaults here + pass # XXX need defaults here + def sleep(secs): global _root_window @@ -54,6 +58,7 @@ def sleep(secs): _root_window.after(int(1000 * secs), _root_window.quit) _root_window.mainloop() + def begin_graphics(width=640, height=480, color=formatColor(0, 0, 0), title=None): global _root_window, _canvas, _canvas_x, _canvas_y, _canvas_xs, _canvas_ys, _bg_color @@ -85,32 +90,37 @@ def begin_graphics(width=640, height=480, color=formatColor(0, 0, 0), title=None raise # Bind to key-down and key-up events - _root_window.bind( "", _keypress ) - _root_window.bind( "", _keyrelease ) - _root_window.bind( "", _clear_keys ) - _root_window.bind( "", _clear_keys ) - _root_window.bind( "", _leftclick ) - _root_window.bind( "", _rightclick ) - _root_window.bind( "", _rightclick ) - _root_window.bind( "", _ctrl_leftclick) + _root_window.bind("", _keypress) + _root_window.bind("", _keyrelease) + _root_window.bind("", _clear_keys) + _root_window.bind("", _clear_keys) + _root_window.bind("", _leftclick) + _root_window.bind("", _rightclick) + _root_window.bind("", _rightclick) + _root_window.bind("", _ctrl_leftclick) _clear_keys() + _leftclick_loc = None _rightclick_loc = None _ctrl_leftclick_loc = None + def _leftclick(event): global _leftclick_loc _leftclick_loc = (event.x, event.y) + def _rightclick(event): global _rightclick_loc _rightclick_loc = (event.x, event.y) + def _ctrl_leftclick(event): global _ctrl_leftclick_loc _ctrl_leftclick_loc = (event.x, event.y) + def wait_for_click(): while True: global _leftclick_loc @@ -130,16 +140,21 @@ def wait_for_click(): return val, 'ctrl_left' sleep(0.05) + def draw_background(): - corners = [(0,0), (0, _canvas_ys), (_canvas_xs, _canvas_ys), (_canvas_xs, 0)] - polygon(corners, _bg_color, fillColor=_bg_color, filled=True, smoothed=False) + corners = [(0, 0), (0, _canvas_ys), + (_canvas_xs, _canvas_ys), (_canvas_xs, 0)] + polygon(corners, _bg_color, fillColor=_bg_color, + filled=True, smoothed=False) + def _destroy_window(event=None): sys.exit(0) # global _root_window # _root_window.destroy() # _root_window = None - #print("DESTROY") + # print "DESTROY" + def end_graphics(): global _root_window, _canvas, _mouse_enabled @@ -156,30 +171,37 @@ def end_graphics(): _mouse_enabled = 0 _clear_keys() + def clear_screen(background=None): global _canvas_x, _canvas_y _canvas.delete('all') draw_background() _canvas_x, _canvas_y = 0, _canvas_ys + def polygon(coords, outlineColor, fillColor=None, filled=1, smoothed=1, behind=0, width=1): c = [] for coord in coords: c.append(coord[0]) c.append(coord[1]) - if fillColor == None: fillColor = outlineColor - if filled == 0: fillColor = "" - poly = _canvas.create_polygon(c, outline=outlineColor, fill=fillColor, smooth=smoothed, width=width) + if fillColor == None: + fillColor = outlineColor + if filled == 0: + fillColor = "" + poly = _canvas.create_polygon( + c, outline=outlineColor, fill=fillColor, smooth=smoothed, width=width) if behind > 0: - _canvas.tag_lower(poly, behind) # Higher should be more visible + _canvas.tag_lower(poly, behind) # Higher should be more visible return poly + def square(pos, r, color, filled=1, behind=0): x, y = pos coords = [(x - r, y - r), (x + r, y - r), (x + r, y + r), (x - r, y + r)] return polygon(coords, color, color, filled, 0, behind=behind) -def circle(pos, r, outlineColor, fillColor=None, endpoints=None, style='pieslice', width=2): + +def circle(pos, r, outlineColor, fillColor, endpoints=None, style='pieslice', width=2): x, y = pos x0, x1 = x - r - 1, x + r y0, y1 = y - r - 1, y + r @@ -187,20 +209,23 @@ def circle(pos, r, outlineColor, fillColor=None, endpoints=None, style='pieslice e = [0, 359] else: e = list(endpoints) - while e[0] > e[1]: e[1] = e[1] + 360 + while e[0] > e[1]: + e[1] = e[1] + 360 - return _canvas.create_arc(x0, y0, x1, y1, outline=outlineColor, fill=fillColor or outlineColor, + return _canvas.create_arc(x0, y0, x1, y1, outline=outlineColor, fill=fillColor, extent=e[1] - e[0], start=e[0], style=style, width=width) + def image(pos, file="../../blueghost.gif"): x, y = pos # img = PhotoImage(file=file) - return _canvas.create_image(x, y, image = tkinter.PhotoImage(file=file), anchor = tkinter.NW) + return _canvas.create_image(x, y, image=tkinter.PhotoImage(file=file), anchor=tkinter.NW) def refresh(): _canvas.update_idletasks() + def moveCircle(id, pos, r, endpoints=None): global _canvas_x, _canvas_y @@ -213,7 +238,8 @@ def moveCircle(id, pos, r, endpoints=None): e = [0, 359] else: e = list(endpoints) - while e[0] > e[1]: e[1] = e[1] + 360 + while e[0] > e[1]: + e[1] = e[1] + 360 if os.path.isfile('flag'): edit(id, ('extent', e[1] - e[0])) @@ -221,23 +247,28 @@ def moveCircle(id, pos, r, endpoints=None): edit(id, ('start', e[0]), ('extent', e[1] - e[0])) move_to(id, x0, y0) + def edit(id, *args): _canvas.itemconfigure(id, **dict(args)) + def text(pos, color, contents, font='Helvetica', size=12, style='normal', anchor="nw"): global _canvas_x, _canvas_y x, y = pos font = (font, str(size), style) return _canvas.create_text(x, y, fill=color, text=contents, font=font, anchor=anchor) + def changeText(id, newText, font=None, size=12, style='normal'): _canvas.itemconfigure(id, text=newText) if font != None: _canvas.itemconfigure(id, font=(font, '-%d' % size, style)) + def changeColor(id, newColor): _canvas.itemconfigure(id, fill=newColor) + def line(here, there, color=formatColor(0, 0, 0), width=2): x0, y0 = here[0], here[1] x1, y1 = there[0], there[1] @@ -249,63 +280,71 @@ def line(here, there, color=formatColor(0, 0, 0), width=2): # We bind to key-down and key-up events. + _keysdown = {} _keyswaiting = {} # This holds an unprocessed key release. We delay key releases by up to # one call to keys_pressed() to get round a problem with auto repeat. _got_release = None + def _keypress(event): global _got_release - #remap_arrows(event) + # remap_arrows(event) _keysdown[event.keysym] = 1 _keyswaiting[event.keysym] = 1 -# print(event.char, event.keycode) +# print event.char, event.keycode _got_release = None + def _keyrelease(event): global _got_release - #remap_arrows(event) + # remap_arrows(event) try: del _keysdown[event.keysym] except: pass _got_release = 1 + def remap_arrows(event): # TURN ARROW PRESSES INTO LETTERS (SHOULD BE IN KEYBOARD AGENT) if event.char in ['a', 's', 'd', 'w']: return - if event.keycode in [37, 101]: # LEFT ARROW (win / x) + if event.keycode in [37, 101]: # LEFT ARROW (win / x) event.char = 'a' - if event.keycode in [38, 99]: # UP ARROW + if event.keycode in [38, 99]: # UP ARROW event.char = 'w' - if event.keycode in [39, 102]: # RIGHT ARROW + if event.keycode in [39, 102]: # RIGHT ARROW event.char = 'd' - if event.keycode in [40, 104]: # DOWN ARROW + if event.keycode in [40, 104]: # DOWN ARROW event.char = 's' + def _clear_keys(event=None): global _keysdown, _got_release, _keyswaiting _keysdown = {} _keyswaiting = {} _got_release = None + def keys_pressed(d_o_e=lambda arg: _root_window.dooneevent(arg), d_w=tkinter._tkinter.DONT_WAIT): d_o_e(d_w) if _got_release: d_o_e(d_w) - return _keysdown.keys() + return list(_keysdown.keys()) + def keys_waiting(): global _keyswaiting - keys = _keyswaiting.keys() + keys = list(_keyswaiting.keys()) _keyswaiting = {} return keys # Block for a list of keys... + def wait_for_keys(): keys = [] while keys == []: @@ -313,29 +352,34 @@ def wait_for_keys(): sleep(0.05) return keys + def remove_from_screen(x, d_o_e=lambda arg: _root_window.dooneevent(arg), d_w=tkinter._tkinter.DONT_WAIT): _canvas.delete(x) d_o_e(d_w) + def _adjust_coords(coord_list, x, y): for i in range(0, len(coord_list), 2): coord_list[i] = coord_list[i] + x coord_list[i + 1] = coord_list[i + 1] + y return coord_list + def move_to(object, x, y=None, d_o_e=lambda arg: _root_window.dooneevent(arg), d_w=tkinter._tkinter.DONT_WAIT): if y is None: - try: x, y = x - except: raise 'incomprehensible coordinates' + try: + x, y = x + except: + raise Exception('incomprehensible coordinates') horiz = True newCoords = [] - current_x, current_y = _canvas.coords(object)[0:2] # first point - for coord in _canvas.coords(object): + current_x, current_y = _canvas.coords(object)[0:2] # first point + for coord in _canvas.coords(object): if horiz: inc = x - current_x else: @@ -347,16 +391,19 @@ def move_to(object, x, y=None, _canvas.coords(object, *newCoords) d_o_e(d_w) + def move_by(object, x, y=None, d_o_e=lambda arg: _root_window.dooneevent(arg), d_w=tkinter._tkinter.DONT_WAIT, lift=False): if y is None: - try: x, y = x - except: raise Exception('incomprehensible coordinates') + try: + x, y = x + except: + raise Exception('incomprehensible coordinates') horiz = True newCoords = [] - for coord in _canvas.coords(object): + for coord in _canvas.coords(object): if horiz: inc = x else: @@ -370,14 +417,16 @@ def move_by(object, x, y=None, if lift: _canvas.tag_raise(object) + def writePostscript(filename): "Writes the current canvas to a postscript file." - psfile = open(filename, 'w') + psfile = file(filename, 'w') psfile.write(_canvas.postscript(pageanchor='sw', - y='0.c', - x='0.c')) + y='0.c', + x='0.c')) psfile.close() + ghost_shape = [ (0, - 0.5), (0.25, - 0.75), @@ -390,7 +439,7 @@ ghost_shape = [ (- 0.75, - 0.75), (- 0.5, - 0.5), (- 0.25, - 0.75) - ] +] if __name__ == '__main__': begin_graphics() diff --git a/keyboardAgents.py b/keyboardAgents.py index 624021d..e8d6812 100644 --- a/keyboardAgents.py +++ b/keyboardAgents.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -16,27 +16,28 @@ from game import Agent from game import Directions import random + class KeyboardAgent(Agent): """ An agent controlled by the keyboard. """ # NOTE: Arrow keys also work. - WEST_KEY = 'a' - EAST_KEY = 'd' + WEST_KEY = 'a' + EAST_KEY = 'd' NORTH_KEY = 'w' SOUTH_KEY = 's' STOP_KEY = 'q' - def __init__( self, index = 0 ): + def __init__(self, index=0): self.lastMove = Directions.STOP self.index = index self.keys = [] - def getAction( self, state): + def getAction(self, state): from graphicsUtils import keys_waiting from graphicsUtils import keys_pressed - keys = list(keys_waiting()) + list(keys_pressed()) + keys = keys_waiting() + keys_pressed() if keys != []: self.keys = keys @@ -48,7 +49,8 @@ class KeyboardAgent(Agent): if self.lastMove in legal: move = self.lastMove - if (self.STOP_KEY in self.keys) and Directions.STOP in legal: move = Directions.STOP + if (self.STOP_KEY in self.keys) and Directions.STOP in legal: + move = Directions.STOP if move not in legal: move = random.choice(legal) @@ -58,27 +60,36 @@ class KeyboardAgent(Agent): def getMove(self, legal): move = Directions.STOP - if (self.WEST_KEY in self.keys or 'Left' in self.keys) and Directions.WEST in legal: move = Directions.WEST - if (self.EAST_KEY in self.keys or 'Right' in self.keys) and Directions.EAST in legal: move = Directions.EAST - if (self.NORTH_KEY in self.keys or 'Up' in self.keys) and Directions.NORTH in legal: move = Directions.NORTH - if (self.SOUTH_KEY in self.keys or 'Down' in self.keys) and Directions.SOUTH in legal: move = Directions.SOUTH + if (self.WEST_KEY in self.keys or 'Left' in self.keys) and Directions.WEST in legal: + move = Directions.WEST + if (self.EAST_KEY in self.keys or 'Right' in self.keys) and Directions.EAST in legal: + move = Directions.EAST + if (self.NORTH_KEY in self.keys or 'Up' in self.keys) and Directions.NORTH in legal: + move = Directions.NORTH + if (self.SOUTH_KEY in self.keys or 'Down' in self.keys) and Directions.SOUTH in legal: + move = Directions.SOUTH return move + class KeyboardAgent2(KeyboardAgent): """ A second agent controlled by the keyboard. """ # NOTE: Arrow keys also work. - WEST_KEY = 'j' - EAST_KEY = "l" + WEST_KEY = 'j' + EAST_KEY = "l" NORTH_KEY = 'i' SOUTH_KEY = 'k' STOP_KEY = 'u' def getMove(self, legal): move = Directions.STOP - if (self.WEST_KEY in self.keys) and Directions.WEST in legal: move = Directions.WEST - if (self.EAST_KEY in self.keys) and Directions.EAST in legal: move = Directions.EAST - if (self.NORTH_KEY in self.keys) and Directions.NORTH in legal: move = Directions.NORTH - if (self.SOUTH_KEY in self.keys) and Directions.SOUTH in legal: move = Directions.SOUTH + if (self.WEST_KEY in self.keys) and Directions.WEST in legal: + move = Directions.WEST + if (self.EAST_KEY in self.keys) and Directions.EAST in legal: + move = Directions.EAST + if (self.NORTH_KEY in self.keys) and Directions.NORTH in legal: + move = Directions.NORTH + if (self.SOUTH_KEY in self.keys) and Directions.SOUTH in legal: + move = Directions.SOUTH return move diff --git a/layout.py b/layout.py index ebba32a..115c959 100644 --- a/layout.py +++ b/layout.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -20,6 +20,7 @@ from functools import reduce VISIBILITY_MATRIX_CACHE = {} + class Layout: """ A Layout manages the static information about the game board. @@ -27,7 +28,7 @@ class Layout: def __init__(self, layoutText): self.width = len(layoutText[0]) - self.height= len(layoutText) + self.height = len(layoutText) self.walls = Grid(self.width, self.height, False) self.food = Grid(self.width, self.height, False) self.capsules = [] @@ -45,41 +46,46 @@ class Layout: global VISIBILITY_MATRIX_CACHE if reduce(str.__add__, self.layoutText) not in VISIBILITY_MATRIX_CACHE: from game import Directions - vecs = [(-0.5,0), (0.5,0),(0,-0.5),(0,0.5)] - dirs = [Directions.NORTH, Directions.SOUTH, Directions.WEST, Directions.EAST] - vis = Grid(self.width, self.height, {Directions.NORTH:set(), Directions.SOUTH:set(), Directions.EAST:set(), Directions.WEST:set(), Directions.STOP:set()}) + vecs = [(-0.5, 0), (0.5, 0), (0, -0.5), (0, 0.5)] + dirs = [Directions.NORTH, Directions.SOUTH, + Directions.WEST, Directions.EAST] + vis = Grid(self.width, self.height, {Directions.NORTH: set(), Directions.SOUTH: set( + ), Directions.EAST: set(), Directions.WEST: set(), Directions.STOP: set()}) for x in range(self.width): for y in range(self.height): if self.walls[x][y] == False: for vec, direction in zip(vecs, dirs): dx, dy = vec nextx, nexty = x + dx, y + dy - while (nextx + nexty) != int(nextx) + int(nexty) or not self.walls[int(nextx)][int(nexty)] : + while (nextx + nexty) != int(nextx) + int(nexty) or not self.walls[int(nextx)][int(nexty)]: vis[x][y][direction].add((nextx, nexty)) nextx, nexty = x + dx, y + dy self.visibility = vis VISIBILITY_MATRIX_CACHE[reduce(str.__add__, self.layoutText)] = vis else: - self.visibility = VISIBILITY_MATRIX_CACHE[reduce(str.__add__, self.layoutText)] + self.visibility = VISIBILITY_MATRIX_CACHE[reduce( + str.__add__, self.layoutText)] def isWall(self, pos): x, col = pos return self.walls[x][col] def getRandomLegalPosition(self): - x = random.choice(range(self.width)) - y = random.choice(range(self.height)) - while self.isWall( (x, y) ): - x = random.choice(range(self.width)) - y = random.choice(range(self.height)) - return (x,y) + x = random.choice(list(range(self.width))) + y = random.choice(list(range(self.height))) + while self.isWall((x, y)): + x = random.choice(list(range(self.width))) + y = random.choice(list(range(self.height))) + return (x, y) def getRandomCorner(self): - poses = [(1,1), (1, self.height - 2), (self.width - 2, 1), (self.width - 2, self.height - 2)] + poses = [(1, 1), (1, self.height - 2), (self.width - 2, 1), + (self.width - 2, self.height - 2)] return random.choice(poses) def getFurthestCorner(self, pacPos): - poses = [(1,1), (1, self.height - 2), (self.width - 2, 1), (self.width - 2, self.height - 2)] + poses = [(1, 1), (1, self.height - 2), (self.width - 2, 1), + (self.width - 2, self.height - 2)] dist, pos = max([(manhattanDistance(p, pacPos), p) for p in poses]) return pos @@ -112,7 +118,7 @@ class Layout: layoutChar = layoutText[maxY - y][x] self.processLayoutChar(x, y, layoutChar) self.agentPositions.sort() - self.agentPositions = [ ( i == 0, pos) for i, pos in self.agentPositions] + self.agentPositions = [(i == 0, pos) for i, pos in self.agentPositions] def processLayoutChar(self, x, y, layoutChar): if layoutChar == '%': @@ -122,29 +128,37 @@ class Layout: elif layoutChar == 'o': self.capsules.append((x, y)) elif layoutChar == 'P': - self.agentPositions.append( (0, (x, y) ) ) + self.agentPositions.append((0, (x, y))) elif layoutChar in ['G']: - self.agentPositions.append( (1, (x, y) ) ) + self.agentPositions.append((1, (x, y))) self.numGhosts += 1 - elif layoutChar in ['1', '2', '3', '4']: - self.agentPositions.append( (int(layoutChar), (x,y))) + elif layoutChar in ['1', '2', '3', '4']: + self.agentPositions.append((int(layoutChar), (x, y))) self.numGhosts += 1 -def getLayout(name, back = 2): + + +def getLayout(name, back=2): if name.endswith('.lay'): layout = tryToLoad('layouts/' + name) - if layout == None: layout = tryToLoad(name) + if layout == None: + layout = tryToLoad(name) else: layout = tryToLoad('layouts/' + name + '.lay') - if layout == None: layout = tryToLoad(name + '.lay') + if layout == None: + layout = tryToLoad(name + '.lay') if layout == None and back >= 0: curdir = os.path.abspath('.') os.chdir('..') - layout = getLayout(name, back -1) + layout = getLayout(name, back - 1) os.chdir(curdir) return layout + def tryToLoad(fullname): - if(not os.path.exists(fullname)): return None + if(not os.path.exists(fullname)): + return None f = open(fullname) - try: return Layout([line.strip() for line in f]) - finally: f.close() + try: + return Layout([line.strip() for line in f]) + finally: + f.close() diff --git a/layouts/bigCorners.lay b/layouts/bigCorners.lay deleted file mode 100644 index 4d89d7b..0000000 --- a/layouts/bigCorners.lay +++ /dev/null @@ -1,37 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%. % %.% -% %%%%% % %%% %%% %%%%%%% % % -% % % % % % % % -%%%%% %%%%% %%% % % % %%% %%%%% % %%% -% % % % % % % % % % % % % -% %%% % % % %%% %%%%% %%% % %%% %%% % -% % % % % % % % % -%%% %%%%%%%%% %%%%%%% %%% %%% % % % % -% % % % % % % -% % %%%%% % %%% % % %%% % %%% %%% % % -% % % % % % % % % % % % % % -% % % %%%%%%% % %%%%%%%%% %%% % %%% % -% % % % % % % % % % -%%% %%% % %%%%% %%%%% %%% %%% %%%%% % -% % % % % % % % % -% % % % % % %%% %%% %%% % % % % % % -% % % % % %% % % % % % % % % % -% % %%%%% % %%% %%% % %%% %%% %%%%% -% % % % % % % % % % % -% %%% % % % %%% %%% %%%%%%%%% % %%% -% % % % % % % -% %%% %%%%%%%%%%%%%%%%%%%%% % % %%% % -% % % % -% % % %%%%% %%% % % % % %%%%%%%%%%%%% -% % % % % % % % % % % % -% % %%% %%% % % % %%%%%%%%% %%% % % % -% % % % % % %P % % % % % % -% %%% %%% %%% % %%% % % %%%%% % %%%%% -% % % % % % % % -%%% % %%%%% %%%%% %%% %%% % %%% % %%% -% % % % % % % % % % % % % % % -% % %%% % % % % %%%%%%%%% % % % % % % -% % % % -% % % %%% %%% %%%%%%% %%% %%% %%% % -%.% % % % % .% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/bigMaze.lay b/layouts/bigMaze.lay deleted file mode 100644 index e11fade..0000000 --- a/layouts/bigMaze.lay +++ /dev/null @@ -1,37 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % % % % % % % -% %%%%%%% % %%% % %%% %%% %%%%%%% % % -% % % % % % % % -%%%%% %%%%% %%% % % % %%% %%%%% % %%% -% % % % % % % % % % % % % % -% %%% % % % %%% %%%%% %%% % %%% %%% % -% % % % % % % % % -%%% %%%%%%%%% %%%%%%% %%% %%% % % % % -% % % % % % % -% % %%%%% % %%% % % %%% % %%% %%% % % -% % % % % % % % % % % % % % -% % % %%%%%%% % %%%%%%%%% %%% % %%% % -% % % % % % % % % % -%%% %%% % %%%%% %%%%% %%% %%% %%%%% % -% % % % % % % % % % % % -% % % % % %%% %%% %%% %%% % % % % % % -% % % % % % % % % -%%% %%%%%%% % % %%%%% %%% % %%% %%%%% -% % % % % % % % % % -%%%%% % % %%%%%%%%% %%%%%%%%%%% % %%% -% % % % % % % % % -% %%% %%%%% %%%%%%%%% %%%%% % % %%% % -% % % % % % % -% % % %%%%% %%% % % % % %%%%%%%%%%%%% -% % % % % % % % % % % % -% % %%% %%% % % % %%%%%%%%% %%% % % % -% % % % % % % % % % % % % -% %%% %%% %%%%% %%% % % %%%%% % %%%%% -% % % % % % % % % -%%% % %%%%% %%%%% %%% %%% % %%% % %%% -% % % % % % % % % % % % % % % -% % %%% % % % % %%%%%%%%% % % % % % % -% % % % % % -% % % % %%% %%% %%%%%%% %%% %%% %%% % -%.% % % % % % % % P% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/bigSafeSearch.lay b/layouts/bigSafeSearch.lay deleted file mode 100644 index b5fd414..0000000 --- a/layouts/bigSafeSearch.lay +++ /dev/null @@ -1,8 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%.%.........%% G % o%%%%.....% -%.%.%%%%%%%.%%%%%% %%%%%%%.%%.% -%............%...%............% -%%%%%...%%%.. ..%.%...%.%%% -%o%%%.%%%%%.%%%%%%%.%%%.%.%%%%% -% ..........Po...%...%. o% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/layouts/bigSearch.lay b/layouts/bigSearch.lay deleted file mode 100644 index bb59eb8..0000000 --- a/layouts/bigSearch.lay +++ /dev/null @@ -1,15 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%.....%.................%.....% -%.%%%.%.%%%.%%%%%%%.%%%.%.....% -%.%...%.%......%......%.%.....% -%...%%%.%.%%%%.%.%%%%...%%%...% -%%%.%.%.%.%......%..%.%...%.%%% -%...%.%%%.%.%%% %%%.%.%%%.%...% -%.%%%.......% %.......%%%.% -%...%.%%%%%.%%%%%%%.%.%%%.%...% -%%%.%...%.%....%....%.%...%.%%% -%...%%%.%.%%%%.%.%%%%.%.%%%...% -%.......%......%......%.....%.% -%.....%.%%%.%%%%%%%.%%%.%.%%%.% -%.....%........P....%...%.....% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/layouts/boxSearch.lay b/layouts/boxSearch.lay deleted file mode 100644 index 4a113fc..0000000 --- a/layouts/boxSearch.lay +++ /dev/null @@ -1,14 +0,0 @@ -%%%%%%%%%%%%%% -%. . . . . % % -% % % -%. . . . . %G% -% % % -%. . . . . % % -% % % -%. . . . . % % -% P %G% -%. . . . . % % -% % % -%. . . . . % % -% % % -%%%%%%%%%%%%%% diff --git a/layouts/contoursMaze.lay b/layouts/contoursMaze.lay deleted file mode 100644 index a068956..0000000 --- a/layouts/contoursMaze.lay +++ /dev/null @@ -1,11 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% % -% P % -% % -% % -% % -%. % -%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/greedySearch.lay b/layouts/greedySearch.lay deleted file mode 100644 index 4072363..0000000 --- a/layouts/greedySearch.lay +++ /dev/null @@ -1,8 +0,0 @@ -%%%%%% -%....% -% %%.% -% %%.% -%.P .% -%.%%%% -%....% -%%%%%% \ No newline at end of file diff --git a/layouts/mediumCorners.lay b/layouts/mediumCorners.lay deleted file mode 100644 index 6a39756..0000000 --- a/layouts/mediumCorners.lay +++ /dev/null @@ -1,14 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%. % % % %.% -% % % %%%%%% %%%%%%% % % -% % % % % % -%%%%% %%%%% %%% %% %%%%% % %%% -% % % % % % % % % -% %%% % % % %%%%%%%% %%% %%% % -% % %% % % % % -%%% % %%%%%%% %%%% %%% % % % % -% % %% % % % -% % %%%%% % %%%% % %%% %%% % % -% % % % % % %%% % -%. %P%%%%% % %%% % .% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/mediumDottedMaze.lay b/layouts/mediumDottedMaze.lay deleted file mode 100644 index 103f818..0000000 --- a/layouts/mediumDottedMaze.lay +++ /dev/null @@ -1,18 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%% %%% %%%%%%%% % -% %% % % %%% %%% %% ... % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % % %% %% %% ... % -% %% % % % % % %%%% %%% %%%%%% % -% % % % % % %% %%%%%%%% ... % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% ... % -% %%%%%% %%%%%%% %% %%%%%% % -%%%%%% % %%%% %% % ... % -% %%%%%% %%%%% % %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%%%% %%%%%%%%%%% %% %% % -%%%%%%%%%% %%%%%% % -%. %%%%%%%%%%%%%%%% ...... % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/mediumMaze.lay b/layouts/mediumMaze.lay deleted file mode 100644 index 55c1236..0000000 --- a/layouts/mediumMaze.lay +++ /dev/null @@ -1,18 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% % -% %% % % %%%%%%% %% % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % %% %% % -% %% % % % % % %%%% %%% %%%%%% % -% % % % % % %% %%%%%%%% % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% % -% %%%%%% %%%%%%% %% %%%%%% % -%%%%%% % %%%% %% % % -% %%%%%% %%%%% % %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%%%% %%%%%%%%%%% %% %% % -%%%%%%%%%% %%%%%% % -%. %%%%%%%%%%%%%%%% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/mediumSafeSearch.lay b/layouts/mediumSafeSearch.lay deleted file mode 100644 index e7d6b1c..0000000 --- a/layouts/mediumSafeSearch.lay +++ /dev/null @@ -1,6 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%.% ....%% G %%%%%% o%%.% -%.%o%%%%%%%.%%%%%%% %%%%%.% -% %%%.%%%%%.%%%%%%%.%%%.%.%%%.% -% ..........Po...%.........% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/layouts/mediumScaryMaze.lay b/layouts/mediumScaryMaze.lay deleted file mode 100644 index 65d4c33..0000000 --- a/layouts/mediumScaryMaze.lay +++ /dev/null @@ -1,18 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%% %%% %%%%%%%% % -% %% % % %%% %%% %%GG % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % % %%GG %% % -% %% % % % % % %%%%% %%% %%%%%% % -% %% % % % % %% %%%%%%%%% % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% % -% %%% %% %%%%%%% %% %%%%%% % -%%%%%% % % %% %% % -% %%%%%% %% %% %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%% %%%%% %%%%%% % -%%%%%%%% % %%%%%% % -%. %%%%%%%%%%%%%%%% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/mediumSearch.lay b/layouts/mediumSearch.lay deleted file mode 100644 index 2f8af42..0000000 --- a/layouts/mediumSearch.lay +++ /dev/null @@ -1,8 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%............%%%%%............% -%%%.%...%%%.........%.%...%.%%% -%...%%%.%.%%%%.%.%%%%%%.%%%...% -%.%.....%......%......%.....%.% -%.%%%.%%%%%.%%%%%%%.%%%.%.%%%%% -%.....%........P....%...%.....% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/layouts/oddSearch.lay b/layouts/oddSearch.lay deleted file mode 100644 index 2ddbc9a..0000000 --- a/layouts/oddSearch.lay +++ /dev/null @@ -1,7 +0,0 @@ -%%%%%%%%%%%%%%%%%%%% -%...%.........%%...% -%.%.%.%%%%%%%%%%.%.% -%..................% -%%%%%%%%.%.%%%%%%%P% -%%%%%%%%....... % -%%%%%%%%%%%%%%%%%%%% diff --git a/layouts/openMaze.lay b/layouts/openMaze.lay deleted file mode 100644 index 5dee689..0000000 --- a/layouts/openMaze.lay +++ /dev/null @@ -1,23 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% % % -% % % -% % % -% % % -% % % -% % % % -% % % % -% % % % -% % % % -% % % % -% % % % -% % % % -%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% -% % % -% % % -% % % -% % -% % -% % -%. % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/openSearch.lay b/layouts/openSearch.lay deleted file mode 100644 index f02d21d..0000000 --- a/layouts/openSearch.lay +++ /dev/null @@ -1,7 +0,0 @@ -%%%%%%%%%%%%%%%%%%%% -%..................% -%..................% -%........P.........% -%..................% -%..................% -%%%%%%%%%%%%%%%%%%%% diff --git a/layouts/smallMaze.lay b/layouts/smallMaze.lay deleted file mode 100644 index 72d3ffc..0000000 --- a/layouts/smallMaze.lay +++ /dev/null @@ -1,10 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%% -% %% % % % -% %%%%%% % %%%%%% % -%%%%%% P % % -% % %%%%%% %% %%%%% -% %%%% % % % -% %%% %%% % % -%%%%%%%%%% %%%%%% % -%. %% % -%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/layouts/smallSafeSearch.lay b/layouts/smallSafeSearch.lay deleted file mode 100644 index b97feaa..0000000 --- a/layouts/smallSafeSearch.lay +++ /dev/null @@ -1,15 +0,0 @@ -%%%%%%%%% -%.. % G % -%%% %%%%% -% % -%%%%%%% % -% % -% %%%%% % -% % % -%%%%% % % -% %o% -% %%%%%%% -% .% -%%%%%%%.% -%Po .% -%%%%%%%%% diff --git a/layouts/smallSearch.lay b/layouts/smallSearch.lay deleted file mode 100644 index c2321d4..0000000 --- a/layouts/smallSearch.lay +++ /dev/null @@ -1,5 +0,0 @@ -%%%%%%%%%%%%%%%%%%%% -%. ...P .% -%.%%.%%.%%.%%.%% %.% -% %% %..... %.% -%%%%%%%%%%%%%%%%%%%% diff --git a/layouts/testMaze.lay b/layouts/testMaze.lay deleted file mode 100644 index 4d259a4..0000000 --- a/layouts/testMaze.lay +++ /dev/null @@ -1,3 +0,0 @@ -%%%%%%%%%% -%. P% -%%%%%%%%%% diff --git a/layouts/testSearch.lay b/layouts/testSearch.lay deleted file mode 100644 index 25bad23..0000000 --- a/layouts/testSearch.lay +++ /dev/null @@ -1,5 +0,0 @@ -%%%%% -%.P % -%%% % -%. % -%%%%% diff --git a/layouts/tinyCorners.lay b/layouts/tinyCorners.lay deleted file mode 100644 index 526c880..0000000 --- a/layouts/tinyCorners.lay +++ /dev/null @@ -1,8 +0,0 @@ -%%%%%%%% -%. .% -% P % -% %%%% % -% % % -% % %%%% -%.% .% -%%%%%%%% diff --git a/layouts/tinyMaze.lay b/layouts/tinyMaze.lay deleted file mode 100644 index f7035a5..0000000 --- a/layouts/tinyMaze.lay +++ /dev/null @@ -1,7 +0,0 @@ -%%%%%%% -% P% -% %%% % -% % % -%% %% -%. %%%% -%%%%%%% diff --git a/layouts/tinySafeSearch.lay b/layouts/tinySafeSearch.lay deleted file mode 100644 index fea6860..0000000 --- a/layouts/tinySafeSearch.lay +++ /dev/null @@ -1,7 +0,0 @@ -%%%%%%%%% -% G %...% -%%%%%%% % -%Po % -%.%%.%%.% -%.%%....% -%%%%%%%%% diff --git a/layouts/tinySearch.lay b/layouts/tinySearch.lay deleted file mode 100644 index c51f4b0..0000000 --- a/layouts/tinySearch.lay +++ /dev/null @@ -1,7 +0,0 @@ -%%%%%%%%% -%.. ..% -%%%%.%% % -% P % -%.%% %%.% -%.%. .% -%%%%%%%%% diff --git a/layouts/trickySearch.lay b/layouts/trickySearch.lay deleted file mode 100644 index 4a607e6..0000000 --- a/layouts/trickySearch.lay +++ /dev/null @@ -1,7 +0,0 @@ -%%%%%%%%%%%%%%%%%%%% -%. ..% % -%.%%.%%.%%.%%.%% % % -% P % % -%%%%%%%%%%%%%%%%%% % -%..... % -%%%%%%%%%%%%%%%%%%%% diff --git a/multiAgents.py b/multiAgents.py new file mode 100644 index 0000000..02b0a94 --- /dev/null +++ b/multiAgents.py @@ -0,0 +1,178 @@ +# multiAgents.py +# -------------- +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). + + +from util import manhattanDistance +from game import Directions +import random, util + +from game import Agent + +class ReflexAgent(Agent): + """ + A reflex agent chooses an action at each choice point by examining + its alternatives via a state evaluation function. + + The code below is provided as a guide. You are welcome to change + it in any way you see fit, so long as you don't touch our method + headers. + """ + + + def getAction(self, gameState): + """ + You do not need to change this method, but you're welcome to. + + getAction chooses among the best options according to the evaluation function. + + Just like in the previous project, getAction takes a GameState and returns + some Directions.X for some X in the set {NORTH, SOUTH, WEST, EAST, STOP} + """ + # Collect legal moves and successor states + legalMoves = gameState.getLegalActions() + + # Choose one of the best actions + scores = [self.evaluationFunction(gameState, action) for action in legalMoves] + bestScore = max(scores) + bestIndices = [index for index in range(len(scores)) if scores[index] == bestScore] + chosenIndex = random.choice(bestIndices) # Pick randomly among the best + + "Add more of your code here if you want to" + + return legalMoves[chosenIndex] + + def evaluationFunction(self, currentGameState, action): + """ + Design a better evaluation function here. + + The evaluation function takes in the current and proposed successor + GameStates (pacman.py) and returns a number, where higher numbers are better. + + The code below extracts some useful information from the state, like the + remaining food (newFood) and Pacman position after moving (newPos). + newScaredTimes holds the number of moves that each ghost will remain + scared because of Pacman having eaten a power pellet. + + Print out these variables to see what you're getting, then combine them + to create a masterful evaluation function. + """ + # Useful information you can extract from a GameState (pacman.py) + successorGameState = currentGameState.generatePacmanSuccessor(action) + newPos = successorGameState.getPacmanPosition() + newFood = successorGameState.getFood() + newGhostStates = successorGameState.getGhostStates() + newScaredTimes = [ghostState.scaredTimer for ghostState in newGhostStates] + + "*** YOUR CODE HERE ***" + return successorGameState.getScore() + +def scoreEvaluationFunction(currentGameState): + """ + This default evaluation function just returns the score of the state. + The score is the same one displayed in the Pacman GUI. + + This evaluation function is meant for use with adversarial search agents + (not reflex agents). + """ + return currentGameState.getScore() + +class MultiAgentSearchAgent(Agent): + """ + This class provides some common elements to all of your + multi-agent searchers. Any methods defined here will be available + to the MinimaxPacmanAgent, AlphaBetaPacmanAgent & ExpectimaxPacmanAgent. + + You *do not* need to make any changes here, but you can if you want to + add functionality to all your adversarial search agents. Please do not + remove anything, however. + + Note: this is an abstract class: one that should not be instantiated. It's + only partially specified, and designed to be extended. Agent (game.py) + is another abstract class. + """ + + def __init__(self, evalFn = 'scoreEvaluationFunction', depth = '2'): + self.index = 0 # Pacman is always agent index 0 + self.evaluationFunction = util.lookup(evalFn, globals()) + self.depth = int(depth) + +class MinimaxAgent(MultiAgentSearchAgent): + """ + Your minimax agent (question 2) + """ + + def getAction(self, gameState): + """ + Returns the minimax action from the current gameState using self.depth + and self.evaluationFunction. + + Here are some method calls that might be useful when implementing minimax. + + gameState.getLegalActions(agentIndex): + Returns a list of legal actions for an agent + agentIndex=0 means Pacman, ghosts are >= 1 + + gameState.generateSuccessor(agentIndex, action): + Returns the successor game state after an agent takes an action + + gameState.getNumAgents(): + Returns the total number of agents in the game + + gameState.isWin(): + Returns whether or not the game state is a winning state + + gameState.isLose(): + Returns whether or not the game state is a losing state + """ + "*** YOUR CODE HERE ***" + util.raiseNotDefined() + +class AlphaBetaAgent(MultiAgentSearchAgent): + """ + Your minimax agent with alpha-beta pruning (question 3) + """ + + def getAction(self, gameState): + """ + Returns the minimax action using self.depth and self.evaluationFunction + """ + "*** YOUR CODE HERE ***" + util.raiseNotDefined() + +class ExpectimaxAgent(MultiAgentSearchAgent): + """ + Your expectimax agent (question 4) + """ + + def getAction(self, gameState): + """ + Returns the expectimax action using self.depth and self.evaluationFunction + + All ghosts should be modeled as choosing uniformly at random from their + legal moves. + """ + "*** YOUR CODE HERE ***" + util.raiseNotDefined() + +def betterEvaluationFunction(currentGameState): + """ + Your extreme ghost-hunting, pellet-nabbing, food-gobbling, unstoppable + evaluation function (question 5). + + DESCRIPTION: + """ + "*** YOUR CODE HERE ***" + util.raiseNotDefined() + +# Abbreviation +better = betterEvaluationFunction diff --git a/multiagentTestClasses.py b/multiagentTestClasses.py new file mode 100644 index 0000000..f437a33 --- /dev/null +++ b/multiagentTestClasses.py @@ -0,0 +1,578 @@ +# multiagentTestClasses.py +# ------------------------ +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). + + +# A minimax tree which interfaces like gameState +# state.getNumAgents() +# state.isWin() +# state.isLose() +# state.generateSuccessor(agentIndex, action) +# state.getScore() +# used by multiAgents.scoreEvaluationFunction, which is the default +# +import testClasses +import json + +from collections import defaultdict +from pprint import PrettyPrinter +pp = PrettyPrinter() + +from game import Agent +from pacman import GameState +from ghostAgents import RandomGhost, DirectionalGhost +import random +import math +import traceback +import sys +import os +import layout +import pacman +import autograder +# import grading + +VERBOSE = False + + +class MultiagentTreeState(object): + def __init__(self, problem, state): + self.problem = problem + self.state = state + + def generateSuccessor(self, agentIndex, action): + if VERBOSE: + print("generateSuccessor(%s, %s, %s) -> %s" % (self.state, agentIndex, + action, self.problem.stateToSuccessorMap[self.state][action])) + successor = self.problem.stateToSuccessorMap[self.state][action] + self.problem.generatedStates.add(successor) + return MultiagentTreeState(self.problem, successor) + + def getScore(self): + if VERBOSE: + print("getScore(%s) -> %s" % + (self.state, self.problem.evaluation[self.state])) + if self.state not in self.problem.evaluation: + raise Exception( + 'getScore() called on non-terminal state or before maximum depth achieved.') + return float(self.problem.evaluation[self.state]) + + def getLegalActions(self, agentIndex=0): + if VERBOSE: + print("getLegalActions(%s) -> %s" % + (self.state, self.problem.stateToActions[self.state])) + # if len(self.problem.stateToActions[self.state]) == 0: + # print "WARNING: getLegalActions called on leaf state %s" % (self.state,) + return list(self.problem.stateToActions[self.state]) + + def isWin(self): + if VERBOSE: + print("isWin(%s) -> %s" % + (self.state, self.state in self.problem.winStates)) + return self.state in self.problem.winStates + + def isLose(self): + if VERBOSE: + print("isLose(%s) -> %s" % + (self.state, self.state in self.problem.loseStates)) + return self.state in self.problem.loseStates + + def getNumAgents(self): + if VERBOSE: + print("getNumAgents(%s) -> %s" % + (self.state, self.problem.numAgents)) + return self.problem.numAgents + + +class MultiagentTreeProblem(object): + def __init__(self, numAgents, startState, winStates, loseStates, successors, evaluation): + self.startState = MultiagentTreeState(self, startState) + + self.numAgents = numAgents + self.winStates = winStates + self.loseStates = loseStates + self.evaluation = evaluation + self.successors = successors + + self.reset() + + self.stateToSuccessorMap = defaultdict(dict) + self.stateToActions = defaultdict(list) + for state, action, nextState in successors: + self.stateToActions[state].append(action) + self.stateToSuccessorMap[state][action] = nextState + + def reset(self): + self.generatedStates = set([self.startState.state]) + + +def parseTreeProblem(testDict): + numAgents = int(testDict["num_agents"]) + startState = testDict["start_state"] + winStates = set(testDict["win_states"].split(" ")) + loseStates = set(testDict["lose_states"].split(" ")) + successors = [] + + evaluation = {} + for line in testDict["evaluation"].split('\n'): + tokens = line.split() + if len(tokens) == 2: + state, value = tokens + evaluation[state] = float(value) + else: + raise Exception("[parseTree] Bad evaluation line: |%s|" % (line,)) + + for line in testDict["successors"].split('\n'): + tokens = line.split() + if len(tokens) == 3: + state, action, nextState = tokens + successors.append((state, action, nextState)) + else: + raise Exception("[parseTree] Bad successor line: |%s|" % (line,)) + + return MultiagentTreeProblem(numAgents, startState, winStates, loseStates, successors, evaluation) + + +def run(lay, layName, pac, ghosts, disp, nGames=1, name='games'): + """ + Runs a few games and outputs their statistics. + """ + starttime = time.time() + print('*** Running %s on' % name, layName, '%d time(s).' % nGames) + games = pacman.runGames(lay, pac, ghosts, disp, + nGames, False, catchExceptions=True, timeout=120) + print('*** Finished running %s on' % name, layName, + 'after %d seconds.' % (time.time() - starttime)) + stats = {'time': time.time() - starttime, 'wins': [g.state.isWin() for g in games].count(True), 'games': games, 'scores': [g.state.getScore() for g in games], + 'timeouts': [g.agentTimeout for g in games].count(True), 'crashes': [g.agentCrashed for g in games].count(True)} + print('*** Won %d out of %d games. Average score: %f ***' % + (stats['wins'], len(games), sum(stats['scores']) * 1.0 / len(games))) + return stats + + +class GradingAgent(Agent): + def __init__(self, seed, studentAgent, optimalActions, altDepthActions, partialPlyBugActions): + # save student agent and actions of refernce agents + self.studentAgent = studentAgent + self.optimalActions = optimalActions + self.altDepthActions = altDepthActions + self.partialPlyBugActions = partialPlyBugActions + # create fields for storing specific wrong actions + self.suboptimalMoves = [] + self.wrongStatesExplored = -1 + # boolean vectors represent types of implementation the student could have + self.actionsConsistentWithOptimal = [ + True for i in range(len(optimalActions[0]))] + self.actionsConsistentWithAlternativeDepth = [ + True for i in range(len(altDepthActions[0]))] + self.actionsConsistentWithPartialPlyBug = [ + True for i in range(len(partialPlyBugActions[0]))] + # keep track of elapsed moves + self.stepCount = 0 + self.seed = seed + + def registerInitialState(self, state): + if 'registerInitialState' in dir(self.studentAgent): + self.studentAgent.registerInitialState(state) + random.seed(self.seed) + + def getAction(self, state): + GameState.getAndResetExplored() + studentAction = (self.studentAgent.getAction(state), + len(GameState.getAndResetExplored())) + optimalActions = self.optimalActions[self.stepCount] + altDepthActions = self.altDepthActions[self.stepCount] + partialPlyBugActions = self.partialPlyBugActions[self.stepCount] + studentOptimalAction = False + curRightStatesExplored = False + for i in range(len(optimalActions)): + if studentAction[0] in optimalActions[i][0]: + studentOptimalAction = True + else: + self.actionsConsistentWithOptimal[i] = False + if studentAction[1] == int(optimalActions[i][1]): + curRightStatesExplored = True + if not curRightStatesExplored and self.wrongStatesExplored < 0: + self.wrongStatesExplored = 1 + for i in range(len(altDepthActions)): + if studentAction[0] not in altDepthActions[i]: + self.actionsConsistentWithAlternativeDepth[i] = False + for i in range(len(partialPlyBugActions)): + if studentAction[0] not in partialPlyBugActions[i]: + self.actionsConsistentWithPartialPlyBug[i] = False + if not studentOptimalAction: + self.suboptimalMoves.append( + (state, studentAction[0], optimalActions[0][0][0])) + self.stepCount += 1 + random.seed(self.seed + self.stepCount) + return optimalActions[0][0][0] + + def getSuboptimalMoves(self): + return self.suboptimalMoves + + def getWrongStatesExplored(self): + return self.wrongStatesExplored + + def checkFailure(self): + """ + Return +n if have n suboptimal moves. + Return -1 if have only off by one depth moves. + Return 0 otherwise. + """ + if self.wrongStatesExplored > 0: + return -3 + if self.actionsConsistentWithOptimal.count(True) > 0: + return 0 + elif self.actionsConsistentWithPartialPlyBug.count(True) > 0: + return -2 + elif self.actionsConsistentWithAlternativeDepth.count(True) > 0: + return -1 + else: + return len(self.suboptimalMoves) + + +class PolyAgent(Agent): + def __init__(self, seed, multiAgents, ourPacOptions, depth): + # prepare our pacman agents + solutionAgents, alternativeDepthAgents, partialPlyBugAgents = self.construct_our_pacs( + multiAgents, ourPacOptions) + for p in solutionAgents: + p.depth = depth + for p in partialPlyBugAgents: + p.depth = depth + for p in alternativeDepthAgents[:2]: + p.depth = max(1, depth - 1) + for p in alternativeDepthAgents[2:]: + p.depth = depth + 1 + self.solutionAgents = solutionAgents + self.alternativeDepthAgents = alternativeDepthAgents + self.partialPlyBugAgents = partialPlyBugAgents + # prepare fields for storing the results + self.optimalActionLists = [] + self.alternativeDepthLists = [] + self.partialPlyBugLists = [] + self.seed = seed + self.stepCount = 0 + + def select(self, list, indices): + """ + Return a sublist of elements given by indices in list. + """ + return [list[i] for i in indices] + + def construct_our_pacs(self, multiAgents, keyword_dict): + pacs_without_stop = [multiAgents.StaffMultiAgentSearchAgent( + **keyword_dict) for i in range(3)] + keyword_dict['keepStop'] = 'True' + pacs_with_stop = [multiAgents.StaffMultiAgentSearchAgent( + **keyword_dict) for i in range(3)] + keyword_dict['usePartialPlyBug'] = 'True' + partial_ply_bug_pacs = [ + multiAgents.StaffMultiAgentSearchAgent(**keyword_dict)] + keyword_dict['keepStop'] = 'False' + partial_ply_bug_pacs = partial_ply_bug_pacs + \ + [multiAgents.StaffMultiAgentSearchAgent(**keyword_dict)] + for pac in pacs_with_stop + pacs_without_stop + partial_ply_bug_pacs: + pac.verbose = False + ourpac = [pacs_with_stop[0], pacs_without_stop[0]] + alternative_depth_pacs = self.select( + pacs_with_stop + pacs_without_stop, [1, 4, 2, 5]) + return (ourpac, alternative_depth_pacs, partial_ply_bug_pacs) + + def registerInitialState(self, state): + for agent in self.solutionAgents + self.alternativeDepthAgents: + if 'registerInitialState' in dir(agent): + agent.registerInitialState(state) + random.seed(self.seed) + + def getAction(self, state): + # survey agents + GameState.getAndResetExplored() + optimalActionLists = [] + for agent in self.solutionAgents: + optimalActionLists.append((agent.getBestPacmanActions( + state)[0], len(GameState.getAndResetExplored()))) + alternativeDepthLists = [agent.getBestPacmanActions( + state)[0] for agent in self.alternativeDepthAgents] + partialPlyBugLists = [agent.getBestPacmanActions( + state)[0] for agent in self.partialPlyBugAgents] + # record responses + self.optimalActionLists.append(optimalActionLists) + self.alternativeDepthLists.append(alternativeDepthLists) + self.partialPlyBugLists.append(partialPlyBugLists) + self.stepCount += 1 + random.seed(self.seed + self.stepCount) + return optimalActionLists[0][0][0] + + def getTraces(self): + # return traces from individual agents + return (self.optimalActionLists, self.alternativeDepthLists, self.partialPlyBugLists) + + +class PacmanGameTreeTest(testClasses.TestCase): + + def __init__(self, question, testDict): + super(PacmanGameTreeTest, self).__init__(question, testDict) + self.seed = int(self.testDict['seed']) + self.alg = self.testDict['alg'] + self.layout_text = self.testDict['layout'] + self.layout_name = self.testDict['layoutName'] + self.depth = int(self.testDict['depth']) + self.max_points = int(self.testDict['max_points']) + + def execute(self, grades, moduleDict, solutionDict): + # load student code and staff code solutions + multiAgents = moduleDict['multiAgents'] + studentAgent = getattr(multiAgents, self.alg)(depth=self.depth) + allActions = [json.loads(x) + for x in solutionDict['optimalActions'].split('\n')] + altDepthActions = [json.loads( + x) for x in solutionDict['altDepthActions'].split('\n')] + partialPlyBugActions = [json.loads( + x) for x in solutionDict['partialPlyBugActions'].split('\n')] + # set up game state and play a game + random.seed(self.seed) + lay = layout.Layout([l.strip() for l in self.layout_text.split('\n')]) + pac = GradingAgent(self.seed, studentAgent, allActions, + altDepthActions, partialPlyBugActions) + # check return codes and assign grades + disp = self.question.getDisplay() + stats = run(lay, self.layout_name, pac, [DirectionalGhost( + i + 1) for i in range(2)], disp, name=self.alg) + if stats['timeouts'] > 0: + self.addMessage('Agent timed out on smallClassic. No credit') + return self.testFail(grades) + if stats['crashes'] > 0: + self.addMessage('Agent crashed on smallClassic. No credit') + return self.testFail(grades) + code = pac.checkFailure() + if code == 0: + return self.testPass(grades) + elif code == -3: + if pac.getWrongStatesExplored() >= 0: + self.addMessage('Bug: Wrong number of states expanded.') + return self.testFail(grades) + else: + return self.testPass(grades) + elif code == -2: + self.addMessage('Bug: Partial Ply Bug') + return self.testFail(grades) + elif code == -1: + self.addMessage('Bug: Search depth off by 1') + return self.testFail(grades) + elif code > 0: + moves = pac.getSuboptimalMoves() + state, studentMove, optMove = random.choice(moves) + self.addMessage('Bug: Suboptimal moves') + self.addMessage('State:%s\nStudent Move:%s\nOptimal Move:%s' % ( + state, studentMove, optMove)) + return self.testFail(grades) + + def writeList(self, handle, name, list): + handle.write('%s: """\n' % name) + for l in list: + handle.write('%s\n' % json.dumps(l)) + handle.write('"""\n') + + def writeSolution(self, moduleDict, filePath): + # load module, set seed, create ghosts and macman, run game + multiAgents = moduleDict['multiAgents'] + random.seed(self.seed) + lay = layout.Layout([l.strip() for l in self.layout_text.split('\n')]) + if self.alg == 'ExpectimaxAgent': + ourPacOptions = {'expectimax': 'True'} + elif self.alg == 'AlphaBetaAgent': + ourPacOptions = {'alphabeta': 'True'} + else: + ourPacOptions = {} + pac = PolyAgent(self.seed, multiAgents, ourPacOptions, self.depth) + disp = self.question.getDisplay() + run(lay, self.layout_name, pac, [DirectionalGhost( + i + 1) for i in range(2)], disp, name=self.alg) + (optimalActions, altDepthActions, partialPlyBugActions) = pac.getTraces() + # recover traces and record to file + handle = open(filePath, 'w') + self.writeList(handle, 'optimalActions', optimalActions) + self.writeList(handle, 'altDepthActions', altDepthActions) + self.writeList(handle, 'partialPlyBugActions', partialPlyBugActions) + handle.close() + + +class GraphGameTreeTest(testClasses.TestCase): + + def __init__(self, question, testDict): + super(GraphGameTreeTest, self).__init__(question, testDict) + self.problem = parseTreeProblem(testDict) + self.alg = self.testDict['alg'] + self.diagram = self.testDict['diagram'].split('\n') + self.depth = int(self.testDict['depth']) + + def solveProblem(self, multiAgents): + self.problem.reset() + studentAgent = getattr(multiAgents, self.alg)(depth=self.depth) + action = studentAgent.getAction(self.problem.startState) + generated = self.problem.generatedStates + return action, " ".join([str(s) for s in sorted(generated)]) + + def addDiagram(self): + self.addMessage('Tree:') + for line in self.diagram: + self.addMessage(line) + + def execute(self, grades, moduleDict, solutionDict): + multiAgents = moduleDict['multiAgents'] + goldAction = solutionDict['action'] + goldGenerated = solutionDict['generated'] + action, generated = self.solveProblem(multiAgents) + + fail = False + if action != goldAction: + self.addMessage('Incorrect move for depth=%s' % (self.depth,)) + self.addMessage( + ' Student move: %s\n Optimal move: %s' % (action, goldAction)) + fail = True + + if generated != goldGenerated: + self.addMessage( + 'Incorrect generated nodes for depth=%s' % (self.depth,)) + self.addMessage(' Student generated nodes: %s\n Correct generated nodes: %s' % ( + generated, goldGenerated)) + fail = True + + if fail: + self.addDiagram() + return self.testFail(grades) + else: + return self.testPass(grades) + + def writeSolution(self, moduleDict, filePath): + multiAgents = moduleDict['multiAgents'] + action, generated = self.solveProblem(multiAgents) + with open(filePath, 'w') as handle: + handle.write('# This is the solution file for %s.\n' % self.path) + handle.write('action: "%s"\n' % (action,)) + handle.write('generated: "%s"\n' % (generated,)) + return True + + +import time +from util import TimeoutFunction + + +class EvalAgentTest(testClasses.TestCase): + + def __init__(self, question, testDict): + super(EvalAgentTest, self).__init__(question, testDict) + self.layoutName = testDict['layoutName'] + self.agentName = testDict['agentName'] + self.ghosts = eval(testDict['ghosts']) + self.maxTime = int(testDict['maxTime']) + self.seed = int(testDict['randomSeed']) + self.numGames = int(testDict['numGames']) + + self.scoreMinimum = int( + testDict['scoreMinimum']) if 'scoreMinimum' in testDict else None + self.nonTimeoutMinimum = int( + testDict['nonTimeoutMinimum']) if 'nonTimeoutMinimum' in testDict else None + self.winsMinimum = int( + testDict['winsMinimum']) if 'winsMinimum' in testDict else None + + self.scoreThresholds = [int(s) for s in testDict.get( + 'scoreThresholds', '').split()] + self.nonTimeoutThresholds = [int(s) for s in testDict.get( + 'nonTimeoutThresholds', '').split()] + self.winsThresholds = [int(s) for s in testDict.get( + 'winsThresholds', '').split()] + + self.maxPoints = sum([len(t) for t in [ + self.scoreThresholds, self.nonTimeoutThresholds, self.winsThresholds]]) + self.agentArgs = testDict.get('agentArgs', '') + + def execute(self, grades, moduleDict, solutionDict): + startTime = time.time() + + agentType = getattr(moduleDict['multiAgents'], self.agentName) + agentOpts = pacman.parseAgentArgs( + self.agentArgs) if self.agentArgs != '' else {} + agent = agentType(**agentOpts) + + lay = layout.getLayout(self.layoutName, 3) + + disp = self.question.getDisplay() + + random.seed(self.seed) + games = pacman.runGames(lay, agent, self.ghosts, disp, self.numGames, + False, catchExceptions=True, timeout=self.maxTime) + totalTime = time.time() - startTime + + stats = {'time': totalTime, 'wins': [g.state.isWin() for g in games].count(True), + 'games': games, 'scores': [g.state.getScore() for g in games], + 'timeouts': [g.agentTimeout for g in games].count(True), 'crashes': [g.agentCrashed for g in games].count(True)} + + averageScore = sum(stats['scores']) / float(len(stats['scores'])) + nonTimeouts = self.numGames - stats['timeouts'] + wins = stats['wins'] + + def gradeThreshold(value, minimum, thresholds, name): + points = 0 + passed = (minimum == None) or (value >= minimum) + if passed: + for t in thresholds: + if value >= t: + points += 1 + return (passed, points, value, minimum, thresholds, name) + + results = [gradeThreshold(averageScore, self.scoreMinimum, self.scoreThresholds, "average score"), + gradeThreshold(nonTimeouts, self.nonTimeoutMinimum, + self.nonTimeoutThresholds, "games not timed out"), + gradeThreshold(wins, self.winsMinimum, self.winsThresholds, "wins")] + + totalPoints = 0 + for passed, points, value, minimum, thresholds, name in results: + if minimum == None and len(thresholds) == 0: + continue + + # print passed, points, value, minimum, thresholds, name + totalPoints += points + if not passed: + assert points == 0 + self.addMessage( + "%s %s (fail: below minimum value %s)" % (value, name, minimum)) + else: + self.addMessage("%s %s (%s of %s points)" % + (value, name, points, len(thresholds))) + + if minimum != None: + self.addMessage(" Grading scheme:") + self.addMessage(" < %s: fail" % (minimum,)) + if len(thresholds) == 0 or minimum != thresholds[0]: + self.addMessage(" >= %s: 0 points" % (minimum,)) + for idx, threshold in enumerate(thresholds): + self.addMessage(" >= %s: %s points" % + (threshold, idx+1)) + elif len(thresholds) > 0: + self.addMessage(" Grading scheme:") + self.addMessage(" < %s: 0 points" % (thresholds[0],)) + for idx, threshold in enumerate(thresholds): + self.addMessage(" >= %s: %s points" % + (threshold, idx+1)) + + if any([not passed for passed, _, _, _, _, _ in results]): + totalPoints = 0 + + return self.testPartial(grades, totalPoints, self.maxPoints) + + def writeSolution(self, moduleDict, filePath): + handle = open(filePath, 'w') + handle.write('# This is the solution file for %s.\n' % self.path) + handle.write('# File intentionally blank.\n') + handle.close() + return True diff --git a/pacman.py b/pacman.py index 0a527c2..4a63c34 100644 --- a/pacman.py +++ b/pacman.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -45,13 +45,19 @@ from game import Directions from game import Actions from util import nearestPoint from util import manhattanDistance -import util, layout -import sys, types, time, random, os +import util +import layout +import sys +import types +import time +import random +import os ################################################### # YOUR INTERFACE TO THE PACMAN WORLD: A GameState # ################################################### + class GameState: """ A GameState specifies the full game state, including the food, capsules, @@ -73,30 +79,33 @@ class GameState: # static variable keeps track of which states have had getLegalActions called explored = set() + def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) - def getLegalActions( self, agentIndex=0 ): + def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ # GameState.explored.add(self) - if self.isWin() or self.isLose(): return [] + if self.isWin() or self.isLose(): + return [] if agentIndex == 0: # Pacman is moving - return PacmanRules.getLegalActions( self ) + return PacmanRules.getLegalActions(self) else: - return GhostRules.getLegalActions( self, agentIndex ) + return GhostRules.getLegalActions(self, agentIndex) - def generateSuccessor( self, agentIndex, action): + def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist - if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') + if self.isWin() or self.isLose(): + raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) @@ -104,18 +113,18 @@ class GameState: # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] - PacmanRules.applyAction( state, action ) + PacmanRules.applyAction(state, action) else: # A ghost is moving - GhostRules.applyAction( state, action, agentIndex ) + GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: - state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around + state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: - GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) + GhostRules.decrementTimer(state.data.agentStates[agentIndex]) # Resolve multi-agent effects - GhostRules.checkDeath( state, agentIndex ) + GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex @@ -124,16 +133,16 @@ class GameState: GameState.explored.add(state) return state - def getLegalPacmanActions( self ): - return self.getLegalActions( 0 ) + def getLegalPacmanActions(self): + return self.getLegalActions(0) - def generatePacmanSuccessor( self, action ): + def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ - return self.generateSuccessor( 0, action ) + return self.generateSuccessor(0, action) - def getPacmanState( self ): + def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) @@ -142,18 +151,18 @@ class GameState: """ return self.data.agentStates[0].copy() - def getPacmanPosition( self ): + def getPacmanPosition(self): return self.data.agentStates[0].getPosition() - def getGhostStates( self ): + def getGhostStates(self): return self.data.agentStates[1:] - def getGhostState( self, agentIndex ): + def getGhostState(self, agentIndex): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] - def getGhostPosition( self, agentIndex ): + def getGhostPosition(self, agentIndex): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() @@ -161,10 +170,10 @@ class GameState: def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] - def getNumAgents( self ): - return len( self.data.agentStates ) + def getNumAgents(self): + return len(self.data.agentStates) - def getScore( self ): + def getScore(self): return float(self.data.score) def getCapsules(self): @@ -173,7 +182,7 @@ class GameState: """ return self.data.capsules - def getNumFood( self ): + def getNumFood(self): return self.data.food.count() def getFood(self): @@ -206,10 +215,10 @@ class GameState: def hasWall(self, x, y): return self.data.layout.walls[x][y] - def isLose( self ): + def isLose(self): return self.data._lose - def isWin( self ): + def isWin(self): return self.data._win ############################################# @@ -217,37 +226,37 @@ class GameState: # You shouldn't need to call these directly # ############################################# - def __init__( self, prevState = None ): + def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ - if prevState != None: # Initial state + if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() - def deepCopy( self ): - state = GameState( self ) + def deepCopy(self): + state = GameState(self) state.data = self.data.deepCopy() return state - def __eq__( self, other ): + def __eq__(self, other): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data - def __hash__( self ): + def __hash__(self): """ Allows states to be keys of dictionaries. """ - return hash( self.data ) + return hash(self.data) - def __str__( self ): + def __str__(self): return str(self.data) - def initialize( self, layout, numGhostAgents=1000 ): + def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ @@ -259,22 +268,25 @@ class GameState: # You shouldn't need to look through the code in this section of the file. # ############################################################################ + SCARED_TIME = 40 # Moves ghosts are scared -COLLISION_TOLERANCE = 0.7 # How close ghosts must be to Pacman to kill -TIME_PENALTY = 1 # Number of points lost each round +COLLISION_TOLERANCE = 0.7 # How close ghosts must be to Pacman to kill +TIME_PENALTY = 1 # Number of points lost each round + class ClassicGameRules: """ These game rules manage the control flow of a game, deciding when and how the game starts and ends. """ + def __init__(self, timeout=30): self.timeout = timeout - def newGame( self, layout, pacmanAgent, ghostAgents, display, quiet = False, catchExceptions=False): + def newGame(self, layout, pacmanAgent, ghostAgents, display, quiet=False, catchExceptions=False): agents = [pacmanAgent] + ghostAgents[:layout.getNumGhosts()] initState = GameState() - initState.initialize( layout, len(ghostAgents) ) + initState.initialize(layout, len(ghostAgents)) game = Game(agents, display, self, catchExceptions=catchExceptions) game.state = initState self.initialState = initState.deepCopy() @@ -285,15 +297,19 @@ class ClassicGameRules: """ Checks to see whether it is time to end the game. """ - if state.isWin(): self.win(state, game) - if state.isLose(): self.lose(state, game) + if state.isWin(): + self.win(state, game) + if state.isLose(): + self.lose(state, game) - def win( self, state, game ): - if not self.quiet: print("Pacman emerges victorious! Score: %d" % state.data.score) + def win(self, state, game): + if not self.quiet: + print("Pacman emerges victorious! Score: %d" % state.data.score) game.gameOver = True - def lose( self, state, game ): - if not self.quiet: print("Pacman died! Score: %d" % state.data.score) + def lose(self, state, game): + if not self.quiet: + print("Pacman died! Score: %d" % state.data.score) game.gameOver = True def getProgress(self, game): @@ -320,44 +336,46 @@ class ClassicGameRules: def getMaxTimeWarnings(self, agentIndex): return 0 + class PacmanRules: """ These functions govern how pacman interacts with his environment under the classic game rules. """ - PACMAN_SPEED=1 + PACMAN_SPEED = 1 - def getLegalActions( state ): + def getLegalActions(state): """ Returns a list of possible actions. """ - return Actions.getPossibleActions( state.getPacmanState().configuration, state.data.layout.walls ) - getLegalActions = staticmethod( getLegalActions ) + return Actions.getPossibleActions(state.getPacmanState().configuration, state.data.layout.walls) + getLegalActions = staticmethod(getLegalActions) - def applyAction( state, action ): + def applyAction(state, action): """ Edits the state to reflect the results of the action. """ - legal = PacmanRules.getLegalActions( state ) + legal = PacmanRules.getLegalActions(state) if action not in legal: raise Exception("Illegal action " + str(action)) pacmanState = state.data.agentStates[0] # Update Configuration - vector = Actions.directionToVector( action, PacmanRules.PACMAN_SPEED ) - pacmanState.configuration = pacmanState.configuration.generateSuccessor( vector ) + vector = Actions.directionToVector(action, PacmanRules.PACMAN_SPEED) + pacmanState.configuration = pacmanState.configuration.generateSuccessor( + vector) # Eat next = pacmanState.configuration.getPosition() - nearest = nearestPoint( next ) - if manhattanDistance( nearest, next ) <= 0.5 : + nearest = nearestPoint(next) + if manhattanDistance(nearest, next) <= 0.5: # Remove food - PacmanRules.consume( nearest, state ) - applyAction = staticmethod( applyAction ) + PacmanRules.consume(nearest, state) + applyAction = staticmethod(applyAction) - def consume( position, state ): - x,y = position + def consume(position, state): + x, y = position # Eat food if state.data.food[x][y]: state.data.scoreChange += 10 @@ -370,70 +388,76 @@ class PacmanRules: state.data.scoreChange += 500 state.data._win = True # Eat capsule - if( position in state.getCapsules() ): - state.data.capsules.remove( position ) + if(position in state.getCapsules()): + state.data.capsules.remove(position) state.data._capsuleEaten = position # Reset all ghosts' scared timers - for index in range( 1, len( state.data.agentStates ) ): + for index in range(1, len(state.data.agentStates)): state.data.agentStates[index].scaredTimer = SCARED_TIME - consume = staticmethod( consume ) + consume = staticmethod(consume) + class GhostRules: """ These functions dictate how ghosts interact with their environment. """ - GHOST_SPEED=1.0 - def getLegalActions( state, ghostIndex ): + GHOST_SPEED = 1.0 + + def getLegalActions(state, ghostIndex): """ Ghosts cannot stop, and cannot turn around unless they reach a dead end, but can turn 90 degrees at intersections. """ - conf = state.getGhostState( ghostIndex ).configuration - possibleActions = Actions.getPossibleActions( conf, state.data.layout.walls ) - reverse = Actions.reverseDirection( conf.direction ) + conf = state.getGhostState(ghostIndex).configuration + possibleActions = Actions.getPossibleActions( + conf, state.data.layout.walls) + reverse = Actions.reverseDirection(conf.direction) if Directions.STOP in possibleActions: - possibleActions.remove( Directions.STOP ) - if reverse in possibleActions and len( possibleActions ) > 1: - possibleActions.remove( reverse ) + possibleActions.remove(Directions.STOP) + if reverse in possibleActions and len(possibleActions) > 1: + possibleActions.remove(reverse) return possibleActions - getLegalActions = staticmethod( getLegalActions ) + getLegalActions = staticmethod(getLegalActions) - def applyAction( state, action, ghostIndex): + def applyAction(state, action, ghostIndex): - legal = GhostRules.getLegalActions( state, ghostIndex ) + legal = GhostRules.getLegalActions(state, ghostIndex) if action not in legal: raise Exception("Illegal ghost action " + str(action)) ghostState = state.data.agentStates[ghostIndex] speed = GhostRules.GHOST_SPEED - if ghostState.scaredTimer > 0: speed /= 2.0 - vector = Actions.directionToVector( action, speed ) - ghostState.configuration = ghostState.configuration.generateSuccessor( vector ) - applyAction = staticmethod( applyAction ) + if ghostState.scaredTimer > 0: + speed /= 2.0 + vector = Actions.directionToVector(action, speed) + ghostState.configuration = ghostState.configuration.generateSuccessor( + vector) + applyAction = staticmethod(applyAction) - def decrementTimer( ghostState): + def decrementTimer(ghostState): timer = ghostState.scaredTimer if timer == 1: - ghostState.configuration.pos = nearestPoint( ghostState.configuration.pos ) - ghostState.scaredTimer = max( 0, timer - 1 ) - decrementTimer = staticmethod( decrementTimer ) + ghostState.configuration.pos = nearestPoint( + ghostState.configuration.pos) + ghostState.scaredTimer = max(0, timer - 1) + decrementTimer = staticmethod(decrementTimer) - def checkDeath( state, agentIndex): + def checkDeath(state, agentIndex): pacmanPosition = state.getPacmanPosition() - if agentIndex == 0: # Pacman just moved; Anyone can kill him - for index in range( 1, len( state.data.agentStates ) ): + if agentIndex == 0: # Pacman just moved; Anyone can kill him + for index in range(1, len(state.data.agentStates)): ghostState = state.data.agentStates[index] ghostPosition = ghostState.configuration.getPosition() - if GhostRules.canKill( pacmanPosition, ghostPosition ): - GhostRules.collide( state, ghostState, index ) + if GhostRules.canKill(pacmanPosition, ghostPosition): + GhostRules.collide(state, ghostState, index) else: ghostState = state.data.agentStates[agentIndex] ghostPosition = ghostState.configuration.getPosition() - if GhostRules.canKill( pacmanPosition, ghostPosition ): - GhostRules.collide( state, ghostState, agentIndex ) - checkDeath = staticmethod( checkDeath ) + if GhostRules.canKill(pacmanPosition, ghostPosition): + GhostRules.collide(state, ghostState, agentIndex) + checkDeath = staticmethod(checkDeath) - def collide( state, ghostState, agentIndex): + def collide(state, ghostState, agentIndex): if ghostState.scaredTimer > 0: state.data.scoreChange += 200 GhostRules.placeGhost(state, ghostState) @@ -444,36 +468,40 @@ class GhostRules: if not state.data._win: state.data.scoreChange -= 500 state.data._lose = True - collide = staticmethod( collide ) + collide = staticmethod(collide) - def canKill( pacmanPosition, ghostPosition ): - return manhattanDistance( ghostPosition, pacmanPosition ) <= COLLISION_TOLERANCE - canKill = staticmethod( canKill ) + def canKill(pacmanPosition, ghostPosition): + return manhattanDistance(ghostPosition, pacmanPosition) <= COLLISION_TOLERANCE + canKill = staticmethod(canKill) def placeGhost(state, ghostState): ghostState.configuration = ghostState.start - placeGhost = staticmethod( placeGhost ) + placeGhost = staticmethod(placeGhost) ############################# # FRAMEWORK TO START A GAME # ############################# + def default(str): return str + ' [Default: %default]' + def parseAgentArgs(str): - if str == None: return {} + if str == None: + return {} pieces = str.split(',') opts = {} for p in pieces: if '=' in p: key, val = p.split('=') else: - key,val = p, 1 + key, val = p, 1 opts[key] = val return opts -def readCommand( argv ): + +def readCommand(argv): """ Processes the command used to run pacman from the command line. """ @@ -491,18 +519,21 @@ def readCommand( argv ): parser.add_option('-n', '--numGames', dest='numGames', type='int', help=default('the number of GAMES to play'), metavar='GAMES', default=1) parser.add_option('-l', '--layout', dest='layout', - help=default('the LAYOUT_FILE from which to load the map layout'), + help=default( + 'the LAYOUT_FILE from which to load the map layout'), metavar='LAYOUT_FILE', default='mediumClassic') parser.add_option('-p', '--pacman', dest='pacman', - help=default('the agent TYPE in the pacmanAgents module to use'), + help=default( + 'the agent TYPE in the pacmanAgents module to use'), metavar='TYPE', default='KeyboardAgent') parser.add_option('-t', '--textGraphics', action='store_true', dest='textGraphics', help='Display output as text only', default=False) parser.add_option('-q', '--quietTextGraphics', action='store_true', dest='quietGraphics', help='Generate minimal output and no graphics', default=False) parser.add_option('-g', '--ghosts', dest='ghost', - help=default('the ghost agent TYPE in the ghostAgents module to use'), - metavar = 'TYPE', default='RandomGhost') + help=default( + 'the ghost agent TYPE in the ghostAgents module to use'), + metavar='TYPE', default='RandomGhost') parser.add_option('-k', '--numghosts', type='int', dest='numGhosts', help=default('The maximum number of ghosts to use'), default=4) parser.add_option('-z', '--zoom', type='float', dest='zoom', @@ -513,7 +544,7 @@ def readCommand( argv ): help='Writes game histories to a file (named by the time they were played)', default=False) parser.add_option('--replay', dest='gameToReplay', help='A recorded game file (pickle) to replay', default=None) - parser.add_option('-a','--agentArgs',dest='agentArgs', + parser.add_option('-a', '--agentArgs', dest='agentArgs', help='Comma separated values sent to agent. e.g. "opt1=val1,opt2,opt3=val3"') parser.add_option('-x', '--numTraining', dest='numTraining', type='int', help=default('How many episodes are training (suppresses output)'), default=0) @@ -530,20 +561,24 @@ def readCommand( argv ): args = dict() # Fix the random seed - if options.fixRandomSeed: random.seed('cs188') + if options.fixRandomSeed: + random.seed('cs188') # Choose a layout - args['layout'] = layout.getLayout( options.layout ) - if args['layout'] == None: raise Exception("The layout " + options.layout + " cannot be found") + args['layout'] = layout.getLayout(options.layout) + if args['layout'] == None: + raise Exception("The layout " + options.layout + " cannot be found") # Choose a Pacman agent - noKeyboard = options.gameToReplay == None and (options.textGraphics or options.quietGraphics) + noKeyboard = options.gameToReplay == None and ( + options.textGraphics or options.quietGraphics) pacmanType = loadAgent(options.pacman, noKeyboard) agentOpts = parseAgentArgs(options.agentArgs) if options.numTraining > 0: args['numTraining'] = options.numTraining - if 'numTraining' not in agentOpts: agentOpts['numTraining'] = options.numTraining - pacman = pacmanType(**agentOpts) # Instantiate Pacman with agentArgs + if 'numTraining' not in agentOpts: + agentOpts['numTraining'] = options.numTraining + pacman = pacmanType(**agentOpts) # Instantiate Pacman with agentArgs args['pacman'] = pacman # Don't display training games @@ -553,7 +588,7 @@ def readCommand( argv ): # Choose a ghost agent ghostType = loadAgent(options.ghost, noKeyboard) - args['ghosts'] = [ghostType( i+1 ) for i in range( options.numGhosts )] + args['ghosts'] = [ghostType(i+1) for i in range(options.numGhosts)] # Choose a display format if options.quietGraphics: @@ -565,7 +600,8 @@ def readCommand( argv ): args['display'] = textDisplay.PacmanGraphics() else: import graphicsDisplay - args['display'] = graphicsDisplay.PacmanGraphics(options.zoom, frameTime = options.frameTime) + args['display'] = graphicsDisplay.PacmanGraphics( + options.zoom, frameTime=options.frameTime) args['numGames'] = options.numGames args['record'] = options.record args['catchExceptions'] = options.catchExceptions @@ -575,15 +611,18 @@ def readCommand( argv ): if options.gameToReplay != None: print('Replaying recorded game %s.' % options.gameToReplay) import pickle - f = open(options.gameToReplay, 'rb') - try: recorded = pickle.load(f) - finally: f.close() + f = open(options.gameToReplay) + try: + recorded = pickle.load(f) + finally: + f.close() recorded['display'] = args['display'] replayGame(**recorded) sys.exit(0) return args + def loadAgent(pacman, nographics): # Looks through all pythonPath Directories for the right module, pythonPathStr = os.path.expandvars("$PYTHONPATH") @@ -594,8 +633,10 @@ def loadAgent(pacman, nographics): pythonPathDirs.append('.') for moduleDir in pythonPathDirs: - if not os.path.isdir(moduleDir): continue - moduleNames = [f for f in os.listdir(moduleDir) if f.endswith('gents.py')] + if not os.path.isdir(moduleDir): + continue + moduleNames = [f for f in os.listdir( + moduleDir) if f.endswith('gents.py')] for modulename in moduleNames: try: module = __import__(modulename[:-3]) @@ -603,36 +644,42 @@ def loadAgent(pacman, nographics): continue if pacman in dir(module): if nographics and modulename == 'keyboardAgents.py': - raise Exception('Using the keyboard requires graphics (not text display)') + raise Exception( + 'Using the keyboard requires graphics (not text display)') return getattr(module, pacman) - raise Exception('The agent ' + pacman + ' is not specified in any *Agents.py.') + raise Exception('The agent ' + pacman + + ' is not specified in any *Agents.py.') -def replayGame( layout, actions, display ): - import pacmanAgents, ghostAgents + +def replayGame(layout, actions, display): + import pacmanAgents + import ghostAgents rules = ClassicGameRules() - agents = [pacmanAgents.GreedyAgent()] + [ghostAgents.RandomGhost(i+1) for i in range(layout.getNumGhosts())] - game = rules.newGame( layout, agents[0], agents[1:], display ) + agents = [pacmanAgents.GreedyAgent()] + [ghostAgents.RandomGhost(i+1) + for i in range(layout.getNumGhosts())] + game = rules.newGame(layout, agents[0], agents[1:], display) state = game.state display.initialize(state.data) for action in actions: # Execute the action - state = state.generateSuccessor( *action ) + state = state.generateSuccessor(*action) # Change the display - display.update( state.data ) + display.update(state.data) # Allow for game specific conditions (winning, losing, etc.) rules.process(state, game) display.finish() -def runGames( layout, pacman, ghosts, display, numGames, record, numTraining = 0, catchExceptions=False, timeout=30 ): + +def runGames(layout, pacman, ghosts, display, numGames, record, numTraining=0, catchExceptions=False, timeout=30): import __main__ __main__.__dict__['_display'] = display rules = ClassicGameRules(timeout) games = [] - for i in range( numGames ): + for i in range(numGames): beQuiet = i < numTraining if beQuiet: # Suppress output and graphics @@ -642,14 +689,18 @@ def runGames( layout, pacman, ghosts, display, numGames, record, numTraining = 0 else: gameDisplay = display rules.quiet = False - game = rules.newGame( layout, pacman, ghosts, gameDisplay, beQuiet, catchExceptions) + game = rules.newGame(layout, pacman, ghosts, + gameDisplay, beQuiet, catchExceptions) game.run() - if not beQuiet: games.append(game) + if not beQuiet: + games.append(game) if record: - import time, pickle - fname = ('recorded-game-%d' % (i + 1)) + '-'.join([str(t) for t in time.localtime()[1:6]]) - f = open(fname, 'wb') + import time + import pickle + fname = ('recorded-game-%d' % (i + 1)) + \ + '-'.join([str(t) for t in time.localtime()[1:6]]) + f = file(fname, 'w') components = {'layout': layout, 'actions': game.moveHistory} pickle.dump(components, f) f.close() @@ -657,14 +708,17 @@ def runGames( layout, pacman, ghosts, display, numGames, record, numTraining = 0 if (numGames-numTraining) > 0: scores = [game.state.getScore() for game in games] wins = [game.state.isWin() for game in games] - winRate = wins.count(True)/ float(len(wins)) + winRate = wins.count(True) / float(len(wins)) print('Average Score:', sum(scores) / float(len(scores))) print('Scores: ', ', '.join([str(score) for score in scores])) - print('Win Rate: %d/%d (%.2f)' % (wins.count(True), len(wins), winRate)) - print('Record: ', ', '.join([ ['Loss', 'Win'][int(w)] for w in wins])) + print('Win Rate: %d/%d (%.2f)' % + (wins.count(True), len(wins), winRate)) + print('Record: ', ', '.join( + [['Loss', 'Win'][int(w)] for w in wins])) return games + if __name__ == '__main__': """ The main function called when pacman.py is run @@ -676,8 +730,8 @@ if __name__ == '__main__': > python pacman.py --help """ - args = readCommand( sys.argv[1:] ) # Get game components based on input - runGames( **args ) + args = readCommand(sys.argv[1:]) # Get game components based on input + runGames(**args) # import cProfile # cProfile.run("runGames( **args )") diff --git a/pacmanAgents.py b/pacmanAgents.py index ae97634..a5d9feb 100644 --- a/pacmanAgents.py +++ b/pacmanAgents.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -18,20 +18,27 @@ import random import game import util + class LeftTurnAgent(game.Agent): "An agent that turns left at every opportunity" def getAction(self, state): legal = state.getLegalPacmanActions() current = state.getPacmanState().configuration.direction - if current == Directions.STOP: current = Directions.NORTH + if current == Directions.STOP: + current = Directions.NORTH left = Directions.LEFT[current] - if left in legal: return left - if current in legal: return current - if Directions.RIGHT[current] in legal: return Directions.RIGHT[current] - if Directions.LEFT[left] in legal: return Directions.LEFT[left] + if left in legal: + return left + if current in legal: + return current + if Directions.RIGHT[current] in legal: + return Directions.RIGHT[current] + if Directions.LEFT[left] in legal: + return Directions.LEFT[left] return Directions.STOP + class GreedyAgent(Agent): def __init__(self, evalFn="scoreEvaluation"): self.evaluationFunction = util.lookup(evalFn, globals()) @@ -40,13 +47,17 @@ class GreedyAgent(Agent): def getAction(self, state): # Generate candidate actions legal = state.getLegalPacmanActions() - if Directions.STOP in legal: legal.remove(Directions.STOP) + if Directions.STOP in legal: + legal.remove(Directions.STOP) - successors = [(state.generateSuccessor(0, action), action) for action in legal] - scored = [(self.evaluationFunction(state), action) for state, action in successors] + successors = [(state.generateSuccessor(0, action), action) + for action in legal] + scored = [(self.evaluationFunction(state), action) + for state, action in successors] bestScore = max(scored)[0] bestActions = [pair[1] for pair in scored if pair[0] == bestScore] return random.choice(bestActions) + def scoreEvaluation(state): return state.getScore() diff --git a/projectParams.py b/projectParams.py index dc3e9d1..77d4caa 100644 --- a/projectParams.py +++ b/projectParams.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -12,7 +12,7 @@ # Pieter Abbeel (pabbeel@cs.berkeley.edu). -STUDENT_CODE_DEFAULT = 'searchAgents.py,search.py' -PROJECT_TEST_CLASSES = 'searchTestClasses.py' -PROJECT_NAME = 'Project 1: Search' +STUDENT_CODE_DEFAULT = 'multiAgents.py' +PROJECT_TEST_CLASSES = 'multiagentTestClasses.py' +PROJECT_NAME = 'Project 2: Multiagent search' BONUS_PIC = False diff --git a/search.py b/search.py deleted file mode 100644 index cd330bf..0000000 --- a/search.py +++ /dev/null @@ -1,119 +0,0 @@ -# search.py -# --------- -# Licensing Information: You are free to use or extend these projects for -# educational purposes provided that (1) you do not distribute or publish -# solutions, (2) you retain this notice, and (3) you provide clear -# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# -# Attribution Information: The Pacman AI projects were developed at UC Berkeley. -# The core projects and autograders were primarily created by John DeNero -# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). -# Student side autograding was added by Brad Miller, Nick Hay, and -# Pieter Abbeel (pabbeel@cs.berkeley.edu). - - -""" -In search.py, you will implement generic search algorithms which are called by -Pacman agents (in searchAgents.py). -""" - -import util - -class SearchProblem: - """ - This class outlines the structure of a search problem, but doesn't implement - any of the methods (in object-oriented terminology: an abstract class). - - You do not need to change anything in this class, ever. - """ - - def getStartState(self): - """ - Returns the start state for the search problem. - """ - util.raiseNotDefined() - - def isGoalState(self, state): - """ - state: Search state - - Returns True if and only if the state is a valid goal state. - """ - util.raiseNotDefined() - - def getSuccessors(self, state): - """ - state: Search state - - For a given state, this should return a list of triples, (successor, - action, stepCost), where 'successor' is a successor to the current - state, 'action' is the action required to get there, and 'stepCost' is - the incremental cost of expanding to that successor. - """ - util.raiseNotDefined() - - def getCostOfActions(self, actions): - """ - actions: A list of actions to take - - This method returns the total cost of a particular sequence of actions. - The sequence must be composed of legal moves. - """ - util.raiseNotDefined() - - -def tinyMazeSearch(problem): - """ - Returns a sequence of moves that solves tinyMaze. For any other maze, the - sequence of moves will be incorrect, so only use this for tinyMaze. - """ - from game import Directions - s = Directions.SOUTH - w = Directions.WEST - return [s, s, w, s, w, w, s, w] - -def depthFirstSearch(problem): - """ - Search the deepest nodes in the search tree first. - - Your search algorithm needs to return a list of actions that reaches the - goal. Make sure to implement a graph search algorithm. - - To get started, you might want to try some of these simple commands to - understand the search problem that is being passed in: - - print("Start:", problem.getStartState()) - print("Is the start a goal?", problem.isGoalState(problem.getStartState())) - print("Start's successors:", problem.getSuccessors(problem.getStartState())) - """ - "*** YOUR CODE HERE ***" - util.raiseNotDefined() - -def breadthFirstSearch(problem): - """Search the shallowest nodes in the search tree first.""" - "*** YOUR CODE HERE ***" - util.raiseNotDefined() - -def uniformCostSearch(problem): - """Search the node of least total cost first.""" - "*** YOUR CODE HERE ***" - util.raiseNotDefined() - -def nullHeuristic(state, problem=None): - """ - A heuristic function estimates the cost from the current state to the nearest - goal in the provided SearchProblem. This heuristic is trivial. - """ - return 0 - -def aStarSearch(problem, heuristic=nullHeuristic): - """Search the node that has the lowest combined cost and heuristic first.""" - "*** YOUR CODE HERE ***" - util.raiseNotDefined() - - -# Abbreviations -bfs = breadthFirstSearch -dfs = depthFirstSearch -astar = aStarSearch -ucs = uniformCostSearch diff --git a/searchAgents.py b/searchAgents.py deleted file mode 100644 index 3a91623..0000000 --- a/searchAgents.py +++ /dev/null @@ -1,542 +0,0 @@ -# searchAgents.py -# --------------- -# Licensing Information: You are free to use or extend these projects for -# educational purposes provided that (1) you do not distribute or publish -# solutions, (2) you retain this notice, and (3) you provide clear -# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# -# Attribution Information: The Pacman AI projects were developed at UC Berkeley. -# The core projects and autograders were primarily created by John DeNero -# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). -# Student side autograding was added by Brad Miller, Nick Hay, and -# Pieter Abbeel (pabbeel@cs.berkeley.edu). - - -""" -This file contains all of the agents that can be selected to control Pacman. To -select an agent, use the '-p' option when running pacman.py. Arguments can be -passed to your agent using '-a'. For example, to load a SearchAgent that uses -depth first search (dfs), run the following command: - -> python pacman.py -p SearchAgent -a fn=depthFirstSearch - -Commands to invoke other search strategies can be found in the project -description. - -Please only change the parts of the file you are asked to. Look for the lines -that say - -"*** YOUR CODE HERE ***" - -The parts you fill in start about 3/4 of the way down. Follow the project -description for details. - -Good luck and happy searching! -""" - -from game import Directions -from game import Agent -from game import Actions -import util -import time -import search - -class GoWestAgent(Agent): - "An agent that goes West until it can't." - - def getAction(self, state): - "The agent receives a GameState (defined in pacman.py)." - if Directions.WEST in state.getLegalPacmanActions(): - return Directions.WEST - else: - return Directions.STOP - -####################################################### -# This portion is written for you, but will only work # -# after you fill in parts of search.py # -####################################################### - -class SearchAgent(Agent): - """ - This very general search agent finds a path using a supplied search - algorithm for a supplied search problem, then returns actions to follow that - path. - - As a default, this agent runs DFS on a PositionSearchProblem to find - location (1,1) - - Options for fn include: - depthFirstSearch or dfs - breadthFirstSearch or bfs - - - Note: You should NOT change any code in SearchAgent - """ - - def __init__(self, fn='depthFirstSearch', prob='PositionSearchProblem', heuristic='nullHeuristic'): - # Warning: some advanced Python magic is employed below to find the right functions and problems - - # Get the search function from the name and heuristic - if fn not in dir(search): - raise AttributeError(fn + ' is not a search function in search.py.') - func = getattr(search, fn) - if 'heuristic' not in func.__code__.co_varnames: - print('[SearchAgent] using function ' + fn) - self.searchFunction = func - else: - if heuristic in globals().keys(): - heur = globals()[heuristic] - elif heuristic in dir(search): - heur = getattr(search, heuristic) - else: - raise AttributeError(heuristic + ' is not a function in searchAgents.py or search.py.') - print('[SearchAgent] using function %s and heuristic %s' % (fn, heuristic)) - # Note: this bit of Python trickery combines the search algorithm and the heuristic - self.searchFunction = lambda x: func(x, heuristic=heur) - - # Get the search problem type from the name - if prob not in globals().keys() or not prob.endswith('Problem'): - raise AttributeError(prob + ' is not a search problem type in SearchAgents.py.') - self.searchType = globals()[prob] - print('[SearchAgent] using problem type ' + prob) - - def registerInitialState(self, state): - """ - This is the first time that the agent sees the layout of the game - board. Here, we choose a path to the goal. In this phase, the agent - should compute the path to the goal and store it in a local variable. - All of the work is done in this method! - - state: a GameState object (pacman.py) - """ - if self.searchFunction == None: raise Exception("No search function provided for SearchAgent") - starttime = time.time() - problem = self.searchType(state) # Makes a new search problem - self.actions = self.searchFunction(problem) # Find a path - totalCost = problem.getCostOfActions(self.actions) - print('Path found with total cost of %d in %.1f seconds' % (totalCost, time.time() - starttime)) - if '_expanded' in dir(problem): print('Search nodes expanded: %d' % problem._expanded) - - def getAction(self, state): - """ - Returns the next action in the path chosen earlier (in - registerInitialState). Return Directions.STOP if there is no further - action to take. - - state: a GameState object (pacman.py) - """ - if 'actionIndex' not in dir(self): self.actionIndex = 0 - i = self.actionIndex - self.actionIndex += 1 - if i < len(self.actions): - return self.actions[i] - else: - return Directions.STOP - -class PositionSearchProblem(search.SearchProblem): - """ - A search problem defines the state space, start state, goal test, successor - function and cost function. This search problem can be used to find paths - to a particular point on the pacman board. - - The state space consists of (x,y) positions in a pacman game. - - Note: this search problem is fully specified; you should NOT change it. - """ - - def __init__(self, gameState, costFn = lambda x: 1, goal=(1,1), start=None, warn=True, visualize=True): - """ - Stores the start and goal. - - gameState: A GameState object (pacman.py) - costFn: A function from a search state (tuple) to a non-negative number - goal: A position in the gameState - """ - self.walls = gameState.getWalls() - self.startState = gameState.getPacmanPosition() - if start != None: self.startState = start - self.goal = goal - self.costFn = costFn - self.visualize = visualize - if warn and (gameState.getNumFood() != 1 or not gameState.hasFood(*goal)): - print('Warning: this does not look like a regular search maze') - - # For display purposes - self._visited, self._visitedlist, self._expanded = {}, [], 0 # DO NOT CHANGE - - def getStartState(self): - return self.startState - - def isGoalState(self, state): - isGoal = state == self.goal - - # For display purposes only - if isGoal and self.visualize: - self._visitedlist.append(state) - import __main__ - if '_display' in dir(__main__): - if 'drawExpandedCells' in dir(__main__._display): #@UndefinedVariable - __main__._display.drawExpandedCells(self._visitedlist) #@UndefinedVariable - - return isGoal - - def getSuccessors(self, state): - """ - Returns successor states, the actions they require, and a cost of 1. - - As noted in search.py: - For a given state, this should return a list of triples, - (successor, action, stepCost), where 'successor' is a - successor to the current state, 'action' is the action - required to get there, and 'stepCost' is the incremental - cost of expanding to that successor - """ - - successors = [] - for action in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]: - x,y = state - dx, dy = Actions.directionToVector(action) - nextx, nexty = int(x + dx), int(y + dy) - if not self.walls[nextx][nexty]: - nextState = (nextx, nexty) - cost = self.costFn(nextState) - successors.append( ( nextState, action, cost) ) - - # Bookkeeping for display purposes - self._expanded += 1 # DO NOT CHANGE - if state not in self._visited: - self._visited[state] = True - self._visitedlist.append(state) - - return successors - - def getCostOfActions(self, actions): - """ - Returns the cost of a particular sequence of actions. If those actions - include an illegal move, return 999999. - """ - if actions == None: return 999999 - x,y= self.getStartState() - cost = 0 - for action in actions: - # Check figure out the next state and see whether its' legal - dx, dy = Actions.directionToVector(action) - x, y = int(x + dx), int(y + dy) - if self.walls[x][y]: return 999999 - cost += self.costFn((x,y)) - return cost - -class StayEastSearchAgent(SearchAgent): - """ - An agent for position search with a cost function that penalizes being in - positions on the West side of the board. - - The cost function for stepping into a position (x,y) is 1/2^x. - """ - def __init__(self): - self.searchFunction = search.uniformCostSearch - costFn = lambda pos: .5 ** pos[0] - self.searchType = lambda state: PositionSearchProblem(state, costFn, (1, 1), None, False) - -class StayWestSearchAgent(SearchAgent): - """ - An agent for position search with a cost function that penalizes being in - positions on the East side of the board. - - The cost function for stepping into a position (x,y) is 2^x. - """ - def __init__(self): - self.searchFunction = search.uniformCostSearch - costFn = lambda pos: 2 ** pos[0] - self.searchType = lambda state: PositionSearchProblem(state, costFn) - -def manhattanHeuristic(position, problem, info={}): - "The Manhattan distance heuristic for a PositionSearchProblem" - xy1 = position - xy2 = problem.goal - return abs(xy1[0] - xy2[0]) + abs(xy1[1] - xy2[1]) - -def euclideanHeuristic(position, problem, info={}): - "The Euclidean distance heuristic for a PositionSearchProblem" - xy1 = position - xy2 = problem.goal - return ( (xy1[0] - xy2[0]) ** 2 + (xy1[1] - xy2[1]) ** 2 ) ** 0.5 - -##################################################### -# This portion is incomplete. Time to write code! # -##################################################### - -class CornersProblem(search.SearchProblem): - """ - This search problem finds paths through all four corners of a layout. - - You must select a suitable state space and successor function - """ - - def __init__(self, startingGameState): - """ - Stores the walls, pacman's starting position and corners. - """ - self.walls = startingGameState.getWalls() - self.startingPosition = startingGameState.getPacmanPosition() - top, right = self.walls.height-2, self.walls.width-2 - self.corners = ((1,1), (1,top), (right, 1), (right, top)) - for corner in self.corners: - if not startingGameState.hasFood(*corner): - print('Warning: no food in corner ' + str(corner)) - self._expanded = 0 # DO NOT CHANGE; Number of search nodes expanded - # Please add any code here which you would like to use - # in initializing the problem - "*** YOUR CODE HERE ***" - - def getStartState(self): - """ - Returns the start state (in your state space, not the full Pacman state - space) - """ - "*** YOUR CODE HERE ***" - util.raiseNotDefined() - - def isGoalState(self, state): - """ - Returns whether this search state is a goal state of the problem. - """ - "*** YOUR CODE HERE ***" - util.raiseNotDefined() - - def getSuccessors(self, state): - """ - Returns successor states, the actions they require, and a cost of 1. - - As noted in search.py: - For a given state, this should return a list of triples, (successor, - action, stepCost), where 'successor' is a successor to the current - state, 'action' is the action required to get there, and 'stepCost' - is the incremental cost of expanding to that successor - """ - - successors = [] - for action in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]: - # Add a successor state to the successor list if the action is legal - # Here's a code snippet for figuring out whether a new position hits a wall: - # x,y = currentPosition - # dx, dy = Actions.directionToVector(action) - # nextx, nexty = int(x + dx), int(y + dy) - # hitsWall = self.walls[nextx][nexty] - - "*** YOUR CODE HERE ***" - - self._expanded += 1 # DO NOT CHANGE - return successors - - def getCostOfActions(self, actions): - """ - Returns the cost of a particular sequence of actions. If those actions - include an illegal move, return 999999. This is implemented for you. - """ - if actions == None: return 999999 - x,y= self.startingPosition - for action in actions: - dx, dy = Actions.directionToVector(action) - x, y = int(x + dx), int(y + dy) - if self.walls[x][y]: return 999999 - return len(actions) - - -def cornersHeuristic(state, problem): - """ - A heuristic for the CornersProblem that you defined. - - state: The current search state - (a data structure you chose in your search problem) - - problem: The CornersProblem instance for this layout. - - This function should always return a number that is a lower bound on the - shortest path from the state to a goal of the problem; i.e. it should be - admissible (as well as consistent). - """ - corners = problem.corners # These are the corner coordinates - walls = problem.walls # These are the walls of the maze, as a Grid (game.py) - - "*** YOUR CODE HERE ***" - return 0 # Default to trivial solution - -class AStarCornersAgent(SearchAgent): - "A SearchAgent for FoodSearchProblem using A* and your foodHeuristic" - def __init__(self): - self.searchFunction = lambda prob: search.aStarSearch(prob, cornersHeuristic) - self.searchType = CornersProblem - -class FoodSearchProblem: - """ - A search problem associated with finding the a path that collects all of the - food (dots) in a Pacman game. - - A search state in this problem is a tuple ( pacmanPosition, foodGrid ) where - pacmanPosition: a tuple (x,y) of integers specifying Pacman's position - foodGrid: a Grid (see game.py) of either True or False, specifying remaining food - """ - def __init__(self, startingGameState): - self.start = (startingGameState.getPacmanPosition(), startingGameState.getFood()) - self.walls = startingGameState.getWalls() - self.startingGameState = startingGameState - self._expanded = 0 # DO NOT CHANGE - self.heuristicInfo = {} # A dictionary for the heuristic to store information - - def getStartState(self): - return self.start - - def isGoalState(self, state): - return state[1].count() == 0 - - def getSuccessors(self, state): - "Returns successor states, the actions they require, and a cost of 1." - successors = [] - self._expanded += 1 # DO NOT CHANGE - for direction in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]: - x,y = state[0] - dx, dy = Actions.directionToVector(direction) - nextx, nexty = int(x + dx), int(y + dy) - if not self.walls[nextx][nexty]: - nextFood = state[1].copy() - nextFood[nextx][nexty] = False - successors.append( ( ((nextx, nexty), nextFood), direction, 1) ) - return successors - - def getCostOfActions(self, actions): - """Returns the cost of a particular sequence of actions. If those actions - include an illegal move, return 999999""" - x,y= self.getStartState()[0] - cost = 0 - for action in actions: - # figure out the next state and see whether it's legal - dx, dy = Actions.directionToVector(action) - x, y = int(x + dx), int(y + dy) - if self.walls[x][y]: - return 999999 - cost += 1 - return cost - -class AStarFoodSearchAgent(SearchAgent): - "A SearchAgent for FoodSearchProblem using A* and your foodHeuristic" - def __init__(self): - self.searchFunction = lambda prob: search.aStarSearch(prob, foodHeuristic) - self.searchType = FoodSearchProblem - -def foodHeuristic(state, problem): - """ - Your heuristic for the FoodSearchProblem goes here. - - This heuristic must be consistent to ensure correctness. First, try to come - up with an admissible heuristic; almost all admissible heuristics will be - consistent as well. - - If using A* ever finds a solution that is worse uniform cost search finds, - your heuristic is *not* consistent, and probably not admissible! On the - other hand, inadmissible or inconsistent heuristics may find optimal - solutions, so be careful. - - The state is a tuple ( pacmanPosition, foodGrid ) where foodGrid is a Grid - (see game.py) of either True or False. You can call foodGrid.asList() to get - a list of food coordinates instead. - - If you want access to info like walls, capsules, etc., you can query the - problem. For example, problem.walls gives you a Grid of where the walls - are. - - If you want to *store* information to be reused in other calls to the - heuristic, there is a dictionary called problem.heuristicInfo that you can - use. For example, if you only want to count the walls once and store that - value, try: problem.heuristicInfo['wallCount'] = problem.walls.count() - Subsequent calls to this heuristic can access - problem.heuristicInfo['wallCount'] - """ - position, foodGrid = state - "*** YOUR CODE HERE ***" - return 0 - -class ClosestDotSearchAgent(SearchAgent): - "Search for all food using a sequence of searches" - def registerInitialState(self, state): - self.actions = [] - currentState = state - while(currentState.getFood().count() > 0): - nextPathSegment = self.findPathToClosestDot(currentState) # The missing piece - self.actions += nextPathSegment - for action in nextPathSegment: - legal = currentState.getLegalActions() - if action not in legal: - t = (str(action), str(currentState)) - raise Exception('findPathToClosestDot returned an illegal move: %s!\n%s' % t) - currentState = currentState.generateSuccessor(0, action) - self.actionIndex = 0 - print('Path found with cost %d.' % len(self.actions)) - - def findPathToClosestDot(self, gameState): - """ - Returns a path (a list of actions) to the closest dot, starting from - gameState. - """ - # Here are some useful elements of the startState - startPosition = gameState.getPacmanPosition() - food = gameState.getFood() - walls = gameState.getWalls() - problem = AnyFoodSearchProblem(gameState) - - "*** YOUR CODE HERE ***" - util.raiseNotDefined() - -class AnyFoodSearchProblem(PositionSearchProblem): - """ - A search problem for finding a path to any food. - - This search problem is just like the PositionSearchProblem, but has a - different goal test, which you need to fill in below. The state space and - successor function do not need to be changed. - - The class definition above, AnyFoodSearchProblem(PositionSearchProblem), - inherits the methods of the PositionSearchProblem. - - You can use this search problem to help you fill in the findPathToClosestDot - method. - """ - - def __init__(self, gameState): - "Stores information from the gameState. You don't need to change this." - # Store the food for later reference - self.food = gameState.getFood() - - # Store info for the PositionSearchProblem (no need to change this) - self.walls = gameState.getWalls() - self.startState = gameState.getPacmanPosition() - self.costFn = lambda x: 1 - self._visited, self._visitedlist, self._expanded = {}, [], 0 # DO NOT CHANGE - - def isGoalState(self, state): - """ - The state is Pacman's position. Fill this in with a goal test that will - complete the problem definition. - """ - x,y = state - - "*** YOUR CODE HERE ***" - util.raiseNotDefined() - -def mazeDistance(point1, point2, gameState): - """ - Returns the maze distance between any two points, using the search functions - you have already built. The gameState can be any game state -- Pacman's - position in that state is ignored. - - Example usage: mazeDistance( (2,4), (5,6), gameState) - - This might be a useful helper function for your ApproximateSearchAgent. - """ - x1, y1 = point1 - x2, y2 = point2 - walls = gameState.getWalls() - assert not walls[x1][y1], 'point1 is a wall: ' + str(point1) - assert not walls[x2][y2], 'point2 is a wall: ' + str(point2) - prob = PositionSearchProblem(gameState, start=point1, goal=point2, warn=False, visualize=False) - return len(search.bfs(prob)) diff --git a/searchTestClasses.py b/searchTestClasses.py deleted file mode 100644 index f2a01af..0000000 --- a/searchTestClasses.py +++ /dev/null @@ -1,823 +0,0 @@ -# searchTestClasses.py -# -------------------- -# Licensing Information: You are free to use or extend these projects for -# educational purposes provided that (1) you do not distribute or publish -# solutions, (2) you retain this notice, and (3) you provide clear -# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# -# Attribution Information: The Pacman AI projects were developed at UC Berkeley. -# The core projects and autograders were primarily created by John DeNero -# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). -# Student side autograding was added by Brad Miller, Nick Hay, and -# Pieter Abbeel (pabbeel@cs.berkeley.edu). - - -import sys -import re -import testClasses -import textwrap - -# import project specific code -import layout -import pacman -from search import SearchProblem - -# helper function for printing solutions in solution files -def wrap_solution(solution): - if type(solution) == type([]): - return '\n'.join(textwrap.wrap(' '.join(solution))) - else: - return str(solution) - - - - -def followAction(state, action, problem): - for successor1, action1, cost1 in problem.getSuccessors(state): - if action == action1: return successor1 - return None - -def followPath(path, problem): - state = problem.getStartState() - states = [state] - for action in path: - state = followAction(state, action, problem) - states.append(state) - return states - -def checkSolution(problem, path): - state = problem.getStartState() - for action in path: - state = followAction(state, action, problem) - return problem.isGoalState(state) - -# Search problem on a plain graph -class GraphSearch(SearchProblem): - - # Read in the state graph; define start/end states, edges and costs - def __init__(self, graph_text): - self.expanded_states = [] - lines = graph_text.split('\n') - r = re.match('start_state:(.*)', lines[0]) - if r == None: - print("Broken graph:") - print('"""%s"""' % graph_text) - raise Exception("GraphSearch graph specification start_state not found or incorrect on line 0") - self.start_state = r.group(1).strip() - r = re.match('goal_states:(.*)', lines[1]) - if r == None: - print("Broken graph:") - print('"""%s"""' % graph_text) - raise Exception("GraphSearch graph specification goal_states not found or incorrect on line 1") - goals = r.group(1).split() - self.goals = [str.strip(g) for g in goals] - self.successors = {} - all_states = set() - self.orderedSuccessorTuples = [] - for l in lines[2:]: - if len(l.split()) == 3: - start, action, next_state = l.split() - cost = 1 - elif len(l.split()) == 4: - start, action, next_state, cost = l.split() - else: - print("Broken graph:") - print('"""%s"""' % graph_text) - raise Exception("Invalid line in GraphSearch graph specification on line:" + l) - cost = float(cost) - self.orderedSuccessorTuples.append((start, action, next_state, cost)) - all_states.add(start) - all_states.add(next_state) - if start not in self.successors: - self.successors[start] = [] - self.successors[start].append((next_state, action, cost)) - for s in all_states: - if s not in self.successors: - self.successors[s] = [] - - # Get start state - def getStartState(self): - return self.start_state - - # Check if a state is a goal state - def isGoalState(self, state): - return state in self.goals - - # Get all successors of a state - def getSuccessors(self, state): - self.expanded_states.append(state) - return list(self.successors[state]) - - # Calculate total cost of a sequence of actions - def getCostOfActions(self, actions): - total_cost = 0 - state = self.start_state - for a in actions: - successors = self.successors[state] - match = False - for (next_state, action, cost) in successors: - if a == action: - state = next_state - total_cost += cost - match = True - if not match: - print('invalid action sequence') - sys.exit(1) - return total_cost - - # Return a list of all states on which 'getSuccessors' was called - def getExpandedStates(self): - return self.expanded_states - - def __str__(self): - print(self.successors) - edges = ["%s %s %s %s" % t for t in self.orderedSuccessorTuples] - return \ -"""start_state: %s -goal_states: %s -%s""" % (self.start_state, " ".join(self.goals), "\n".join(edges)) - - - -def parseHeuristic(heuristicText): - heuristic = {} - for line in heuristicText.split('\n'): - tokens = line.split() - if len(tokens) != 2: - print("Broken heuristic:") - print('"""%s"""' % heuristicText) - raise Exception("GraphSearch heuristic specification broken at tokens:" + str(tokens)) - state, h = tokens - heuristic[state] = float(h) - - def graphHeuristic(state, problem=None): - if state in heuristic: - return heuristic[state] - else: - import pprint - pp = pprint.PrettyPrinter(indent=4) - print("Heuristic:") - pp.pprint(heuristic) - raise Exception("Graph heuristic called with invalid state: " + str(state)) - - return graphHeuristic - - -class GraphSearchTest(testClasses.TestCase): - - def __init__(self, question, testDict): - super(GraphSearchTest, self).__init__(question, testDict) - self.graph_text = testDict['graph'] - self.alg = testDict['algorithm'] - self.diagram = testDict['diagram'] - self.exactExpansionOrder = testDict.get('exactExpansionOrder', 'True').lower() == "true" - if 'heuristic' in testDict: - self.heuristic = parseHeuristic(testDict['heuristic']) - else: - self.heuristic = None - - # Note that the return type of this function is a tripple: - # (solution, expanded states, error message) - def getSolInfo(self, search): - alg = getattr(search, self.alg) - problem = GraphSearch(self.graph_text) - if self.heuristic != None: - solution = alg(problem, self.heuristic) - else: - solution = alg(problem) - - if type(solution) != type([]): - return None, None, 'The result of %s must be a list. (Instead, it is %s)' % (self.alg, type(solution)) - - return solution, problem.getExpandedStates(), None - - # Run student code. If an error message is returned, print error and return false. - # If a good solution is returned, printn the solution and return true; otherwise, - # print both the correct and student's solution and return false. - def execute(self, grades, moduleDict, solutionDict): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - gold_solution = [str.split(solutionDict['solution']), str.split(solutionDict['rev_solution'])] - gold_expanded_states = [str.split(solutionDict['expanded_states']), str.split(solutionDict['rev_expanded_states'])] - - solution, expanded_states, error = self.getSolInfo(search) - if error != None: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('\t%s' % error) - return False - - if solution in gold_solution and (not self.exactExpansionOrder or expanded_states in gold_expanded_states): - grades.addMessage('PASS: %s' % self.path) - grades.addMessage('\tsolution:\t\t%s' % solution) - grades.addMessage('\texpanded_states:\t%s' % expanded_states) - return True - else: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('\tgraph:') - for line in self.diagram.split('\n'): - grades.addMessage('\t %s' % (line,)) - grades.addMessage('\tstudent solution:\t\t%s' % solution) - grades.addMessage('\tstudent expanded_states:\t%s' % expanded_states) - grades.addMessage('') - grades.addMessage('\tcorrect solution:\t\t%s' % gold_solution[0]) - grades.addMessage('\tcorrect expanded_states:\t%s' % gold_expanded_states[0]) - grades.addMessage('\tcorrect rev_solution:\t\t%s' % gold_solution[1]) - grades.addMessage('\tcorrect rev_expanded_states:\t%s' % gold_expanded_states[1]) - return False - - def writeSolution(self, moduleDict, filePath): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - # open file and write comments - handle = open(filePath, 'w') - handle.write('# This is the solution file for %s.\n' % self.path) - handle.write('# This solution is designed to support both right-to-left\n') - handle.write('# and left-to-right implementations.\n') - - # write forward solution - solution, expanded_states, error = self.getSolInfo(search) - if error != None: raise Exception("Error in solution code: %s" % error) - handle.write('solution: "%s"\n' % ' '.join(solution)) - handle.write('expanded_states: "%s"\n' % ' '.join(expanded_states)) - - # reverse and write backwards solution - search.REVERSE_PUSH = not search.REVERSE_PUSH - solution, expanded_states, error = self.getSolInfo(search) - if error != None: raise Exception("Error in solution code: %s" % error) - handle.write('rev_solution: "%s"\n' % ' '.join(solution)) - handle.write('rev_expanded_states: "%s"\n' % ' '.join(expanded_states)) - - # clean up - search.REVERSE_PUSH = not search.REVERSE_PUSH - handle.close() - return True - - - -class PacmanSearchTest(testClasses.TestCase): - - def __init__(self, question, testDict): - super(PacmanSearchTest, self).__init__(question, testDict) - self.layout_text = testDict['layout'] - self.alg = testDict['algorithm'] - self.layoutName = testDict['layoutName'] - - # TODO: sensible to have defaults like this? - self.leewayFactor = float(testDict.get('leewayFactor', '1')) - self.costFn = eval(testDict.get('costFn', 'None')) - self.searchProblemClassName = testDict.get('searchProblemClass', 'PositionSearchProblem') - self.heuristicName = testDict.get('heuristic', None) - - - def getSolInfo(self, search, searchAgents): - alg = getattr(search, self.alg) - lay = layout.Layout([l.strip() for l in self.layout_text.split('\n')]) - start_state = pacman.GameState() - start_state.initialize(lay, 0) - - problemClass = getattr(searchAgents, self.searchProblemClassName) - problemOptions = {} - if self.costFn != None: - problemOptions['costFn'] = self.costFn - problem = problemClass(start_state, **problemOptions) - heuristic = getattr(searchAgents, self.heuristicName) if self.heuristicName != None else None - - if heuristic != None: - solution = alg(problem, heuristic) - else: - solution = alg(problem) - - if type(solution) != type([]): - return None, None, 'The result of %s must be a list. (Instead, it is %s)' % (self.alg, type(solution)) - - from game import Directions - dirs = Directions.LEFT.keys() - if [el in dirs for el in solution].count(False) != 0: - return None, None, 'Output of %s must be a list of actions from game.Directions' % self.alg - - expanded = problem._expanded - return solution, expanded, None - - def execute(self, grades, moduleDict, solutionDict): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - gold_solution = [str.split(solutionDict['solution']), str.split(solutionDict['rev_solution'])] - gold_expanded = max(int(solutionDict['expanded_nodes']), int(solutionDict['rev_expanded_nodes'])) - - solution, expanded, error = self.getSolInfo(search, searchAgents) - if error != None: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('%s' % error) - return False - - # FIXME: do we want to standardize test output format? - - if solution not in gold_solution: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('Solution not correct.') - grades.addMessage('\tstudent solution length: %s' % len(solution)) - grades.addMessage('\tstudent solution:\n%s' % wrap_solution(solution)) - grades.addMessage('') - grades.addMessage('\tcorrect solution length: %s' % len(gold_solution[0])) - grades.addMessage('\tcorrect (reversed) solution length: %s' % len(gold_solution[1])) - grades.addMessage('\tcorrect solution:\n%s' % wrap_solution(gold_solution[0])) - grades.addMessage('\tcorrect (reversed) solution:\n%s' % wrap_solution(gold_solution[1])) - return False - - if expanded > self.leewayFactor * gold_expanded and expanded > gold_expanded + 1: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('Too many node expanded; are you expanding nodes twice?') - grades.addMessage('\tstudent nodes expanded: %s' % expanded) - grades.addMessage('') - grades.addMessage('\tcorrect nodes expanded: %s (leewayFactor %s)' % (gold_expanded, self.leewayFactor)) - return False - - grades.addMessage('PASS: %s' % self.path) - grades.addMessage('\tpacman layout:\t\t%s' % self.layoutName) - grades.addMessage('\tsolution length: %s' % len(solution)) - grades.addMessage('\tnodes expanded:\t\t%s' % expanded) - return True - - - def writeSolution(self, moduleDict, filePath): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - # open file and write comments - handle = open(filePath, 'w') - handle.write('# This is the solution file for %s.\n' % self.path) - handle.write('# This solution is designed to support both right-to-left\n') - handle.write('# and left-to-right implementations.\n') - handle.write('# Number of nodes expanded must be with a factor of %s of the numbers below.\n' % self.leewayFactor) - - # write forward solution - solution, expanded, error = self.getSolInfo(search, searchAgents) - if error != None: raise Exception("Error in solution code: %s" % error) - handle.write('solution: """\n%s\n"""\n' % wrap_solution(solution)) - handle.write('expanded_nodes: "%s"\n' % expanded) - - # write backward solution - search.REVERSE_PUSH = not search.REVERSE_PUSH - solution, expanded, error = self.getSolInfo(search, searchAgents) - if error != None: raise Exception("Error in solution code: %s" % error) - handle.write('rev_solution: """\n%s\n"""\n' % wrap_solution(solution)) - handle.write('rev_expanded_nodes: "%s"\n' % expanded) - - # clean up - search.REVERSE_PUSH = not search.REVERSE_PUSH - handle.close() - return True - - -from game import Actions -def getStatesFromPath(start, path): - "Returns the list of states visited along the path" - vis = [start] - curr = start - for a in path: - x,y = curr - dx, dy = Actions.directionToVector(a) - curr = (int(x + dx), int(y + dy)) - vis.append(curr) - return vis - -class CornerProblemTest(testClasses.TestCase): - - def __init__(self, question, testDict): - super(CornerProblemTest, self).__init__(question, testDict) - self.layoutText = testDict['layout'] - self.layoutName = testDict['layoutName'] - - def solution(self, search, searchAgents): - lay = layout.Layout([l.strip() for l in self.layoutText.split('\n')]) - gameState = pacman.GameState() - gameState.initialize(lay, 0) - problem = searchAgents.CornersProblem(gameState) - path = search.bfs(problem) - - gameState = pacman.GameState() - gameState.initialize(lay, 0) - visited = getStatesFromPath(gameState.getPacmanPosition(), path) - top, right = gameState.getWalls().height-2, gameState.getWalls().width-2 - missedCorners = [p for p in ((1,1), (1,top), (right, 1), (right, top)) if p not in visited] - - return path, missedCorners - - def execute(self, grades, moduleDict, solutionDict): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - gold_length = int(solutionDict['solution_length']) - solution, missedCorners = self.solution(search, searchAgents) - - if type(solution) != type([]): - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('The result must be a list. (Instead, it is %s)' % type(solution)) - return False - - if len(missedCorners) != 0: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('Corners missed: %s' % missedCorners) - return False - - if len(solution) != gold_length: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('Optimal solution not found.') - grades.addMessage('\tstudent solution length:\n%s' % len(solution)) - grades.addMessage('') - grades.addMessage('\tcorrect solution length:\n%s' % gold_length) - return False - - grades.addMessage('PASS: %s' % self.path) - grades.addMessage('\tpacman layout:\t\t%s' % self.layoutName) - grades.addMessage('\tsolution length:\t\t%s' % len(solution)) - return True - - def writeSolution(self, moduleDict, filePath): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - # open file and write comments - handle = open(filePath, 'w') - handle.write('# This is the solution file for %s.\n' % self.path) - - print("Solving problem", self.layoutName) - print(self.layoutText) - - path, _ = self.solution(search, searchAgents) - length = len(path) - print("Problem solved") - - handle.write('solution_length: "%s"\n' % length) - handle.close() - - - - -# template = """class: "HeuristicTest" -# -# heuristic: "foodHeuristic" -# searchProblemClass: "FoodSearchProblem" -# layoutName: "Test %s" -# layout: \"\"\" -# %s -# \"\"\" -# """ -# -# for i, (_, _, l) in enumerate(doneTests + foodTests): -# f = open("food_heuristic_%s.test" % (i+1), "w") -# f.write(template % (i+1, "\n".join(l))) -# f.close() - -class HeuristicTest(testClasses.TestCase): - - def __init__(self, question, testDict): - super(HeuristicTest, self).__init__(question, testDict) - self.layoutText = testDict['layout'] - self.layoutName = testDict['layoutName'] - self.searchProblemClassName = testDict['searchProblemClass'] - self.heuristicName = testDict['heuristic'] - - def setupProblem(self, searchAgents): - lay = layout.Layout([l.strip() for l in self.layoutText.split('\n')]) - gameState = pacman.GameState() - gameState.initialize(lay, 0) - problemClass = getattr(searchAgents, self.searchProblemClassName) - problem = problemClass(gameState) - state = problem.getStartState() - heuristic = getattr(searchAgents, self.heuristicName) - - return problem, state, heuristic - - def checkHeuristic(self, heuristic, problem, state, solutionCost): - h0 = heuristic(state, problem) - - if solutionCost == 0: - if h0 == 0: - return True, '' - else: - return False, 'Heuristic failed H(goal) == 0 test' - - if h0 < 0: - return False, 'Heuristic failed H >= 0 test' - if not h0 > 0: - return False, 'Heuristic failed non-triviality test' - if not h0 <= solutionCost: - return False, 'Heuristic failed admissibility test' - - for succ, action, stepCost in problem.getSuccessors(state): - h1 = heuristic(succ, problem) - if h1 < 0: return False, 'Heuristic failed H >= 0 test' - if h0 - h1 > stepCost: return False, 'Heuristic failed consistency test' - - return True, '' - - def execute(self, grades, moduleDict, solutionDict): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - solutionCost = int(solutionDict['solution_cost']) - problem, state, heuristic = self.setupProblem(searchAgents) - - passed, message = self.checkHeuristic(heuristic, problem, state, solutionCost) - - if not passed: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('%s' % message) - return False - else: - grades.addMessage('PASS: %s' % self.path) - return True - - def writeSolution(self, moduleDict, filePath): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - # open file and write comments - handle = open(filePath, 'w') - handle.write('# This is the solution file for %s.\n' % self.path) - - print("Solving problem", self.layoutName, self.heuristicName) - print(self.layoutText) - problem, _, heuristic = self.setupProblem(searchAgents) - path = search.astar(problem, heuristic) - cost = problem.getCostOfActions(path) - print("Problem solved") - - handle.write('solution_cost: "%s"\n' % cost) - handle.close() - return True - - - - - - -class HeuristicGrade(testClasses.TestCase): - - def __init__(self, question, testDict): - super(HeuristicGrade, self).__init__(question, testDict) - self.layoutText = testDict['layout'] - self.layoutName = testDict['layoutName'] - self.searchProblemClassName = testDict['searchProblemClass'] - self.heuristicName = testDict['heuristic'] - self.basePoints = int(testDict['basePoints']) - self.thresholds = [int(t) for t in testDict['gradingThresholds'].split()] - - def setupProblem(self, searchAgents): - lay = layout.Layout([l.strip() for l in self.layoutText.split('\n')]) - gameState = pacman.GameState() - gameState.initialize(lay, 0) - problemClass = getattr(searchAgents, self.searchProblemClassName) - problem = problemClass(gameState) - state = problem.getStartState() - heuristic = getattr(searchAgents, self.heuristicName) - - return problem, state, heuristic - - - def execute(self, grades, moduleDict, solutionDict): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - problem, _, heuristic = self.setupProblem(searchAgents) - - path = search.astar(problem, heuristic) - - expanded = problem._expanded - - if not checkSolution(problem, path): - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('\tReturned path is not a solution.') - grades.addMessage('\tpath returned by astar: %s' % expanded) - return False - - grades.addPoints(self.basePoints) - points = 0 - for threshold in self.thresholds: - if expanded <= threshold: - points += 1 - grades.addPoints(points) - if points >= len(self.thresholds): - grades.addMessage('PASS: %s' % self.path) - else: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('\texpanded nodes: %s' % expanded) - grades.addMessage('\tthresholds: %s' % self.thresholds) - - return True - - - def writeSolution(self, moduleDict, filePath): - handle = open(filePath, 'w') - handle.write('# This is the solution file for %s.\n' % self.path) - handle.write('# File intentionally blank.\n') - handle.close() - return True - - - - - -# template = """class: "ClosestDotTest" -# -# layoutName: "Test %s" -# layout: \"\"\" -# %s -# \"\"\" -# """ -# -# for i, (_, _, l) in enumerate(foodTests): -# f = open("closest_dot_%s.test" % (i+1), "w") -# f.write(template % (i+1, "\n".join(l))) -# f.close() - -class ClosestDotTest(testClasses.TestCase): - - def __init__(self, question, testDict): - super(ClosestDotTest, self).__init__(question, testDict) - self.layoutText = testDict['layout'] - self.layoutName = testDict['layoutName'] - - def solution(self, searchAgents): - lay = layout.Layout([l.strip() for l in self.layoutText.split('\n')]) - gameState = pacman.GameState() - gameState.initialize(lay, 0) - path = searchAgents.ClosestDotSearchAgent().findPathToClosestDot(gameState) - return path - - def execute(self, grades, moduleDict, solutionDict): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - gold_length = int(solutionDict['solution_length']) - solution = self.solution(searchAgents) - - if type(solution) != type([]): - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('\tThe result must be a list. (Instead, it is %s)' % type(solution)) - return False - - if len(solution) != gold_length: - grades.addMessage('FAIL: %s' % self.path) - grades.addMessage('Closest dot not found.') - grades.addMessage('\tstudent solution length:\n%s' % len(solution)) - grades.addMessage('') - grades.addMessage('\tcorrect solution length:\n%s' % gold_length) - return False - - grades.addMessage('PASS: %s' % self.path) - grades.addMessage('\tpacman layout:\t\t%s' % self.layoutName) - grades.addMessage('\tsolution length:\t\t%s' % len(solution)) - return True - - def writeSolution(self, moduleDict, filePath): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - # open file and write comments - handle = open(filePath, 'w') - handle.write('# This is the solution file for %s.\n' % self.path) - - print("Solving problem", self.layoutName) - print(self.layoutText) - - length = len(self.solution(searchAgents)) - print("Problem solved") - - handle.write('solution_length: "%s"\n' % length) - handle.close() - return True - - - - -class CornerHeuristicSanity(testClasses.TestCase): - - def __init__(self, question, testDict): - super(CornerHeuristicSanity, self).__init__(question, testDict) - self.layout_text = testDict['layout'] - - def execute(self, grades, moduleDict, solutionDict): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - game_state = pacman.GameState() - lay = layout.Layout([l.strip() for l in self.layout_text.split('\n')]) - game_state.initialize(lay, 0) - problem = searchAgents.CornersProblem(game_state) - start_state = problem.getStartState() - h0 = searchAgents.cornersHeuristic(start_state, problem) - succs = problem.getSuccessors(start_state) - # cornerConsistencyA - for succ in succs: - h1 = searchAgents.cornersHeuristic(succ[0], problem) - if h0 - h1 > 1: - grades.addMessage('FAIL: inconsistent heuristic') - return False - heuristic_cost = searchAgents.cornersHeuristic(start_state, problem) - true_cost = float(solutionDict['cost']) - # cornerNontrivial - if heuristic_cost == 0: - grades.addMessage('FAIL: must use non-trivial heuristic') - return False - # cornerAdmissible - if heuristic_cost > true_cost: - grades.addMessage('FAIL: Inadmissible heuristic') - return False - path = solutionDict['path'].split() - states = followPath(path, problem) - heuristics = [] - for state in states: - heuristics.append(searchAgents.cornersHeuristic(state, problem)) - for i in range(0, len(heuristics) - 1): - h0 = heuristics[i] - h1 = heuristics[i+1] - # cornerConsistencyB - if h0 - h1 > 1: - grades.addMessage('FAIL: inconsistent heuristic') - return False - # cornerPosH - if h0 < 0 or h1 <0: - grades.addMessage('FAIL: non-positive heuristic') - return False - # cornerGoalH - if heuristics[len(heuristics) - 1] != 0: - grades.addMessage('FAIL: heuristic non-zero at goal') - return False - grades.addMessage('PASS: heuristic value less than true cost at start state') - return True - - def writeSolution(self, moduleDict, filePath): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - # write comment - handle = open(filePath, 'w') - handle.write('# In order for a heuristic to be admissible, the value\n') - handle.write('# of the heuristic must be less at each state than the\n') - handle.write('# true cost of the optimal path from that state to a goal.\n') - - # solve problem and write solution - lay = layout.Layout([l.strip() for l in self.layout_text.split('\n')]) - start_state = pacman.GameState() - start_state.initialize(lay, 0) - problem = searchAgents.CornersProblem(start_state) - solution = search.astar(problem, searchAgents.cornersHeuristic) - handle.write('cost: "%d"\n' % len(solution)) - handle.write('path: """\n%s\n"""\n' % wrap_solution(solution)) - handle.close() - return True - - - -class CornerHeuristicPacman(testClasses.TestCase): - - def __init__(self, question, testDict): - super(CornerHeuristicPacman, self).__init__(question, testDict) - self.layout_text = testDict['layout'] - - def execute(self, grades, moduleDict, solutionDict): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - total = 0 - true_cost = float(solutionDict['cost']) - thresholds = [int(x) for x in solutionDict['thresholds'].split()] - game_state = pacman.GameState() - lay = layout.Layout([l.strip() for l in self.layout_text.split('\n')]) - game_state.initialize(lay, 0) - problem = searchAgents.CornersProblem(game_state) - start_state = problem.getStartState() - if searchAgents.cornersHeuristic(start_state, problem) > true_cost: - grades.addMessage('FAIL: Inadmissible heuristic') - return False - path = search.astar(problem, searchAgents.cornersHeuristic) - print("path:", path) - print("path length:", len(path)) - cost = problem.getCostOfActions(path) - if cost > true_cost: - grades.addMessage('FAIL: Inconsistent heuristic') - return False - expanded = problem._expanded - points = 0 - for threshold in thresholds: - if expanded <= threshold: - points += 1 - grades.addPoints(points) - if points >= len(thresholds): - grades.addMessage('PASS: Heuristic resulted in expansion of %d nodes' % expanded) - else: - grades.addMessage('FAIL: Heuristic resulted in expansion of %d nodes' % expanded) - return True - - def writeSolution(self, moduleDict, filePath): - search = moduleDict['search'] - searchAgents = moduleDict['searchAgents'] - # write comment - handle = open(filePath, 'w') - handle.write('# This solution file specifies the length of the optimal path\n') - handle.write('# as well as the thresholds on number of nodes expanded to be\n') - handle.write('# used in scoring.\n') - - # solve problem and write solution - lay = layout.Layout([l.strip() for l in self.layout_text.split('\n')]) - start_state = pacman.GameState() - start_state.initialize(lay, 0) - problem = searchAgents.CornersProblem(start_state) - solution = search.astar(problem, searchAgents.cornersHeuristic) - handle.write('cost: "%d"\n' % len(solution)) - handle.write('path: """\n%s\n"""\n' % wrap_solution(solution)) - handle.write('thresholds: "2000 1600 1200"\n') - handle.close() - return True - diff --git a/submission_autograder.py b/submission_autograder.py index 60b140c..78fbfa8 100644 --- a/submission_autograder.py +++ b/submission_autograder.py @@ -26,5 +26,5 @@ If you're having trouble running the autograder, please contact the staff. ============================================================================== """ import bz2, base64 -exec(bz2.decompress(base64.b64decode('QlpoOTFBWSZTWbTDk+sAPHbfgHkQfv///3////7////7YB18OzKH3ihw3rzeAV1sx7MsrHfYbvg8NnoA+9gHXeQUG2uMzYO1uzSNKDCEQlVtUMw5sG2BCkp2A1fcJJCBMTJppkEyGQno1NBPSZkyaRk00AGg09CANNBNBNECaNCUeMlNoam1HqeoNNMj1NBo0AAAA0yIp6mlP1Js1BNpA0ek9TepNlBhGjTQABoGmRkMgk0iSESep6SZqT1DxGoNGg2U0YgHqANNAAAPUCKiSekyA00AAA0AMjQADQAAAAAkSCAEyCaGjUT00TVPNJ6RhJsyoeUHqD1AABmp1IfFE+aHqMn+9qjEGfjYX+Rr/yl/HYXbYiinGiCDH4bWf92VYqMQSI/2WqqKoC/KlZzt9eFZNgkUx3AushRWCQYsnkklYf2priHpmYr1bKh/CzkDlUqoZyJliTqIuWzHgztVeAEyqvUA+599fyefLuZw+J7M7+bu/F/GXu7fXO/txUEnvwzxVZj4ZTg9zuDTQ8XxrddzOFGyCZkPa/zVSYM1zNY1LZJ9SFLq7zxC5kjBJIViiKiKgsFGMBUUFYgrIsVGQRFn5X0+378+/Pq9/0GeX3D46Z66IrcTtLI8kpNMq2vX4tsPyhU3rw1Ph6MI7D3O8rZiRs5ic4crKMQQpQfampguJulN9dwyq8MzKtSczdKbaNjZsxluYmGBlStLKKsy1Q+JC8OMczmyldpSOc3DS8CVVVVYKtk+XnA78M50EWRY3UKkwrbZVsLFCcDFFFf5dxmYqt95KPXdrIb4e2KH9lX9AG7nbZRwoVsM8O9Wxx3YFtgdXUMnLS8aFsZmE2BBJJRAVZx4bNXYCU8lgK64vMiiYXUuAb7PJuNFdt9NmXC8rsQUIKT6lGg1nHHzYc7lzvsu7imu7cfXoQN4xDbTTNK4FgyI4ESw4wS/5URxGDaeXCG2De3LvwoFl+fNRNCgUQPEZnhHjcZv81bxIh8gbXo4mnUgggkgEoCQhBDdYNZxfOLx2KrKXd98IuVWipbuhcDU4oY3093VgTU7GxaVuN6Zxba7zNW5LG++8yUi/Ya7irG32k7M/ABccKaafKOHzjjNUbnDO3D05duV7zk8bOOrPxxt8XVP54+HEKaa7GQLP7YLW6TumHQg9SS32+bwwx5C2IGSlUK3QDBq9Xe/ObTybZqCefA1qvzSQsCdxdTM9Jc92LJU/Rk03WRfGYpbxM3NyPatxBmYYZMNNecv1GTFoaOTz5l2W2FO8bW0JnbrmRNdhTOlbH5eEjvysz2PXHDnOo34tn6/jSZSyIi667mVOJkY+0hfhBgYCscJq0iQzKSYmCiWZamZf+OXwvi/31agW646ZbobEx6MnKEm/4QyCbc9gJEnJhxi0a86usFmo8tpcz4jDo2gdWHye/8U9iX7WeNn3Mn0Yz1WJVUI2wri+fd197ts7tKY7sxNPK+XYw09x4Z1dWXpiVIAEzU6U7ilR8ieQmMI5S5EhVLKzKVBVWXR27saOJlaiZGHRKQgBQEUCu3FeWLUXiKh6zR6ZKRBpfb2dMdlNNBcMBYo+A7i9Ad6WECFEBzIdmqhTShow5mzAsOdIEyCFxV8EAMCB1Lthcmx4dwxjRNAF0Nl9BS7m9A1RCq2igi4C2pdpuF0oFfSXSoVHTlTGj79RxyONV9lcZ6vsR9E2Rvxarii4lUP5DNL1pNhbv/GxiNyu6jBAbuViLBwqsJzWNpEUyyoUTZURy1V/QR70rYLIsqsB267mk/gVNCdH8rPOrbiFpuxOaakn4QO+XAwqT3e6Qg2RMqyCcJz01IjPhqxFtM7JZ3+temk558mcOaDpntcS+yt0wayajGk6P15kX3dhpywnXIVl/DTQ67UMopLcF+Sy2jL7qhYVX9JsVoa9YN110KD3gU+q64VR5hZS+sW50l1ABKUK9NWkc+DUmt7jQoqDx1iKTFucHzYtsslBANMXkA7Lhz0Szap1me49UiNIrLhWGurDuaKOTp7+Nvx47GFvgxLVhDHmQ+FJKTUOdYI7utZmvfFd0QzZqHfJ2bocC+SdhBMHI+itSlvI2NhgN5zil/f9s6mRqGBrlFEAQwJKKmhgp4EUF6DwsoiOxG2snFvg7pnVY1q8HEBRiAsroJpor0yICs6ito0w71GRvyN/PXv0rqCs7URQ5R9Md2Lcjc5LYdds8tvDcQDH2a73HbFrwRNg2aRugDUp78p7mgqXNF/h0Dza6xAQM6lVjhcg6yWrHFKngp/hEpgVQGn7bgI68HZiDublW1BUCcYumlYlBDjkAFp6kGFlaa5dB4ZhtCBgghCi2x11cY+SVYFFE6kB6J2IU031WiMQnxgucFyaDZXjeiaAwV+Ofk+AIfCZE8bM5UIQabcOGRnnFZKpykjw+LG+PdF21DedIrv6zyAXJEaBjVW6ltoDG7hMwG+unq4n+Lvs4C5ozjhFBioiBwfMDOGILbYIhP5biCHwGYfbS79y+4DmX4u2uQ25rp9RExpmZucZGsaOuyPqzw6NCCAGT8J8YNjFRY2FUnTO6ENa9Dzt5q9Iju+LVONumTepY81a55cxtYYFBdrqSCCN4p3blsbVDiRJFSNeF6XOmmRbZtZmFZjPZyviY98bW3YE1w9ZtrI4FALu4q2hQBb7wwAXdJq6v8No65J1jqlgjZgm4yyeUEibwdySlBa88APNys14ywSZTipjQRZsSBSZsYVMmd3eNjPnoUpBIk6CI8SBnSRnv9nqt7eFD1/Zw8lEt9fiuVOBN2a0C4NqnsxXgI4OQRPsGZ3X+bXz8dmuKeuvC4MKKSdCH/XHaaSVK1lSGXcIZUYKDxD6b9+lFWIsCCQKcS7OQitFsfepSLgk1lQqg1Fwfa96CYmIJW6qckakRRNLfMI1goExFdFK8Zgiap4E80SZJPJGJ4b0UJopH5PS0Pn09GzZ7fgUb3Dn64ewBJCPVy8WE8tV1wwXOd8eSUpRLVxrb8CTIvyQA9wgIk6ElEEZRlEBGHdkAOEk4NDRgIMIdilhEQKBSkkRIGGPQkjaUwNEESEmylkiIXBwySIklzhUswJoyCJANKWQRDMFwxAgQH38qlia25GtZRPQBUSWtJSAVEhYQDplqe/Z54PNPO0BUSrYBhgKiRpyXV1ZlmAqJMo4GoAqJI0JT6o0a4r/0BUSFSqAqJ8WoCol5N2AFRJpgY1C+wQFRPSUrTtgBUSnYWEe9Ly6ZqOwBJCJYZpcnFQNrASQimd7OwgSQha2/T9k9n3ev5uvT4Q/IhizRlGa/kwt0bN1pm3U1qqwv7dMyiK1GJ+p9G97vedyySbSzWVUrLMTFKufpAdWBEA1IckOvymBrNEF4jbOxc26CqaXcPCtyXR/1cenZcRcJxOnglSmcu04db1MVWKupTMrmBb1cc2eHWbWk0cKTp18u9DUFxh0CcpakoMEazqXImRMTDMKZlSZkMkxQ1LGLcoZrmFRr3pmm3EVURW0tLVVUJUWqg+LI9x48XLR1qlu0K+zLuXVx7thW9nfAkI26yooPY7+AzRfsJ3xV7NarkFGtitV8OCke+4HC43b3rEScntmzf/0AkhGt9YEdPLWlnP4AJIRZawzhvZgComGAqJJMpx6wFRPkBUSnlTgRa2lPw/hwMxy3MMZMmZlxpsbuuX3ZrhuS2GKUbkuYLcRZlnMc1MXSGDBGDTAoNBBibCJiA0mFKBTAHRLarWFKYRHGyWWKIxjhQqRjIi+03ATmrZcsawsYoMWVlaULCmSXLbKMFFyFEoogiyzlMzLbQclttKjWECxtZYQEomBTKgggg5WtaiAqEkG3d0QdCSZKBfcR7nqoudo3Gg+MslMwwPxD6fUfBPfUUJ9Xjx5+z7e3q0/n+fcZ7RDniyLfXMo7DJfh8A+jT61vLbKB8EOq/X9KOdwfjq/iAxut2RC9un1TE5A5hxL9I4miJqB+2ZKqNGEne+aZxZb7hnOGphajLa8D9Ll2ZMlgCSEe2L+pZy7EjtDGtwZ3I9Ov+Zmme1Byxsm0FBsYoIxWGQtEck5IwTmfjDXFdylFiPsdaTJ5aAYIrScq4/Z+ISNxPjIAlZbsQSEBEEPDS3xaUzcOk5onCrHnUGF6LD1W4HNR0Iwzv+YCFcu0Jw7FkgbPpZf4g9zDlIAvKYoGVzTG62SMcPta7DjEZl1555GwaGcoMEZL3vBzSEqAbJ6gEkIwLBU0Cu9iuAOgBCwWCx9MduECU2uVh9d56yRmF8brO2RLoAkhDKFrJnAiasniWMamJQ1AY2L1I73BUqrgwmlj/LKoT3oDHZ180r71atGG/U5fx3vfpIi1kPloSYD8aBGyw+6W6xo43zmqqFvCWyvQbv0AcbOcGDL25kQuyJIvsMJax4SRV97u6pkROFi4J/LG36yfi6gcedTITxuILBjh/7JAJM7waPXxZVnV96xdvl0ohEXoCdI30maAzuIEQGEwMSlmB3GyTqkHycKznfmMOCASWtfLPG1g2DRGhVIiwFxIGeIraVa5IAGljosClBVTI0m9HEZ+oCT+nR/L10oCyE+mrsNqCPUD5aKBa/O1YAZlsnJ4Wz2e65aj5VlTx0IuxCpKInploKqoCWYh2iVTMJ3gUWziwqHcyK02v56WAg6MqVBRA46MGqUbJ3u3GcpDwrSWd0ZGVxJkEyEvzASQi1bA1pRKiUhe/Oe+yUg4AR+hK21HXab4eukquVqXqJ4RacQFCDQg2bnAMgpoEkaJgs4cpnCGaMRLoWEkweAgzA4Dfw6uDRkzKpDg9OJXPzGcxm+7MCOMdJQYHjuHEVjcgHP6Yr1dYOKMCyKxRlYCRMiCMkbr1MLBRyyvtFxQNUL+D64wLwKSchDREUJa0GcSlhmw/k6IK363X+wkT8hGBzb9ZqaSCm6ZZrPWKk2KjxDjH7jFlAtFYgLrbYsSZK6Yi6QBeWAflT5LAAttUF/IWfYMZTwTQOhG63uS8RNgmhjYCYxo7uE/jjRKn4Vg7h0HgUXvZ+vtTDR+07+dQ5xszKXS+bXj1y9J9zNW5UA2BSxUqVBWC6x2hAE+eJCEHs22MrZoQzEbD5xkSMJgQQokGDGpgTQgckIJDAY0iUvIuT16F4bRWBAIbCiUr1K565IxycUEaVsFDP4QHwh4CJGx8dz3HsPsKVhRL8ISiHxCAgxTNWkyIXsZMhocEitCGCREHvPuiQaYNj1XlvHcg1Kr0YJYi5wERDWAOUlIT7bOjtNOjTylmCeiNbaBoJZYMEPZj7urWBiBUfOh7uWoCxZ9lAEHzq/ITpLRLoy4Uy4fkLtizkWfeAkhEwJ2pUaO4Z7uOB2HsaTWxCRA0yLtJhA/cxEBQiCM978fmJhVWMi5MEQQ/l77+JskUqfmAkhFdqIMbnKwZN1akSvhxK8Ea+XdF58qRNhEU3hPdmHBLzGKG39bS771ugoZ3e+m9OwDBL+ACSEWeSbPM+F64tA2IJpoD3tKoINwBuEllBaTMpcEsGxI7nTo4vsOQLisG4TnV1GO8ZkQYyy7XIiTyHFRjTJSh77+PD2gaZ/Lcsi5FsaJobTbEDGxpof0IKH5wZ2I3JB3v0HZ15ZNGO72PyVtxgLij7b5EgYDygNS3f5Jds88C6dpx3OW2NbQkegyBewBJCNNHPP1ROcHRzoDNOgpCJh6Sx33cp9kXrP3AJIRde5owz1hajUmvoElnwfe6+jQHXN2YXDTamCPU5mGpnBLctF7N3UVx6+fo2G737Yjm8N7cOmuHG5exnNqI8DkQRDDAiLCsag0XSXAowSLghQEitzt3fvQ9fMKHR5jYcGIMmkZB+XujAmq8YU2hXcDGYieponkQNjhgQLVBSCE2TUxrvxHjuVq8Twy8Pn1qd/fvF2LewOyCBbSjtIhbXeFrR54abyDLNGNIlzMCpuMmZrOTA6boA1RAdoc0+j7nITalCiMcwpMy1oykWJT4/AXhwU4VtlayqUEW2eV7LklNBXBZRttoWPvUzC7kMhDMWgkRJGmTCHYslNsYQNxEJKe1hXZwpG1ERKf6AJIRxXs6anpZw7L4Pf8kkjnRabozn2KHKIL4UNpA0mAyO9jTYbPlh21t7jAw44kvFd0VDNHQDEBiu0vQdlo/qtCbxAPsGSsmDZp9mXB8zBd2/3XGCfMIYJ52e8KIggiKIrEDKNLdHCtL72OabU/ggVie7t2A4hvweiZkIfGn19Um2ncXsCUhMLjDTpbb35TGTjsOF6OACSEcArDyh544UYHsKQyAUlIz39M/SE1pCKIDpZJlmaJe0Vl4G6dnLk+I0Gw1qvVrb5xIeqYKApJ5IGsEKy+qSbIx4ci6mjaxn+Z1sL0snB0jzngDlWKIZmZ+kxl9pkl9DMxZgrT1gj4AoPTZdF9mzP0pZ7t0clxhS1e5pHOkTq2QMwkPe5mEQC+ToMq9kkikQ9ioMDtfjx35aX/qo0CguLt81ULUO2q/i8xVDRpFoIojDlmHkASQjfqkmSM7EOdYyzESw8Y0IAXrl2+CWmSgLxdcwy5+M5tKXAwcbkGd26KLvAJIRxvVfNrXrau5KOS0ZDdvAZ7MI3fpRr15CJhUVPEiEkrWywZaGYYKGkmkuETIoQRLqvomkKRAbGxwpjNoCSEYZwh5mPXevswIYj6RttX0Sj5NDw3o0wLIkPXt4z9gCSEO1DpK2eQH0AH1JjkgMOoBO65YvMZJMtA7M6ypBSLogvRj5CzFTtxP1FqJniHz3rMY6ZQkl1d/POu4GsPOkpzKJlVB8xrVFBDwTAGAGtqLRF3n8ypgPVYcrccA/vUBuCQEBa8wDNpp4fP8LSZRt1EUQL4eJXRX+QTiqOwDED7kxeKMo4qioR6COE0uDEeljlRJdIIVfQrdRVDjYbqgCyiFDXRbzV8rcTuniygJPECv28PQheY2hx6fMCSEHKMblhUJC1Ss3dX2uegcm4tGMZIIVQ6s+XK7zHdfW+xEwxvn6EBIDRcQqToed1/lPG9ItwhMaAbWHHThosd5vj2jnwAuNhaWg2JgiShAMHmOM4jiBAGxff2yrebRfhcX762ckydLscXA38XFtqtidxa+1Es2sHMIOWekacTW9EAyrlZ7aMFZZ3UyVIHUbGSliFWWZyBbCgwKGJw44BxukyC0BzrrdnBhxGb8wEiEVJ1SZez3EC75XYAXWB+1010znfZcOJBKkpyzHDKOuUC8Lja3BH3MIefRg/HHIKXYAi1JgYMakgO1rxLK4BmonrQ32erv8DhxDi0xoJoNpmvDed05uhukSjOJKUROJZJUBO5k0STRckQOvcePNEksB2ofDIzbZkxEIHviQ+5I3WJyACeJjguJ72+wMEzkSB4dsqjdIIY4furMwzCpTE6XblmLczMcqpQwyCFcQ1dttHTJWGYWhwBmxmnKuVTHgx13GMmK1Qoq2plKqbLVy0Yo0lxWhiMxilBxHPTwHS4Au14K7YlCmfeIjaD8x5aUhQ2yGEA4aix9+SA5kGOEzBsD6Q547dpw7eqplYUuUTMgi2F9szR0hvp8gYc1gopQmL2vN3nSxDX+GB3eSicpSRbauFOtkgA6hYBTwHT0xyHt6+y3vGX3Fe5GHQyj722BCtMjmjnECW+7LWjaFWtQwtH0woDIZKorgTnCQ2pm3PHf168dwCSEOc9t3oe6Oqb1t8nTEo5Zzw9ZOWLCa9viAkhGVanaWC6TLblCUxUSA+s0nos8wCSEUyi5WSYN/RvNt2Qv0vT1GRZ4dcnl3782SeSQ7w548N+W7ram0C3dLg7m5vfRm9uiceNEWNzDMK1bTpMwrKwZkTfHfPEGAbAsM7TZA7afMm97r1uIp1W2vC49Ga74R47laDgtrJQgIRa6DUdyUxBcbGCFCVGGFkMBGVAULJ33iHl5EzoZsolpROpIeMNmTZHMU7mZmC24ywKjglCQQgYNjalCY6bI8OaLi76awy61OSBl1aUbEzK2yUaUxUsjJjFFhSEMZIZAtvqNBqEcjJgPx1P8gEkI1NLCm6QMIFD8ihs4l8wi2/u46VbM8Q4G4P19FxHQ5cFxouQHDkg+sD/xdyRThQkLTDk+s'))) +exec(bz2.decompress(base64.b64decode('QlpoOTFBWSZTWcngzx4AO57fgHkQfv///3////7////7YB1cEk+5twc46nOaALplk1ixNhG4Btg0AAANATBVKW2ORoA6NUKVJlTKLroCNAO466AA4JIhATEGmmk0CaegJiJtJtNU8AhpBp4po02mU0MNMpo0CE0JqT09Ep7SmhhMjZGo0yPUaDQaDRiBoaHA0aMQaNMmEGIDEYmjRo0AaaaAAAAJNFIkETUynkagw1DIA0yPUZDRpoaA0YRpkGIcDRoxBo0yYQYgMRiaNGjQBppoAAAAkREAJoCAEyGhop6NU/QRsiJ6TR6gNAAyNp3IfFE+iB8wWf4sL9xK/9s+3qKxh/7ZVFEGIyI/5JWLFO2ggni0GfE1j/q180JWT7aezyLxgxVPBQ/81h+V+RO+FUUUiqHaG/PSpx6ZY549csBIorBIMWAVifJXMP+vf+z0e1k8/d/d+T5/R91DtgpZIi3R058a/zxZvm1jfVqsN0ZtRDL433LaEfpU+TeeEPqzQb6M/6R93vv+mGNequmf9bMv3tdkqNmKFva+eAhdKRAYgFBWMUZFUFWRYsBVEVFkWCrFGICoiz3fx/qfLPln3Ph9wz0/cPyUftzdGyJroxgFBTFZW1B8d8+Ubm9+S2EfZYPm+b9zPv6iYyrNNmIPw4WwIcmqUzfKiPWG/fTdfAmd6Szg2PCvRlrKbh/xpBK9OWFcnOOduywG22NgNkTQ9+ybtgXLtsBXXF4ijHB1LgG+zwbjLylvTaSwuyPacZyExJIJWsY5ebDngtN4t1E9+GuoLEEn4UETkoHanASaGoPGU4HKYyV0PmmhDVpyQzEPNXGN8w88detyeZyRKPUb7eNnZgZ4fjdjW0rTMOOFlC2zmRVjaaG0DZv0x8vHre+yxL7rRzYliDFTNynrbjodq9POFOWjY2WpNocwV25zHErjEeW6Urzt5rwvQsFxZRVurnFBxmHSHFeSfQ6D04d9dhFkWL2HZwO/K+ADtVVVVXwUFpSOjLjnu9sR3JSRd34zZbJUTYzNajJxQz40/X1wIqdzYyhXHBtMW2u8RWW6nvfd00G/aa8CpG3vt62nuAWHGmM/oHH8TlOCZ3GfrIDpvdi8DmGPT59zm+rTjXTeHHMKqnDQRM5+7K9vMftSPGMFPRo1P6/ssmgE+jA0RBkpKObj/OX47vHy1UlWSdr1q1zxWYK8LIlLIXXpzabobmG7hnl9aSxuxm5+yXrBRtjGmO/mPZE/PmXz10Py53w7Hn1nqfUnHt5PNhhQmN2adu/vQNmWfNpPC+aDyd5SlgYzT77Dt2QPXKIcTM9XjBtpAh0I3yQrYhsSisJujhtKO/LH9/0/dPo//+veBdty2Z6w2Jj2MpMJN/yhkFG6bgJJch1bK0a9d3iBxHq2l2+cY7OUDuw+h7vuz2Jfk3nyfLp9fM/nWJVUI2wrl9fJ46R3Xp7Na3X5FJp4S5fFOZmxQhH0eAnDgCeisTE3lO/nZ/KjPZrkQFSTHOjykkpyRQKXk0zMPVWFYMqJWVQNDLCKTxjlIGQw1j7NsYPJ39pllzLMCybL2C13N6CXET70+qBGQFemJVwFrQJ9YdnfJOhsHFMzUxzMnLVKQvAcWoKypEeTXvpml8DdC/STpCJAjMqqMwziwshWOt7C9x1rQOKVqa7SxyCbm3Ss6RtYcewX35+j0/NTo2qfvXyvXWm1bHyfKhV6W5oVwmP7bSq62MqMUB20vKD6kMkSV/Bdk68n3IVcS0q9S1SyLVQIoJdU5OpFc22rAnRmJWSGiX8TI+5dSsSvSZAdUnw3nkmOxYfhIRH8o7pHJkfCk+921pyxtAc8Rbive92vnfur5J28XfMaBbS62N4NRwzGH7d4F9+hp48Cdue+o83GYwq2zuGtHBn0REcVHqmBA/eIU+G8tk6GvaMN2MZsI57pwZYPwspPn2Upur6CI6L4jM4DY3whRdCxNGNI8SfieY6o3Q6tRhfNJgajl9gckkvYz1MXuT1PVJnMOzg7O9g2FGc7Cvxst/HhtL7u5iWrCGPMh76ypah0sgjq77KGzqizWIZsaRuJR45FBvXewmTM6D5q1LW75Y2GBL1ziiD45tKKNtL2/FEaKeavM8JhDEwoXlEUynpuJhSdCtp5xJ7jM0zPdw06crtMDGbvtwNiZYFhGt46bGHnZS0bacmqaBn5LJRlVPKPSQnm1VdaOp0tp6/D39hYGPs263PdI38u3pnaPJxDeUDOS7LY5mQTJU1d/eDmZcbuDjHGWrC5BkeZ7m3FbDtVf3RNAOCA1+WAEePF25g725szQWAUrlis++tqK0OQEWfQjKLYs19VEeOdZ2EDBYEMrY8dXGPz1WwLIV2IFIbqxbTjVUaRDfGOjydG7DU5Nt7U0BosNNfF8xYxBHKpFctuyZDoMt+GGQuteafLXltJ7uy+GPXL25hvSkZ9fqO0DFImQMd7K9jeABjr2nuA769Xq5oeQbxMlg0xzylG4koDMHlBnGIrpnEOm6aRx2vGK/PKn1L1gYlU+R7Mxtyuv9JFGNtt/AaPAdmu6z7+mn29SCgHH/PHeA8g2Rvq2g+PCm+te09LeFe2c+vvatyt26G9TI9FK559BtYYFBeV0SCCNxTrwVjaocQBFUNeN6XOc6C20tYeFJGPW53xE/bG1uGBFcPWLawOJYC7uKyyWAWG0kCNbXdSKez2v6n8GOIPj74RV8N8z67XGsxRoo5sIiaR8q1KM+D0igfXQQvSxKYGvJXn2ev4f7/864VIOiAhwOVkFrCLbZy3g8vio82Mzbn21xnZKnxYvVZzKriUrzjAN7HuzbkJ8nIIj0jWN7/Jt9zntK4PxVGkkPGRSiZ/kLo4BQJd81U+w0BFFX0KXv0V7yMEfOcm8yjglqcagSLCfLsKk5aVFGOFLySBfgLJM4QPQWU7X7BN3sKPWRQ8vwyVhYGKWSz2ioVypzxvZmi7yndo7d6+Uc1VEMfuanu4fLycn9fofsAkhFu/x6/ZH39PLad11r5gEkIwwqASQjsoPN63/ClyX3ucjBxgJIRxft49vx/X/wCSEbn9Oc8mQG8T40gJIRjYUuASQjf0+8BJCKKzy3AxuHEIg8t0zMRtaVk2acmM7i7XW5tjoLlKN0u1Mms5nhzHLj0P/sdL32Q7GCMMcAaJbRr7GGMdEzihUjGRFw1slliiMTdTgLQQYnISmKBioDSbhtrbQdLbbWNYQKLVlhA2LUEEEHYTRdSpVgVELzAlMNmY1ogsUGKS20obW2yjBRbDGIwRMKIJZbHnkep9X/kBJCOXxAJIRs5gEkInnODd0bP1ke2fnASQjL0nEs+4BJCPG/2d3rASQjHO+nXd9Xqz7GNdIM/VRuZUTVc1tUli8/XJ88SIyAdlLIIwpSkEZ0SToaGBkRkh2BSkkRIFKWERkIF501LOHJIIycKWQRkk2FxpEQDoM8EI2lOHAEQ5KWSIkJLhxpBEgfB73kz9oCSEO7Xv4UCSEbpm0TR1sT/uAkhEaOukPne3+Dr9L9gknv34PhXOwpcNSmmmG6UR2RdRg85RM8xxW6rbxu9iUIyPLG8obJ0CIaRIipqFGCCyzDg4IMQssxRRqBScgaYZjQbl0lOKDhZRttaCLLTOq0EiMgs0KEMWYgyJrEqiMkt4FjXOIs1ludW1qpSLHCTUwJrZWsrQosZbjj6eqHx7h3T4iuswzDLTUZkLlsMI3U0xrFrW1uOvx9dETqltiDL7QhrGw9CMIjJwDQgNhAwgIyHAghRIIIxIE8HXIlQqpUwcBgxCGDCRXGIREHcWzEGML0HB6RqW2ToEssGCDJw4hQbWYNpYDMUeZRrD0NnjzNqcoG5uYec5weDuEzxoixpS2tW04mxUsxQqWyBohDXNRRt4nONW14V5Xct4DkbNTINpYwo4shYYKEQRmQFCyazg0trJQgIRbXnMXWi26yCZHTRDQEFFmoJtwZZYltE5JDYSzSNY2AnK0o610ppjCWR0iJRMJSaFVBYUgnMhdf5R6QEkI8gEkIswdwsCAbkbmIawHaxibFwzPF5dZhuu3w3mXhnFDQwZDpdbaPDSsNi2TTmGOU4ji8q5qipylVMJc5xi5WgmRoKMMqUNCs4rVCirZzhiubQWml0EWwxUaEuSKpQu3LKMKlBrIseSQNoMaTZbAssLY2XlWjaFWtTIygMg0aXUicktyDUN0Y6al/R3o/wbb2NEfpZ9lLoPS91dzIsNHnK0rHie/Ud4tW02kfXef3545xR2P9kR/ZC3DBKl0mZ8sITNOWLu7Q5rtivKJ5B5UNMuroR9tK9Dbj8IDDNNTYR8bezsrKiJtIFHYOUyKchD0UpXTItK4Qppcz3/IZ3GsjejG+AHwwXo06fSAkhHul/Kis1ZkegNC/INjo7+b4mxMdSDVkniyCQzDCcfIq7BXI1A0EVponsdlgtig86O1ppRI2XASrRKMWZfw+YSalOMgE23biCRARBDx2XdzFQ1HWkURdTPIORFSJzjorMU+8PXbV1gOqVrCLtOrEDZ+DMO4Hqw5SAYGVjAZZomN2WyZY/qa5jS72lNRyWGcLjcMhVNQ3N9nynKEA2mlUlsC7Bi6QPEB1UqlXwvjW4lFl/wBJCMKDurOUgXBW+tvRJKoWsk4EUVlMjrY1QFDRAZ2rp9AoLCZUhXEWT7oTBG9AZNDTcaVVSoVzB7QEkI05zH01tflgPSw7Y5SDANwSB9Cr+kM07IwqjFTJ1eE71gg1/MBxvdIMWYN0Ihc8SjC0xnbHbKLH2Pz+lEt5Z7Gz6J0j+cn9XcDPXc0k8+BliRJ0NLi26lrWGCy/z8+6iMjBAVpHAkzRGfaCIjCYMSnQDoN6TsSDw32UphoMNa+fPG1g2HTYhaIrecS0Oipsdy77aAHWz6toZoNmdrt6q7hCSEdmg2NP4d2deUqx+u6NlSnuH3YwF+HK+6oWTQys3N6Kzw91pKj6KSb7eSLyITQGYgNWCPYk8GU3gpJtIbqBRWcUFQ7mBam1/ClgJnMk1QWYUOhg1WrZTB3ZZTJWMrYvtjS7P/sBJCLyrJLSErluBrZQVEpF9OlN9syHACPzJuuR3bqPh6azY7nnKgK17NQMkHUg8PbADQZ5CSOq8N3fzm4EdcwijYrSerrIswOBwW7/Dsw1q5Dh6cywhr3Ge824TIzfXotRiejU3l1dUHL+NbuPNVxjMjlRLUxISUIgjNGuCoFoo5Z4XC4oGqmHB92UC7CsuRDREVJ21GcStpow/b1oLMNt+H3klPARic7fibTZIV1oRbt2uwliq8uLUfIyZULhWoC+26LUmTfQRfIBgWgfCvhaAF1ygw5C05hjK9iaB1I6V0b7pQu0E2DQwYxCYU/XWD9Hd4K73zE/jFjQ/yASQj92fnKp59BaHrFoFAp2+BcZ9a3yvGpCgyLEttFTm+gCaU95VFE77iCfJMG2NCea79g6oMixdmMEqxW7Y7ZJaCGBCPih7/VqAsU/QBJCD8KAIPnQ+MjZOSXSzAVDAfeLjFu4tkCbUqNHEZ7t2Bv9LAZuISIGn5AJIQ5w2VCB+5iICpEEaG/p8igWK1kXpgiCH49GHE3pFbDXgid4CSEOc8A0DJvf3kUQj3lQCOjl55d2KRaIqswCvTaGj4sS84xS303rWCTS/313p2gYpWd6bPQXfJrgwGYQRTIDqZKYEGUAuElqBbDFUVURbKj+EYo8//h6Q4moPuPYuOW/kNoozmnnckS8xxYMaZMw9+HHh6gNmnjesy9F0bE0NptiBjY00PyQVP8YNLUapB1PuObjkw7Xlr6X4K68xFxR9WMkgwHnAbS7f4JdFNMS+lxx1c7srrWpPMZgsgCSEW2tG3ieMXWyMgYu2CgIkHCTtVTpjg9S0uvco6AEkIx8Wto1DUCBqH2wQMgqAkhE0fsRjQIDgWjerQjBpF4fl64xKKzbCiyFTlMkREW10DUWKK2GynZy2TGrVcK9XMBoccXCY5EQt1/Rc0d+OzeQZ6IyrE8TEsNTNmi0lgdOVwMyHRpkG8T1QJXRIXM6gXSQ8I/ABJCM6267ThYzX1OeDhgkaZK7K9sWvCDuVOnZkgZJgMjnY02G7fGPKy7mMTHjkT1L6IsDRHSBkAxX7MEHNcP4XBR5AHxGTbQGzZ8c+D5zEOnf7b56z4wUE9Wj7S3g4rS4wiKMVEVQYiB7V5jlT+iBWJ83x4DM6YfB7yWiEc7P5WQUbTvMGBMiYXmOzruu6s6Do45jhhDoBYecPTOKMD1KQ0ApKRnvcN+0JRpCKoDrtlluaJ9YreYDWlvLk+Iw3DA2rw23YpiNWSNoGwDD/UBJCIFVoYS1GZhKSTJpjjXa0zaGh5H0xxSw733kDqiDrMKQzM0N8vMdJhRgzMK0FQdACSEcoI84KBxUVPXRoZ+dbfdtjmXKFO57WkdFaxq0DYkTMNiKBz2/Qa1+E86nRBi4Kn8O3RjrlV4ZMgTlJToipgoQ1Ey8HIKYLmSKARJFeFgcFs1CRrYj1LOZspRH+w0YgYLn5uuiyfIGAu6kZdXGdG6lwMG10Gt/BKXIkgEvQ0AkpWvl3r9r15JWXcBof39x07tB+7NHf38SrGztIMweKnnVy3UkEDJi0dAwswywE2/H4s2gaBAfa99M7D9YCSESTURiSy615QKWPROIirJPeSj6NDzb2cMFkSHzPHnu0OkrZ5gfAAyZjkgMOwApfesXmMlMuS452TWCsXxBgjLvFoKvNke8uRQ6w8sFoMdc4SS7Hhy0s1BrHz1mlCqZYoPYbbEVEPFMAYAbbkXCL/P7FXEe1Y8rssQ/eoDUJAgLtEENLRpp4+XzuKFW3YIsRHmASQjvy8KSV+4tUXBkw+y+uNbJg4QoLWQehm+63AZ42WTOcWuiqyI9EBJyeWw1uAvgrBOCjC2+mcYDLmXwoAYr0EPwk0IXrHV2Dt+T3/7fpldc/rVGzHA+qhukKMWU583HNYKjVRSpWoZHWIgpwu5eAv0muepci4nSdvQlS9PHnXA0ejOQgqSFCSpMnBCYgn9JR8PVaqe7VnD2VVdbPHd8dp2p3fxPk5/dDq4TxWJ0nB0xXSmMYoxi+XLMk5sgkyhzWbijc1GvlTGRVVfN7Z7GC1Dp8Xt2njXcNnaebxnK0OIjiyeHnC1aFiDBEJ55y+dR7eng0FL6nNziluvgSEdZxqKD5h0eNwV6fRpLfN5VVVHjaUqqtotVALs4crYLPp83Gq3utvRHxsFp1OdNcr1FUfDbn17mpa7wgLeSnq5muaOwOId6BxhhwdTLmY8Fl+4d+FmFqKBlhTggJA2LuCwpU+V+HGmWCRdjCY0A2se3Zw2LLeb4/QOnAC83C2XA2JgiVCAab0IjSI4gQBuMMPCbMDdGGN5hvst5JlK35ZKBPiKrVqp7Cp8GEtS2C4HSQO223ZY70KjzUkImLtbM3DDi77CMEQouawZEXzJYxY4upY0zo44DpvCaC0B3ffOToQ6YznRoEkEVSZiz6SBdM3ZAXWh83XXPOmFt44kJrNM6NwyrszgXovNt2KP1MIenUwfZlmFb8QRckwMWNSgOdrsLbMUaKKbanR7uN/WcOIcWmNBag3UNvDec9KOprJMaRKmIpE5JVBO9lESmi9IgsjoOznRRLEdyHwzNBrNiIQPfEj6UjW1OQApkZYriXq7nQYVDpoAUz1XP7AEkI1KSqn4CI1g/EftB2TouvLrQxe94u06rENf6XHR3qKTMouuW6vbbIAdoWgV6x180cB6+jhd0DMLyzmRj0mcfgxtKFcYLZyu17e3b9gCSEOlNmXmeUdib43ed1yKudKY+kpOTCi9mVanIsF0ULblCX9oCSEVFlcFNTqP2bs7RfFo7QEkIZAdnmO+OPVKlOYV1a1okrWIkIVZoiUDRDXP1wpgzASQj12XXCsNUd3Mihj9dkM2/MzGoRwMGA+vUBJCLS4yTkutg1BQ35M/2NxN/cdl7fJtoq7ZuI+C+Hzb4t/vT9c86lPEgQJyGUD+BdyRThQkMngzx4='))) diff --git a/testClasses.py b/testClasses.py index 39ee87c..caf2147 100644 --- a/testClasses.py +++ b/testClasses.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -61,6 +61,7 @@ class PassAllTestsQuestion(Question): else: grades.assignFullCredit() + class ExtraCreditPassAllTestsQuestion(Question): def __init__(self, questionDict, display): Question.__init__(self, questionDict, display) @@ -92,11 +93,12 @@ class HackedPartialCreditQuestion(Question): for testCase, f in self.testCases: testResult = f(grades) if "points" in testCase.testDict: - if testResult: points += float(testCase.testDict["points"]) + if testResult: + points += float(testCase.testDict["points"]) else: passed = passed and testResult - ## FIXME: Below terrible hack to match q3's logic + # FIXME: Below terrible hack to match q3's logic if int(points) == self.maxPoints and not passed: grades.assignZeroCredit() else: @@ -116,6 +118,7 @@ class Q6PartialCreditQuestion(Question): if False in results: grades.assignZeroCredit() + class PartialCreditQuestion(Question): """Fails any test which returns False, otherwise doesn't effect the grades object. Partial credit tests will add the required points.""" @@ -130,7 +133,6 @@ class PartialCreditQuestion(Question): return False - class NumberPassedQuestion(Question): """Grade is the number of test cases passed.""" @@ -138,9 +140,6 @@ class NumberPassedQuestion(Question): grades.addPoints([f(grades) for _, f in self.testCases].count(True)) - - - # Template modeling a generic test case class TestCase(object): @@ -186,13 +185,13 @@ class TestCase(object): return False # This should really be question level? - # def testPartial(self, grades, points, maxPoints): grades.addPoints(points) extraCredit = max(0, points - maxPoints) regularCredit = points - extraCredit - grades.addMessage('%s: %s (%s of %s points)' % ("PASS" if points >= maxPoints else "FAIL", self.path, regularCredit, maxPoints)) + grades.addMessage('%s: %s (%s of %s points)' % ( + "PASS" if points >= maxPoints else "FAIL", self.path, regularCredit, maxPoints)) if extraCredit > 0: grades.addMessage('EXTRA CREDIT: %s points' % (extraCredit,)) @@ -203,4 +202,3 @@ class TestCase(object): def addMessage(self, message): self.messages.extend(message.split('\n')) - diff --git a/testParser.py b/testParser.py index 17f3485..227a808 100644 --- a/testParser.py +++ b/testParser.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -15,6 +15,7 @@ import re import sys + class TestParser(object): def __init__(self, path): diff --git a/test_cases/CONFIG b/test_cases/CONFIG index dbed66b..e01f27b 100644 --- a/test_cases/CONFIG +++ b/test_cases/CONFIG @@ -1 +1 @@ -order: "q1 q2 q3 q4 q5 q6 q7 q8" \ No newline at end of file +order: "q1 q2 q3 q4 q5" diff --git a/test_cases/q7/CONFIG b/test_cases/extra/CONFIG similarity index 51% rename from test_cases/q7/CONFIG rename to test_cases/extra/CONFIG index ee85183..3a646dd 100644 --- a/test_cases/q7/CONFIG +++ b/test_cases/extra/CONFIG @@ -1,3 +1,2 @@ +max_points: "0" class: "PartialCreditQuestion" -max_points: "4" -depends: "q4" \ No newline at end of file diff --git a/test_cases/extra/grade-agent.test b/test_cases/extra/grade-agent.test new file mode 100644 index 0000000..5da84c6 --- /dev/null +++ b/test_cases/extra/grade-agent.test @@ -0,0 +1,11 @@ +class: "EvalAgentTest" + +agentName: "ContestAgent" +layoutName: "contestClassic" +maxTime: "180" +numGames: "5" + +scoreThresholds: "2500 2900" + +randomSeed: "0" +ghosts: "[DirectionalGhost(1), DirectionalGhost(2), DirectionalGhost(3)]" diff --git a/test_cases/q1/CONFIG b/test_cases/q1/CONFIG index ad7e38a..426bfe9 100644 --- a/test_cases/q1/CONFIG +++ b/test_cases/q1/CONFIG @@ -1,2 +1,2 @@ -max_points: "3" -class: "PassAllTestsQuestion" +max_points: "4" +class: "PartialCreditQuestion" diff --git a/test_cases/q1/grade-agent.solution b/test_cases/q1/grade-agent.solution new file mode 100644 index 0000000..278af4f --- /dev/null +++ b/test_cases/q1/grade-agent.solution @@ -0,0 +1,2 @@ +# This is the solution file for test_cases/q1/grade-agent.test. +# File intentionally blank. diff --git a/test_cases/q1/grade-agent.test b/test_cases/q1/grade-agent.test new file mode 100644 index 0000000..3a70660 --- /dev/null +++ b/test_cases/q1/grade-agent.test @@ -0,0 +1,18 @@ +class: "EvalAgentTest" + +agentName: "ReflexAgent" +layoutName: "openClassic" +maxTime: "120" +numGames: "10" + + +nonTimeoutMinimum: "10" + +scoreThresholds: "500 1000" + +winsMinimum: "1" +winsThresholds: "5 10" + + +randomSeed: "0" +ghosts: "[RandomGhost(1)]" diff --git a/test_cases/q1/graph_backtrack.solution b/test_cases/q1/graph_backtrack.solution deleted file mode 100644 index c52850c..0000000 --- a/test_cases/q1/graph_backtrack.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q1/graph_backtrack.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->C 0:C->G" -expanded_states: "A D C" -rev_solution: "1:A->C 0:C->G" -rev_expanded_states: "A B C" diff --git a/test_cases/q1/graph_backtrack.test b/test_cases/q1/graph_backtrack.test deleted file mode 100644 index 05640a0..0000000 --- a/test_cases/q1/graph_backtrack.test +++ /dev/null @@ -1,32 +0,0 @@ -class: "GraphSearchTest" -algorithm: "depthFirstSearch" - -diagram: """ - B - ^ - | -*A --> C --> G - | - V - D - -A is the start state, G is the goal. Arrows mark -possible state transitions. This tests whether -you extract the sequence of actions correctly even -if your search backtracks. If you fail this, your -nodes are not correctly tracking the sequences of -actions required to reach them. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -A 1:A->C C 2.0 -A 2:A->D D 4.0 -C 0:C->G G 8.0 -""" diff --git a/test_cases/q1/graph_bfs_vs_dfs.solution b/test_cases/q1/graph_bfs_vs_dfs.solution deleted file mode 100644 index 0680f92..0000000 --- a/test_cases/q1/graph_bfs_vs_dfs.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q1/graph_bfs_vs_dfs.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "2:A->D 0:D->G" -expanded_states: "A D" -rev_solution: "0:A->B 0:B->D 0:D->G" -rev_expanded_states: "A B D" diff --git a/test_cases/q1/graph_bfs_vs_dfs.test b/test_cases/q1/graph_bfs_vs_dfs.test deleted file mode 100644 index 155e1fe..0000000 --- a/test_cases/q1/graph_bfs_vs_dfs.test +++ /dev/null @@ -1,30 +0,0 @@ -# Graph where BFS finds the optimal solution but DFS does not -class: "GraphSearchTest" -algorithm: "depthFirstSearch" - -diagram: """ -/-- B -| ^ -| | -| *A -->[G] -| | ^ -| V | -\-->D ----/ - -A is the start state, G is the goal. Arrows -mark possible transitions -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -A 1:A->G G 2.0 -A 2:A->D D 4.0 -B 0:B->D D 8.0 -D 0:D->G G 16.0 -""" diff --git a/test_cases/q1/graph_infinite.solution b/test_cases/q1/graph_infinite.solution deleted file mode 100644 index 82203ee..0000000 --- a/test_cases/q1/graph_infinite.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q1/graph_infinite.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "0:A->B 1:B->C 1:C->G" -expanded_states: "A B C" -rev_solution: "0:A->B 1:B->C 1:C->G" -rev_expanded_states: "A B C" diff --git a/test_cases/q1/graph_infinite.test b/test_cases/q1/graph_infinite.test deleted file mode 100644 index 692ac05..0000000 --- a/test_cases/q1/graph_infinite.test +++ /dev/null @@ -1,30 +0,0 @@ -# Graph where natural action choice leads to an infinite loop -class: "GraphSearchTest" -algorithm: "depthFirstSearch" - -diagram: """ - B <--> C - ^ /| - | / | - V / V -*A<-/ [G] - -A is the start state, G is the goal. Arrows mark -possible state transitions. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -B 0:B->A A 2.0 -B 1:B->C C 4.0 -C 0:C->A A 8.0 -C 1:C->G G 16.0 -C 2:C->B B 32.0 -""" - diff --git a/test_cases/q1/graph_manypaths.solution b/test_cases/q1/graph_manypaths.solution deleted file mode 100644 index 34b5a82..0000000 --- a/test_cases/q1/graph_manypaths.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q1/graph_manypaths.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "2:A->B2 0:B2->C 0:C->D 2:D->E2 0:E2->F 0:F->G" -expanded_states: "A B2 C D E2 F" -rev_solution: "0:A->B1 0:B1->C 0:C->D 0:D->E1 0:E1->F 0:F->G" -rev_expanded_states: "A B1 C D E1 F" diff --git a/test_cases/q1/graph_manypaths.test b/test_cases/q1/graph_manypaths.test deleted file mode 100644 index 953c4eb..0000000 --- a/test_cases/q1/graph_manypaths.test +++ /dev/null @@ -1,39 +0,0 @@ -class: "GraphSearchTest" -algorithm: "depthFirstSearch" - -diagram: """ - B1 E1 - ^ \ ^ \ - / V / V -*A --> C --> D --> F --> [G] - \ ^ \ ^ - V / V / - B2 E2 - -A is the start state, G is the goal. Arrows mark -possible state transitions. This graph has multiple -paths to the goal, where nodes with the same state -are added to the fringe multiple times before they -are expanded. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B1 B1 1.0 -A 1:A->C C 2.0 -A 2:A->B2 B2 4.0 -B1 0:B1->C C 8.0 -B2 0:B2->C C 16.0 -C 0:C->D D 32.0 -D 0:D->E1 E1 64.0 -D 1:D->F F 128.0 -D 2:D->E2 E2 256.0 -E1 0:E1->F F 512.0 -E2 0:E2->F F 1024.0 -F 0:F->G G 2048.0 -""" diff --git a/test_cases/q1/pacman_1.solution b/test_cases/q1/pacman_1.solution deleted file mode 100644 index 82a670c..0000000 --- a/test_cases/q1/pacman_1.solution +++ /dev/null @@ -1,40 +0,0 @@ -# This is the solution file for test_cases/q1/pacman_1.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -# Number of nodes expanded must be with a factor of 1.0 of the numbers below. -solution: """ -West West West West West West West West West West West West West West -West West West West West West West West West West West West West West -West West West West West South South South South South South South -South South East East East North North North North North North North -East East South South South South South South East East North North -North North North North East East South South South South East East -North North East East East East East East East East South South South -East East East East East East East South South South South South South -South West West West West West West West West West West West West West -West West West West South West West West West West West West West West -""" -expanded_nodes: "146" -rev_solution: """ -South South West West West West South South East East East East South -South West West West West South South East East East East South South -West West West West South South South East North East East East South -South South West West West West West West West North North North North -North North North North West West West West West West West North North -North East East East East South East East East North North North West -West North North West West West West West West West West West West -West West West West West West West West West West West West West West -South South South South South South South South South East East East -North North North North North North North East East South South South -South South South East East North North North North North North East -East South South South South East East North North North North East -East East East East South South West West West South South East East -East South South West West West West West West South South West West -West West West South West West West West West South South East East -East East East East East North East East East East East North North -East East East East East East North East East East East East South -South West West West South West West West West West West South South -West West West West West South West West West West West West West West -West -""" -rev_expanded_nodes: "269" diff --git a/test_cases/q1/pacman_1.test b/test_cases/q1/pacman_1.test deleted file mode 100644 index 6ae5412..0000000 --- a/test_cases/q1/pacman_1.test +++ /dev/null @@ -1,27 +0,0 @@ -# This is a basic depth first search test -class: "PacmanSearchTest" -algorithm: "depthFirstSearch" - -# The following specifies the layout to be used -layoutName: "mediumMaze" -layout: """ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% % -% %% % % %%%%%%% %% % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % %% %% % -% %% % % % % % %%%% %%% %%%%%% % -% % % % % % %% %%%%%%%% % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% % -% %%%%%% %%%%%%% %% %%%%%% % -%%%%%% % %%%% %% % % -% %%%%%% %%%%% % %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%%%% %%%%%%%%%%% %% %% % -%%%%%%%%%% %%%%%% % -%. %%%%%%%%%%%%%%%% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -""" - diff --git a/test_cases/q2/0-eval-function-lose-states-1.solution b/test_cases/q2/0-eval-function-lose-states-1.solution new file mode 100644 index 0000000..d0b6eed --- /dev/null +++ b/test_cases/q2/0-eval-function-lose-states-1.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/0-eval-function-lose-states-1.test. +action: "Left" +generated: "lose1 lose2 root" diff --git a/test_cases/q2/0-eval-function-lose-states-1.test b/test_cases/q2/0-eval-function-lose-states-1.test new file mode 100644 index 0000000..791ea43 --- /dev/null +++ b/test_cases/q2/0-eval-function-lose-states-1.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + root + / \ + lose1 lose2 + 1 0 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on losing states. +""" +num_agents: "2" + +start_state: "root" +win_states: "" +lose_states: "lose1 lose2" + +successors: """ +root Left lose1 +root Right lose2 +""" + +evaluation: """ +lose1 1.0 +lose2 0.0 +""" + diff --git a/test_cases/q2/0-eval-function-lose-states-2.solution b/test_cases/q2/0-eval-function-lose-states-2.solution new file mode 100644 index 0000000..df68452 --- /dev/null +++ b/test_cases/q2/0-eval-function-lose-states-2.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/0-eval-function-lose-states-2.test. +action: "Right" +generated: "lose1 lose2 root" diff --git a/test_cases/q2/0-eval-function-lose-states-2.test b/test_cases/q2/0-eval-function-lose-states-2.test new file mode 100644 index 0000000..0d4c149 --- /dev/null +++ b/test_cases/q2/0-eval-function-lose-states-2.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + root + / \ + lose1 lose2 + 0 1 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on losing states. +""" +num_agents: "2" + +start_state: "root" +win_states: "" +lose_states: "lose1 lose2" + +successors: """ +root Left lose1 +root Right lose2 +""" + +evaluation: """ +lose1 0.0 +lose2 1.0 +""" + diff --git a/test_cases/q2/0-eval-function-win-states-1.solution b/test_cases/q2/0-eval-function-win-states-1.solution new file mode 100644 index 0000000..0254142 --- /dev/null +++ b/test_cases/q2/0-eval-function-win-states-1.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/0-eval-function-win-states-1.test. +action: "Left" +generated: "root win1 win2" diff --git a/test_cases/q2/0-eval-function-win-states-1.test b/test_cases/q2/0-eval-function-win-states-1.test new file mode 100644 index 0000000..eab0af1 --- /dev/null +++ b/test_cases/q2/0-eval-function-win-states-1.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + root + / \ + win1 win2 + 1 0 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on winning states. +""" +num_agents: "2" + +start_state: "root" +win_states: "win1 win2" +lose_states: "" + +successors: """ +root Left win1 +root Right win2 +""" + +evaluation: """ +win1 1.0 +win2 0.0 +""" + diff --git a/test_cases/q2/0-eval-function-win-states-2.solution b/test_cases/q2/0-eval-function-win-states-2.solution new file mode 100644 index 0000000..f21c04a --- /dev/null +++ b/test_cases/q2/0-eval-function-win-states-2.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/0-eval-function-win-states-2.test. +action: "Right" +generated: "root win1 win2" diff --git a/test_cases/q2/0-eval-function-win-states-2.test b/test_cases/q2/0-eval-function-win-states-2.test new file mode 100644 index 0000000..77d1ff0 --- /dev/null +++ b/test_cases/q2/0-eval-function-win-states-2.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + root + / \ + win1 win2 + 0 1 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on winning states. +""" +num_agents: "2" + +start_state: "root" +win_states: "win1 win2" +lose_states: "" + +successors: """ +root Left win1 +root Right win2 +""" + +evaluation: """ +win1 0.0 +win2 1.0 +""" + diff --git a/test_cases/q2/0-lecture-6-tree.solution b/test_cases/q2/0-lecture-6-tree.solution new file mode 100644 index 0000000..3c6a74d --- /dev/null +++ b/test_cases/q2/0-lecture-6-tree.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/0-lecture-6-tree.test. +action: "Center" +generated: "A B C D E F G H I max min1 min2 min3" diff --git a/test_cases/q2/0-lecture-6-tree.test b/test_cases/q2/0-lecture-6-tree.test new file mode 100644 index 0000000..debf815 --- /dev/null +++ b/test_cases/q2/0-lecture-6-tree.test @@ -0,0 +1,50 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +# Tree from lecture 6 slides +diagram: """ + max + /-/ | \--\ + / | \ + / | \ + min1 min2 min3 + /|\ /|\ /|\ + / | \ / | \ / | \ +A B C D E F G H I +3 12 8 5 4 6 14 1 11 +""" + +num_agents: "2" + +start_state: "max" +win_states: "A B C D E F G H I" +lose_states: "" + +successors: """ +max Left min1 +max Center min2 +max Right min3 +min1 Left A +min1 Center B +min1 Right C +min2 Left D +min2 Center E +min2 Right F +min3 Left G +min3 Center H +min3 Right I +""" + + +evaluation: """ +A 3.0 +B 12.0 +C 8.0 +D 5.0 +E 4.0 +F 6.0 +G 14.0 +H 1.0 +I 11.0 +""" diff --git a/test_cases/q2/0-small-tree.solution b/test_cases/q2/0-small-tree.solution new file mode 100644 index 0000000..f381f9a --- /dev/null +++ b/test_cases/q2/0-small-tree.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/0-small-tree.test. +action: "pacLeft" +generated: "A B C D deeper minLeft minRight root" diff --git a/test_cases/q2/0-small-tree.test b/test_cases/q2/0-small-tree.test new file mode 100644 index 0000000..5eaa65c --- /dev/null +++ b/test_cases/q2/0-small-tree.test @@ -0,0 +1,36 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + root + / \ + minLeft minRight + / \ / \ + A B C deeper + 4 3 2 | + D + 1000 +""" +num_agents: "2" + +start_state: "root" +win_states: "A C" +lose_states: "B D" + +successors: """ +root pacLeft minLeft +root pacRight minRight +minLeft gLeft A +minLeft gRight B +minRight gLeft C +minRight gRight deeper +deeper pacLeft D +""" + +evaluation: """ +A 4.0 +B 3.0 +C 2.0 +D 1000.0 +""" diff --git a/test_cases/q2/1-1-minmax.solution b/test_cases/q2/1-1-minmax.solution new file mode 100644 index 0000000..3ac7510 --- /dev/null +++ b/test_cases/q2/1-1-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/1-1-minmax.test. +action: "Left" +generated: "a b1 b2 c1 c2 cx d1 d2 d3 d4 dx" diff --git a/test_cases/q2/1-1-minmax.test b/test_cases/q2/1-1-minmax.test new file mode 100644 index 0000000..addd65b --- /dev/null +++ b/test_cases/q2/1-1-minmax.test @@ -0,0 +1,47 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | + c1 c2 cx + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -3.01 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -3.01 +""" diff --git a/test_cases/q2/1-2-minmax.solution b/test_cases/q2/1-2-minmax.solution new file mode 100644 index 0000000..e40e3de --- /dev/null +++ b/test_cases/q2/1-2-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/1-2-minmax.test. +action: "Right" +generated: "a b1 b2 c1 c2 cx d1 d2 d3 d4 dx" diff --git a/test_cases/q2/1-2-minmax.test b/test_cases/q2/1-2-minmax.test new file mode 100644 index 0000000..44e0a77 --- /dev/null +++ b/test_cases/q2/1-2-minmax.test @@ -0,0 +1,47 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | + c1 c2 cx + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -2.99 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -2.99 +""" diff --git a/test_cases/q2/1-3-minmax.solution b/test_cases/q2/1-3-minmax.solution new file mode 100644 index 0000000..513961c --- /dev/null +++ b/test_cases/q2/1-3-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/1-3-minmax.test. +action: "Left" +generated: "a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q2/1-3-minmax.test b/test_cases/q2/1-3-minmax.test new file mode 100644 index 0000000..5f4b12d --- /dev/null +++ b/test_cases/q2/1-3-minmax.test @@ -0,0 +1,47 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + cx c3 c4 + | / \ / \ + dx d5 d6 d7 d8 + 4.01 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b2 is 4. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 4.01 +""" diff --git a/test_cases/q2/1-4-minmax.solution b/test_cases/q2/1-4-minmax.solution new file mode 100644 index 0000000..1ae4c0f --- /dev/null +++ b/test_cases/q2/1-4-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/1-4-minmax.test. +action: "Right" +generated: "a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q2/1-4-minmax.test b/test_cases/q2/1-4-minmax.test new file mode 100644 index 0000000..445fe0f --- /dev/null +++ b/test_cases/q2/1-4-minmax.test @@ -0,0 +1,47 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + cx c3 c4 + | / \ / \ + dx d5 d6 d7 d8 + 3.99 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b2 is 4. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 3.99 +""" diff --git a/test_cases/q2/1-5-minmax.solution b/test_cases/q2/1-5-minmax.solution new file mode 100644 index 0000000..0553ca7 --- /dev/null +++ b/test_cases/q2/1-5-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/1-5-minmax.test. +action: "Right" +generated: "A B C D E F G H Z a b1 b2 c1 c2 cx d1 d2 d3 d4 dx" diff --git a/test_cases/q2/1-5-minmax.test b/test_cases/q2/1-5-minmax.test new file mode 100644 index 0000000..5ce2ba9 --- /dev/null +++ b/test_cases/q2/1-5-minmax.test @@ -0,0 +1,75 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | + c1 c2 cx + / \ / \ | + d1 d2 d3 d4 dx + / \ / \ / \ / \ | + A B C D E F G H Z +-3 13 5 9 10 3 -6 8 3.01 + +a - max +b - min +c - max +d - min + +Note the minimax value of b1 is 3. +""" +num_agents: "2" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P Z" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +dx Down Z +""" + +evaluation: """ +A -3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 3.0 +G -6.0 +H 8.0 +Z 3.01 +""" diff --git a/test_cases/q2/1-6-minmax.solution b/test_cases/q2/1-6-minmax.solution new file mode 100644 index 0000000..f25e068 --- /dev/null +++ b/test_cases/q2/1-6-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/1-6-minmax.test. +action: "Left" +generated: "A B C D E F G H Z a b1 b2 c1 c2 cx d1 d2 d3 d4 dx" diff --git a/test_cases/q2/1-6-minmax.test b/test_cases/q2/1-6-minmax.test new file mode 100644 index 0000000..44b166f --- /dev/null +++ b/test_cases/q2/1-6-minmax.test @@ -0,0 +1,75 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | + c1 c2 cx + / \ / \ | + d1 d2 d3 d4 dx + / \ / \ / \ / \ | + A B C D E F G H Z +-3 13 5 9 10 3 -6 8 2.99 + +a - max +b - min +c - max +d - min + +Note the minimax value of b1 is 3. +""" +num_agents: "2" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P Z" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +dx Down Z +""" + +evaluation: """ +A -3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 3.0 +G -6.0 +H 8.0 +Z 2.99 +""" diff --git a/test_cases/q2/1-7-minmax.solution b/test_cases/q2/1-7-minmax.solution new file mode 100644 index 0000000..fd801a8 --- /dev/null +++ b/test_cases/q2/1-7-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/1-7-minmax.test. +action: "Left" +generated: "I J K L M N O P Z a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q2/1-7-minmax.test b/test_cases/q2/1-7-minmax.test new file mode 100644 index 0000000..534cb39 --- /dev/null +++ b/test_cases/q2/1-7-minmax.test @@ -0,0 +1,75 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + cx c3 c4 + | / \ / \ + dx d5 d6 d7 d8 + | / \ / \ / \ / \ + Z I J K L M N O P + -1.99 -1 -9 4 7 2 5 -3 -2 + +a - max +b - min +c - min +d - max + +Note that the minimax value of b2 is -2 +""" +num_agents: "3" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P Z" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +dx Down Z +""" + +evaluation: """ +I -1.0 +J -9.0 +K 4.0 +L 7.0 +M 2.0 +N 5.0 +O -3.0 +P -2.0 +Z -1.99 +""" diff --git a/test_cases/q2/1-8-minmax.solution b/test_cases/q2/1-8-minmax.solution new file mode 100644 index 0000000..80c7ebe --- /dev/null +++ b/test_cases/q2/1-8-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/1-8-minmax.test. +action: "Right" +generated: "I J K L M N O P Z a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q2/1-8-minmax.test b/test_cases/q2/1-8-minmax.test new file mode 100644 index 0000000..7d3ead9 --- /dev/null +++ b/test_cases/q2/1-8-minmax.test @@ -0,0 +1,75 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + cx c3 c4 + | / \ / \ + dx d5 d6 d7 d8 + | / \ / \ / \ / \ + Z I J K L M N O P + -2.01 -1 -9 4 7 2 5 -3 -2 + +a - max +b - min +c - min +d - max + +Note that the minimax value of b2 is -2.01 +""" +num_agents: "3" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P Z" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +dx Down Z +""" + +evaluation: """ +I -1.0 +J -9.0 +K 4.0 +L 7.0 +M 2.0 +N 5.0 +O -3.0 +P -2.0 +Z -2.01 +""" diff --git a/test_cases/q2/2-1a-vary-depth.solution b/test_cases/q2/2-1a-vary-depth.solution new file mode 100644 index 0000000..9dd1708 --- /dev/null +++ b/test_cases/q2/2-1a-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-1a-vary-depth.test. +action: "Left" +generated: "a b1 b2 c1 c2 cx" diff --git a/test_cases/q2/2-1a-vary-depth.test b/test_cases/q2/2-1a-vary-depth.test new file mode 100644 index 0000000..321b1ce --- /dev/null +++ b/test_cases/q2/2-1a-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "1" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | +-4 c1 c2 9 cx -4.01 + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -4.01 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3, but the depth=1 limited value is -4. +The values next to c1, c2, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +c1 -4.0 +c2 9.0 +cx -4.01 +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -4.01 +""" diff --git a/test_cases/q2/2-1b-vary-depth.solution b/test_cases/q2/2-1b-vary-depth.solution new file mode 100644 index 0000000..a824e44 --- /dev/null +++ b/test_cases/q2/2-1b-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-1b-vary-depth.test. +action: "Left" +generated: "a b1 b2 c1 c2 cx d1 d2 d3 d4 dx" diff --git a/test_cases/q2/2-1b-vary-depth.test b/test_cases/q2/2-1b-vary-depth.test new file mode 100644 index 0000000..d0d656d --- /dev/null +++ b/test_cases/q2/2-1b-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | +-4 c1 c2 9 cx -4.01 + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -4.01 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3, but the depth=1 limited value is -4. +The values next to c1, c2, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +c1 -4.0 +c2 9.0 +cx -4.01 +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -4.01 +""" diff --git a/test_cases/q2/2-2a-vary-depth.solution b/test_cases/q2/2-2a-vary-depth.solution new file mode 100644 index 0000000..b4b0e98 --- /dev/null +++ b/test_cases/q2/2-2a-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-2a-vary-depth.test. +action: "Right" +generated: "a b1 b2 c1 c2 cx" diff --git a/test_cases/q2/2-2a-vary-depth.test b/test_cases/q2/2-2a-vary-depth.test new file mode 100644 index 0000000..204877f --- /dev/null +++ b/test_cases/q2/2-2a-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "1" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | +-4 c1 c2 9 cx -3.99 + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -3.99 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3, but the depth=1 limited value is -4. +The values next to c1, c2, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +c1 -4.0 +c2 9.0 +cx -3.99 +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -3.99 +""" diff --git a/test_cases/q2/2-2b-vary-depth.solution b/test_cases/q2/2-2b-vary-depth.solution new file mode 100644 index 0000000..94e2089 --- /dev/null +++ b/test_cases/q2/2-2b-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-2b-vary-depth.test. +action: "Left" +generated: "a b1 b2 c1 c2 cx d1 d2 d3 d4 dx" diff --git a/test_cases/q2/2-2b-vary-depth.test b/test_cases/q2/2-2b-vary-depth.test new file mode 100644 index 0000000..1e4ef41 --- /dev/null +++ b/test_cases/q2/2-2b-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | +-4 c1 c2 9 cx -3.99 + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -3.99 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3, but the depth=1 limited value is -4. +The values next to c1, c2, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +c1 -4.0 +c2 9.0 +cx -3.99 +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -3.99 +""" diff --git a/test_cases/q2/2-3a-vary-depth.solution b/test_cases/q2/2-3a-vary-depth.solution new file mode 100644 index 0000000..1bab661 --- /dev/null +++ b/test_cases/q2/2-3a-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-3a-vary-depth.test. +action: "Left" +generated: "a b1 b2 c3 c4 cx" diff --git a/test_cases/q2/2-3a-vary-depth.test b/test_cases/q2/2-3a-vary-depth.test new file mode 100644 index 0000000..e083759 --- /dev/null +++ b/test_cases/q2/2-3a-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "1" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + 5.01 cx 8 c3 c4 5 + | / \ / \ + dx d5 d6 d7 d8 + 5.01 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b1 is 4, but the depth=1 limited value is 5. +The values next to c3, c4, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +c3 8.0 +c4 5.0 +cx 5.01 +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 5.01 +""" diff --git a/test_cases/q2/2-3b-vary-depth.solution b/test_cases/q2/2-3b-vary-depth.solution new file mode 100644 index 0000000..fb389ec --- /dev/null +++ b/test_cases/q2/2-3b-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-3b-vary-depth.test. +action: "Left" +generated: "a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q2/2-3b-vary-depth.test b/test_cases/q2/2-3b-vary-depth.test new file mode 100644 index 0000000..cbe88b5 --- /dev/null +++ b/test_cases/q2/2-3b-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + 5.01 cx 8 c3 c4 5 + | / \ / \ + dx d5 d6 d7 d8 + 5.01 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b1 is 4, but the depth=1 limited value is 5. +The values next to c3, c4, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +c3 8.0 +c4 5.0 +cx 5.01 +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 5.01 +""" diff --git a/test_cases/q2/2-4a-vary-depth.solution b/test_cases/q2/2-4a-vary-depth.solution new file mode 100644 index 0000000..815147d --- /dev/null +++ b/test_cases/q2/2-4a-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-4a-vary-depth.test. +action: "Right" +generated: "a b1 b2 c3 c4 cx" diff --git a/test_cases/q2/2-4a-vary-depth.test b/test_cases/q2/2-4a-vary-depth.test new file mode 100644 index 0000000..e519969 --- /dev/null +++ b/test_cases/q2/2-4a-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "1" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + 4.99 cx 8 c3 c4 5 + | / \ / \ + dx d5 d6 d7 d8 + 4.99 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b1 is 4, but the depth=1 limited value is 5. +The values next to c3, c4, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +c3 8.0 +c4 5.0 +cx 4.99 +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 4.99 +""" diff --git a/test_cases/q2/2-4b-vary-depth.solution b/test_cases/q2/2-4b-vary-depth.solution new file mode 100644 index 0000000..3b12519 --- /dev/null +++ b/test_cases/q2/2-4b-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-4b-vary-depth.test. +action: "Left" +generated: "a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q2/2-4b-vary-depth.test b/test_cases/q2/2-4b-vary-depth.test new file mode 100644 index 0000000..a80e82d --- /dev/null +++ b/test_cases/q2/2-4b-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + 4.99 cx 8 c3 c4 5 + | / \ / \ + dx d5 d6 d7 d8 + 4.99 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b1 is 4, but the depth=1 limited value is 5. +The values next to c3, c4, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +c3 8.0 +c4 5.0 +cx 4.99 +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 4.99 +""" diff --git a/test_cases/q2/2-one-ghost-3level.solution b/test_cases/q2/2-one-ghost-3level.solution new file mode 100644 index 0000000..f7b10fb --- /dev/null +++ b/test_cases/q2/2-one-ghost-3level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/2-one-ghost-3level.test. +action: "Left" +generated: "a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7 d8" diff --git a/test_cases/q2/2-one-ghost-3level.test b/test_cases/q2/2-one-ghost-3level.test new file mode 100644 index 0000000..90d4685 --- /dev/null +++ b/test_cases/q2/2-one-ghost-3level.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 + 3 9 10 6 4 7 0 5 + +a - max +b - min +c - max +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +""" + +evaluation: """ +d1 3.0 +d2 9.0 +d3 10.0 +d4 6.0 +d5 4.0 +d6 7.0 +d7 0.0 +d8 5.0 +""" diff --git a/test_cases/q2/3-one-ghost-4level.solution b/test_cases/q2/3-one-ghost-4level.solution new file mode 100644 index 0000000..5fcb2c5 --- /dev/null +++ b/test_cases/q2/3-one-ghost-4level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/3-one-ghost-4level.test. +action: "Left" +generated: "A B C D E F G H I J K L M N O P a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7 d8" diff --git a/test_cases/q2/3-one-ghost-4level.test b/test_cases/q2/3-one-ghost-4level.test new file mode 100644 index 0000000..6868528 --- /dev/null +++ b/test_cases/q2/3-one-ghost-4level.test @@ -0,0 +1,79 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 +/ \ / \ / \ / \ / \ / \ / \ / \ +A B C D E F G H I J K L M N O P +3 13 5 9 10 11 6 8 1 0 4 7 12 15 2 14 + +a - max +b - min +c - max +d - min +""" +num_agents: "2" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +""" + +evaluation: """ +A 3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 11.0 +G 6.0 +H 8.0 +I 1.0 +J 0.0 +K 4.0 +L 7.0 +M 12.0 +N 15.0 +O 2.0 +P 14.0 +""" diff --git a/test_cases/q2/4-two-ghosts-3level.solution b/test_cases/q2/4-two-ghosts-3level.solution new file mode 100644 index 0000000..36a2326 --- /dev/null +++ b/test_cases/q2/4-two-ghosts-3level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/4-two-ghosts-3level.test. +action: "Left" +generated: "a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7 d8" diff --git a/test_cases/q2/4-two-ghosts-3level.test b/test_cases/q2/4-two-ghosts-3level.test new file mode 100644 index 0000000..a2c5bad --- /dev/null +++ b/test_cases/q2/4-two-ghosts-3level.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 + 3 9 10 6 4 7 0 5 + +a - max +b - min +c - min +""" +num_agents: "3" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +""" + +evaluation: """ +d1 3.0 +d2 9.0 +d3 10.0 +d4 6.0 +d5 4.0 +d6 7.0 +d7 0.0 +d8 5.0 +""" diff --git a/test_cases/q2/5-two-ghosts-4level.solution b/test_cases/q2/5-two-ghosts-4level.solution new file mode 100644 index 0000000..3164ec0 --- /dev/null +++ b/test_cases/q2/5-two-ghosts-4level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/5-two-ghosts-4level.test. +action: "Left" +generated: "A B C D E F G H I J K L M N O P a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7 d8" diff --git a/test_cases/q2/5-two-ghosts-4level.test b/test_cases/q2/5-two-ghosts-4level.test new file mode 100644 index 0000000..9eeb228 --- /dev/null +++ b/test_cases/q2/5-two-ghosts-4level.test @@ -0,0 +1,79 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 +/ \ / \ / \ / \ / \ / \ / \ / \ +A B C D E F G H I J K L M N O P +3 13 5 9 10 11 6 8 1 0 4 7 12 15 2 14 + +a - max +b - min +c - min +d - max +""" +num_agents: "3" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +""" + +evaluation: """ +A 3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 11.0 +G 6.0 +H 8.0 +I 1.0 +J 0.0 +K 4.0 +L 7.0 +M 12.0 +N 15.0 +O 2.0 +P 14.0 +""" diff --git a/test_cases/q2/6-tied-root.solution b/test_cases/q2/6-tied-root.solution new file mode 100644 index 0000000..61918b0 --- /dev/null +++ b/test_cases/q2/6-tied-root.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/6-tied-root.test. +action: "Left" +generated: "A B C max min1 min2" diff --git a/test_cases/q2/6-tied-root.test b/test_cases/q2/6-tied-root.test new file mode 100644 index 0000000..98cc012 --- /dev/null +++ b/test_cases/q2/6-tied-root.test @@ -0,0 +1,31 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + max + / \ +min1 min2 + | / \ + A B C +10 10 0 +""" +num_agents: "2" + +start_state: "max" +win_states: "A B" +lose_states: "C" + +successors: """ +max Left min1 +max Right min2 +min1 Down A +min2 Left B +min2 Right C +""" + +evaluation: """ +A 10.0 +B 10.0 +C 0.0 +""" diff --git a/test_cases/q2/7-1a-check-depth-one-ghost.solution b/test_cases/q2/7-1a-check-depth-one-ghost.solution new file mode 100644 index 0000000..0b7f01b --- /dev/null +++ b/test_cases/q2/7-1a-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/7-1a-check-depth-one-ghost.test. +action: "Left" +generated: "a b1 b2 b3 c1 c2 c3" diff --git a/test_cases/q2/7-1a-check-depth-one-ghost.test b/test_cases/q2/7-1a-check-depth-one-ghost.test new file mode 100644 index 0000000..077effc --- /dev/null +++ b/test_cases/q2/7-1a-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "1" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 1, the evaluation function is called at level c, +so Left should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q2/7-1b-check-depth-one-ghost.solution b/test_cases/q2/7-1b-check-depth-one-ghost.solution new file mode 100644 index 0000000..e7e3c6f --- /dev/null +++ b/test_cases/q2/7-1b-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/7-1b-check-depth-one-ghost.test. +action: "Center" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3" diff --git a/test_cases/q2/7-1b-check-depth-one-ghost.test b/test_cases/q2/7-1b-check-depth-one-ghost.test new file mode 100644 index 0000000..53cefd4 --- /dev/null +++ b/test_cases/q2/7-1b-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 2, the evaluation function is called at level e, +so Center should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q2/7-1c-check-depth-one-ghost.solution b/test_cases/q2/7-1c-check-depth-one-ghost.solution new file mode 100644 index 0000000..188854d --- /dev/null +++ b/test_cases/q2/7-1c-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/7-1c-check-depth-one-ghost.test. +action: "Right" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3" diff --git a/test_cases/q2/7-1c-check-depth-one-ghost.test b/test_cases/q2/7-1c-check-depth-one-ghost.test new file mode 100644 index 0000000..51a5c9a --- /dev/null +++ b/test_cases/q2/7-1c-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 3, the evaluation function is called at level g, +so Right should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q2/7-2a-check-depth-two-ghosts.solution b/test_cases/q2/7-2a-check-depth-two-ghosts.solution new file mode 100644 index 0000000..649825a --- /dev/null +++ b/test_cases/q2/7-2a-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/7-2a-check-depth-two-ghosts.test. +action: "Left" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3" diff --git a/test_cases/q2/7-2a-check-depth-two-ghosts.test b/test_cases/q2/7-2a-check-depth-two-ghosts.test new file mode 100644 index 0000000..c8fc743 --- /dev/null +++ b/test_cases/q2/7-2a-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "1" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 1, the evaluation function is called at level d, +so Left should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q2/7-2b-check-depth-two-ghosts.solution b/test_cases/q2/7-2b-check-depth-two-ghosts.solution new file mode 100644 index 0000000..440eaf8 --- /dev/null +++ b/test_cases/q2/7-2b-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/7-2b-check-depth-two-ghosts.test. +action: "Center" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3" diff --git a/test_cases/q2/7-2b-check-depth-two-ghosts.test b/test_cases/q2/7-2b-check-depth-two-ghosts.test new file mode 100644 index 0000000..2dff6d0 --- /dev/null +++ b/test_cases/q2/7-2b-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "2" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 2, the evaluation function is called at level g, +so Center should be returned. If your algorithm is returning +a different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q2/7-2c-check-depth-two-ghosts.solution b/test_cases/q2/7-2c-check-depth-two-ghosts.solution new file mode 100644 index 0000000..fb146d8 --- /dev/null +++ b/test_cases/q2/7-2c-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q2/7-2c-check-depth-two-ghosts.test. +action: "Right" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3 h1 h2 h3 i1 i2 i3 j1 j2 j3" diff --git a/test_cases/q2/7-2c-check-depth-two-ghosts.test b/test_cases/q2/7-2c-check-depth-two-ghosts.test new file mode 100644 index 0000000..2ef9f15 --- /dev/null +++ b/test_cases/q2/7-2c-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "MinimaxAgent" +depth: "3" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 3, the evaluation function is called at level j, +so Right should be returned. If your algorithm is returning +a different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q2/8-pacman-game.solution b/test_cases/q2/8-pacman-game.solution new file mode 100644 index 0000000..4ee19d8 --- /dev/null +++ b/test_cases/q2/8-pacman-game.solution @@ -0,0 +1,444 @@ +optimalActions: """ +[[["West", "East"], 59], [["West", "East"], 35]] +[[["West"], 190], [["West"], 127]] +[[["West"], 190], [["West"], 135]] +[[["West", "North"], 120], [["West", "North"], 82]] +[[["West"], 77], [["West"], 57]] +[[["West", "North"], 143], [["West", "North"], 97]] +[[["West"], 155], [["West"], 110]] +[[["West"], 40], [["West"], 27]] +[[["North"], 64], [["North"], 43]] +[[["North"], 85], [["North"], 57]] +[[["North"], 106], [["North"], 71]] +[[["North"], 97], [["North"], 65]] +[[["Stop", "East"], 154], [["East"], 103]] +[[["East"], 156], [["East"], 101]] +[[["West"], 30], [["West"], 17]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["North"], 29], [["North"], 18]] +[[["North"], 50], [["North"], 31]] +[[["West"], 55], [["West"], 36]] +[[["East"], 29], [["East"], 16]] +[[["North"], 89], [["North"], 61]] +[[["East", "North"], 161], [["East", "North"], 121]] +[[["East", "North"], 221], [["East", "North"], 166]] +[[["North", "South"], 105], [["North", "South"], 77]] +[[["West"], 69], [["West"], 51]] +[[["West"], 94], [["West"], 69]] +[[["West", "Stop"], 57], [["West"], 42]] +[[["West", "Stop", "East"], 69], [["West", "East"], 49]] +[[["West", "Stop", "East"], 61], [["West", "East"], 41]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 28], [["East", "South"], 19]] +[[["Stop", "East", "South"], 34], [["East", "South"], 23]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 85], [["East", "South"], 57]] +[[["Stop", "East", "South"], 64], [["East", "South"], 43]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 85], [["East", "South"], 57]] +[[["Stop", "East", "South"], 102], [["East", "South"], 67]] +[[["Stop", "South"], 23], [["South"], 13]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East", "North"], 29], [["East", "North"], 18]] +[[["East"], 38], [["East"], 22]] +[[["North"], 29], [["North"], 18]] +[[["North"], 38], [["North"], 22]] +[[["East"], 33], [["East"], 22]] +[[["East"], 37], [["East"], 18]] +[[["East"], 18], [["East"], 12]] +[[["East"], 37], [["East"], 26]] +[[["East"], 69], [["East"], 41]] +[[["East"], 56], [["East"], 26]] +[[["East"], 44], [["East"], 29]] +[[["North", "South"], 83], [["North", "South"], 52]] +[[["East", "North"], 121], [["East", "North"], 74]] +[[["East", "North"], 97], [["East", "North"], 73]] +[[["North", "South"], 173], [["North", "South"], 130]] +[[["West", "East"], 90], [["West", "East"], 66]] +[[["West", "Stop", "East"], 161], [["West", "East"], 118]] +[[["Stop", "East", "South"], 58], [["East", "South"], 43]] +[[["Stop", "East"], 120], [["South"], 85]] +[[["East"], 78], [["East"], 45]] +[[["West"], 77], [["West"], 42]] +[[["South"], 83], [["South"], 48]] +[[["South"], 49], [["South"], 37]] +[[["South"], 185], [["South"], 104]] +[[["South"], 68], [["South"], 41]] +[[["West"], 30], [["West"], 18]] +[[["West"], 56], [["West"], 29]] +[[["West"], 14], [["West"], 10]] +[[["West"], 20], [["West"], 14]] +[[["West"], 13], [["West"], 9]] +[[["West"], 13], [["West"], 9]] +[[["West"], 16], [["West"], 12]] +[[["West", "North"], 30], [["West", "North"], 20]] +[[["West"], 38], [["West"], 23]] +[[["West", "Stop", "East", "North"], 70], [["West", "East", "North"], 46]] +[[["West", "Stop", "East"], 128], [["West", "East"], 89]] +[[["West", "Stop", "East"], 31], [["West", "East"], 20]] +[[["Stop", "East", "North"], 69], [["East", "North"], 45]] +[[["Stop", "North"], 58], [["North"], 31]] +[[["North"], 34], [["North"], 19]] +[[["North"], 30], [["North"], 17]] +[[["North"], 19], [["North"], 11]] +[[["North"], 34], [["North"], 19]] +[[["East"], 30], [["East"], 17]] +[[["East"], 19], [["East"], 11]] +[[["East"], 44], [["East"], 29]] +[[["East", "South"], 87], [["East", "South"], 60]] +[[["East", "South"], 108], [["East", "South"], 62]] +[[["South"], 120], [["South"], 61]] +[[["North", "South"], 209], [["North", "South"], 132]] +[[["West"], 108], [["West"], 60]] +[[["West", "Stop", "East", "South"], 83], [["West", "East", "South"], 61]] +[[["West", "Stop", "East", "South"], 90], [["West", "East", "South"], 66]] +[[["West", "Stop", "East"], 134], [["West", "East"], 95]] +[[["West", "Stop", "East"], 82], [["West", "East"], 55]] +[[["Stop", "East", "South"], 142], [["East", "South"], 95]] +[[["Stop", "East", "South"], 98], [["East", "South"], 65]] +[[["Stop", "East", "South"], 128], [["East", "South"], 86]] +[[["Stop", "East", "South"], 82], [["East", "South"], 55]] +[[["Stop", "East", "South"], 85], [["East", "South"], 57]] +[[["Stop", "East", "South"], 190], [["East", "South"], 127]] +[[["Stop", "East", "South"], 158], [["East", "South"], 103]] +[[["Stop", "South"], 50], [["South"], 27]] +[[["South"], 30], [["South"], 17]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East", "North"], 29], [["East", "North"], 18]] +[[["East"], 37], [["East"], 22]] +[[["East", "North"], 41], [["East", "North"], 24]] +[[["East"], 59], [["East"], 29]] +[[["East"], 19], [["East"], 11]] +[[["East"], 26], [["East"], 15]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East"], 29], [["East"], 18]] +[[["East"], 37], [["East"], 22]] +[[["East", "North"], 41], [["East", "North"], 24]] +[[["East"], 59], [["East"], 29]] +[[["East"], 19], [["East"], 11]] +[[["North"], 26], [["North"], 15]] +[[["North"], 19], [["North"], 11]] +[[["North"], 30], [["North"], 17]] +[[["North"], 34], [["North"], 19]] +[[["West"], 34], [["West"], 19]] +[[["West"], 25], [["West"], 13]] +[[["West", "Stop", "East"], 7], [["West", "East"], 3]] +""" +altDepthActions: """ +[["West", "East"], ["West", "East"], ["West", "East"], ["West", "East"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["Stop", "North"], ["North"]] +[["East"], ["East"], ["Stop", "East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["West"], ["West"], ["West"], ["West"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["West"], ["West"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"], ["North"], ["North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West", "Stop"], ["West"]] +[["West"], ["West"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"], ["Stop", "South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North", "South"], ["North", "South"], ["South"], ["South"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"], ["North"], ["North"]] +[["West", "East"], ["West", "East"], ["East"], ["East"]] +[["West"], ["West"], ["East"], ["East"]] +[["Stop", "East", "South"], ["East", "South"], ["East"], ["East"]] +[["Stop", "East"], ["East"], ["Stop", "East"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["West"], ["West"], ["West"], ["West"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["West", "East"], ["West", "East"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East", "North"], ["West", "East", "North"], ["West", "Stop", "East", "North"], ["West", "East", "North"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "North"], ["East", "North"], ["Stop", "East", "North"], ["East", "North"]] +[["Stop", "North"], ["North"], ["Stop", "North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "South"], ["East", "South"], ["East", "South"], ["East", "South"]] +[["East", "South"], ["East", "South"], ["East", "South"], ["East", "South"]] +[["South"], ["South"], ["South"], ["South"]] +[["North", "South"], ["North", "South"], ["North", "South"], ["North", "South"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"], ["Stop", "South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +""" +partialPlyBugActions: """ +[["West", "East"], ["West", "East"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["Stop", "East"], ["East"]] +[["West"], ["West"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["West"], ["West"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "Stop"], ["West"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North", "South"], ["North", "South"]] +[["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"]] +[["West", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East"], ["East"]] +[["East"], ["East"]] +[["West"], ["West"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West", "Stop", "East", "North"], ["West", "East", "North"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "North"], ["East", "North"]] +[["Stop", "North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "South"], ["East", "South"]] +[["East", "South"], ["East", "South"]] +[["South"], ["South"]] +[["North", "South"], ["North", "South"]] +[["West"], ["West"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "Stop", "East"], ["West", "East"]] +""" diff --git a/test_cases/q2/8-pacman-game.test b/test_cases/q2/8-pacman-game.test new file mode 100644 index 0000000..be7396d --- /dev/null +++ b/test_cases/q2/8-pacman-game.test @@ -0,0 +1,19 @@ +class: "PacmanGameTreeTest" +alg: "MinimaxAgent" +seed: "0" +depth: "2" +max_points: "4" + +# The following specifies the layout to be used +layoutName: "smallClassic" +layout: """ +%%%%%%%%%%%%%%%%%%%% +%......%G G%......% +%.%%...%% %%...%%.% +%.%o.%........%.o%.% +%.%%.%.%%%%%%.%.%%.% +%........P.........% +%%%%%%%%%%%%%%%%%%%% +""" + + diff --git a/test_cases/q2/CONFIG b/test_cases/q2/CONFIG index ad7e38a..a5adc3f 100644 --- a/test_cases/q2/CONFIG +++ b/test_cases/q2/CONFIG @@ -1,2 +1,2 @@ -max_points: "3" +max_points: "5" class: "PassAllTestsQuestion" diff --git a/test_cases/q2/graph_backtrack.solution b/test_cases/q2/graph_backtrack.solution deleted file mode 100644 index 6c669c2..0000000 --- a/test_cases/q2/graph_backtrack.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q2/graph_backtrack.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->C 0:C->G" -expanded_states: "A B C D" -rev_solution: "1:A->C 0:C->G" -rev_expanded_states: "A D C B" diff --git a/test_cases/q2/graph_backtrack.test b/test_cases/q2/graph_backtrack.test deleted file mode 100644 index 2b35d8b..0000000 --- a/test_cases/q2/graph_backtrack.test +++ /dev/null @@ -1,32 +0,0 @@ -class: "GraphSearchTest" -algorithm: "breadthFirstSearch" - -diagram: """ - B - ^ - | -*A --> C --> G - | - V - D - -A is the start state, G is the goal. Arrows mark -possible state transitions. This tests whether -you extract the sequence of actions correctly even -if your search backtracks. If you fail this, your -nodes are not correctly tracking the sequences of -actions required to reach them. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -A 1:A->C C 2.0 -A 2:A->D D 4.0 -C 0:C->G G 8.0 -""" diff --git a/test_cases/q2/graph_bfs_vs_dfs.solution b/test_cases/q2/graph_bfs_vs_dfs.solution deleted file mode 100644 index 05eecc8..0000000 --- a/test_cases/q2/graph_bfs_vs_dfs.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q2/graph_bfs_vs_dfs.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->G" -expanded_states: "A B" -rev_solution: "1:A->G" -rev_expanded_states: "A D" diff --git a/test_cases/q2/graph_bfs_vs_dfs.test b/test_cases/q2/graph_bfs_vs_dfs.test deleted file mode 100644 index 47b78a6..0000000 --- a/test_cases/q2/graph_bfs_vs_dfs.test +++ /dev/null @@ -1,30 +0,0 @@ -# Graph where BFS finds the optimal solution but DFS does not -class: "GraphSearchTest" -algorithm: "breadthFirstSearch" - -diagram: """ -/-- B -| ^ -| | -| *A -->[G] -| | ^ -| V | -\-->D ----/ - -A is the start state, G is the goal. Arrows -mark possible transitions -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -A 1:A->G G 2.0 -A 2:A->D D 4.0 -B 0:B->D D 8.0 -D 0:D->G G 16.0 -""" diff --git a/test_cases/q2/graph_infinite.solution b/test_cases/q2/graph_infinite.solution deleted file mode 100644 index 17b621c..0000000 --- a/test_cases/q2/graph_infinite.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q2/graph_infinite.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "0:A->B 1:B->C 1:C->G" -expanded_states: "A B C" -rev_solution: "0:A->B 1:B->C 1:C->G" -rev_expanded_states: "A B C" diff --git a/test_cases/q2/graph_infinite.test b/test_cases/q2/graph_infinite.test deleted file mode 100644 index 2cae9ad..0000000 --- a/test_cases/q2/graph_infinite.test +++ /dev/null @@ -1,30 +0,0 @@ -# Graph where natural action choice leads to an infinite loop -class: "GraphSearchTest" -algorithm: "breadthFirstSearch" - -diagram: """ - B <--> C - ^ /| - | / | - V / V -*A<-/ [G] - -A is the start state, G is the goal. Arrows mark -possible state transitions. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -B 0:B->A A 2.0 -B 1:B->C C 4.0 -C 0:C->A A 8.0 -C 1:C->G G 16.0 -C 2:C->B B 32.0 -""" - diff --git a/test_cases/q2/graph_manypaths.solution b/test_cases/q2/graph_manypaths.solution deleted file mode 100644 index 0cea422..0000000 --- a/test_cases/q2/graph_manypaths.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q2/graph_manypaths.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->C 0:C->D 1:D->F 0:F->G" -expanded_states: "A B1 C B2 D E1 F E2" -rev_solution: "1:A->C 0:C->D 1:D->F 0:F->G" -rev_expanded_states: "A B2 C B1 D E2 F E1" diff --git a/test_cases/q2/graph_manypaths.test b/test_cases/q2/graph_manypaths.test deleted file mode 100644 index 7c636ea..0000000 --- a/test_cases/q2/graph_manypaths.test +++ /dev/null @@ -1,39 +0,0 @@ -class: "GraphSearchTest" -algorithm: "breadthFirstSearch" - -diagram: """ - B1 E1 - ^ \ ^ \ - / V / V -*A --> C --> D --> F --> [G] - \ ^ \ ^ - V / V / - B2 E2 - -A is the start state, G is the goal. Arrows mark -possible state transitions. This graph has multiple -paths to the goal, where nodes with the same state -are added to the fringe multiple times before they -are expanded. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B1 B1 1.0 -A 1:A->C C 2.0 -A 2:A->B2 B2 4.0 -B1 0:B1->C C 8.0 -B2 0:B2->C C 16.0 -C 0:C->D D 32.0 -D 0:D->E1 E1 64.0 -D 1:D->F F 128.0 -D 2:D->E2 E2 256.0 -E1 0:E1->F F 512.0 -E2 0:E2->F F 1024.0 -F 0:F->G G 2048.0 -""" diff --git a/test_cases/q2/pacman_1.solution b/test_cases/q2/pacman_1.solution deleted file mode 100644 index 8f6d2bd..0000000 --- a/test_cases/q2/pacman_1.solution +++ /dev/null @@ -1,22 +0,0 @@ -# This is the solution file for test_cases/q2/pacman_1.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -# Number of nodes expanded must be with a factor of 1.0 of the numbers below. -solution: """ -West West West West West West West West West South South East East -South South South West West West North West West West West South South -South East East East East East East East South South South South South -South South West West West West West West West West West West West -West West West West West West South West West West West West West West -West West -""" -expanded_nodes: "269" -rev_solution: """ -West West West West West West West West West South South East East -South South South West West West North West West West West South South -South East East East East East East East South South South South South -South South West West West West West West West West West West West -West West West West West West South West West West West West West West -West West -""" -rev_expanded_nodes: "269" diff --git a/test_cases/q2/pacman_1.test b/test_cases/q2/pacman_1.test deleted file mode 100644 index c913f0c..0000000 --- a/test_cases/q2/pacman_1.test +++ /dev/null @@ -1,27 +0,0 @@ -# This is a basic breadth first search test -class: "PacmanSearchTest" -algorithm: "breadthFirstSearch" - -# The following specifies the layout to be used -layoutName: "mediumMaze" -layout: """ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% % -% %% % % %%%%%%% %% % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % %% %% % -% %% % % % % % %%%% %%% %%%%%% % -% % % % % % %% %%%%%%%% % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% % -% %%%%%% %%%%%%% %% %%%%%% % -%%%%%% % %%%% %% % % -% %%%%%% %%%%% % %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%%%% %%%%%%%%%%% %% %% % -%%%%%%%%%% %%%%%% % -%. %%%%%%%%%%%%%%%% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -""" - diff --git a/test_cases/q3/0-eval-function-lose-states-1.solution b/test_cases/q3/0-eval-function-lose-states-1.solution new file mode 100644 index 0000000..7d48add --- /dev/null +++ b/test_cases/q3/0-eval-function-lose-states-1.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/0-eval-function-lose-states-1.test. +action: "Left" +generated: "lose1 lose2 root" diff --git a/test_cases/q3/0-eval-function-lose-states-1.test b/test_cases/q3/0-eval-function-lose-states-1.test new file mode 100644 index 0000000..36dc214 --- /dev/null +++ b/test_cases/q3/0-eval-function-lose-states-1.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + root + / \ + lose1 lose2 + 1 0 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on losing states. +""" +num_agents: "2" + +start_state: "root" +win_states: "" +lose_states: "lose1 lose2" + +successors: """ +root Left lose1 +root Right lose2 +""" + +evaluation: """ +lose1 1.0 +lose2 0.0 +""" + diff --git a/test_cases/q3/0-eval-function-lose-states-2.solution b/test_cases/q3/0-eval-function-lose-states-2.solution new file mode 100644 index 0000000..cc0f8f7 --- /dev/null +++ b/test_cases/q3/0-eval-function-lose-states-2.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/0-eval-function-lose-states-2.test. +action: "Right" +generated: "lose1 lose2 root" diff --git a/test_cases/q3/0-eval-function-lose-states-2.test b/test_cases/q3/0-eval-function-lose-states-2.test new file mode 100644 index 0000000..ed55fc8 --- /dev/null +++ b/test_cases/q3/0-eval-function-lose-states-2.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + root + / \ + lose1 lose2 + 0 1 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on losing states. +""" +num_agents: "2" + +start_state: "root" +win_states: "" +lose_states: "lose1 lose2" + +successors: """ +root Left lose1 +root Right lose2 +""" + +evaluation: """ +lose1 0.0 +lose2 1.0 +""" + diff --git a/test_cases/q3/0-eval-function-win-states-1.solution b/test_cases/q3/0-eval-function-win-states-1.solution new file mode 100644 index 0000000..7734b36 --- /dev/null +++ b/test_cases/q3/0-eval-function-win-states-1.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/0-eval-function-win-states-1.test. +action: "Left" +generated: "root win1 win2" diff --git a/test_cases/q3/0-eval-function-win-states-1.test b/test_cases/q3/0-eval-function-win-states-1.test new file mode 100644 index 0000000..20436ea --- /dev/null +++ b/test_cases/q3/0-eval-function-win-states-1.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + root + / \ + win1 win2 + 1 0 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on winning states. +""" +num_agents: "2" + +start_state: "root" +win_states: "win1 win2" +lose_states: "" + +successors: """ +root Left win1 +root Right win2 +""" + +evaluation: """ +win1 1.0 +win2 0.0 +""" + diff --git a/test_cases/q3/0-eval-function-win-states-2.solution b/test_cases/q3/0-eval-function-win-states-2.solution new file mode 100644 index 0000000..7e479db --- /dev/null +++ b/test_cases/q3/0-eval-function-win-states-2.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/0-eval-function-win-states-2.test. +action: "Right" +generated: "root win1 win2" diff --git a/test_cases/q3/0-eval-function-win-states-2.test b/test_cases/q3/0-eval-function-win-states-2.test new file mode 100644 index 0000000..6f4519c --- /dev/null +++ b/test_cases/q3/0-eval-function-win-states-2.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + root + / \ + win1 win2 + 0 1 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on winning states. +""" +num_agents: "2" + +start_state: "root" +win_states: "win1 win2" +lose_states: "" + +successors: """ +root Left win1 +root Right win2 +""" + +evaluation: """ +win1 0.0 +win2 1.0 +""" + diff --git a/test_cases/q3/0-lecture-6-tree.solution b/test_cases/q3/0-lecture-6-tree.solution new file mode 100644 index 0000000..c4a91ad --- /dev/null +++ b/test_cases/q3/0-lecture-6-tree.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/0-lecture-6-tree.test. +action: "Center" +generated: "A B C D E F G H max min1 min2 min3" diff --git a/test_cases/q3/0-lecture-6-tree.test b/test_cases/q3/0-lecture-6-tree.test new file mode 100644 index 0000000..cbc61fe --- /dev/null +++ b/test_cases/q3/0-lecture-6-tree.test @@ -0,0 +1,50 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +# Tree from lecture 6 slides +diagram: """ + max + /-/ | \--\ + / | \ + / | \ + min1 min2 min3 + /|\ /|\ /|\ + / | \ / | \ / | \ +A B C D E F G H I +3 12 8 5 4 6 14 1 11 +""" + +num_agents: "2" + +start_state: "max" +win_states: "A B C D E F G H I" +lose_states: "" + +successors: """ +max Left min1 +max Center min2 +max Right min3 +min1 Left A +min1 Center B +min1 Right C +min2 Left D +min2 Center E +min2 Right F +min3 Left G +min3 Center H +min3 Right I +""" + + +evaluation: """ +A 3.0 +B 12.0 +C 8.0 +D 5.0 +E 4.0 +F 6.0 +G 14.0 +H 1.0 +I 11.0 +""" diff --git a/test_cases/q3/0-small-tree.solution b/test_cases/q3/0-small-tree.solution new file mode 100644 index 0000000..e940986 --- /dev/null +++ b/test_cases/q3/0-small-tree.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/0-small-tree.test. +action: "pacLeft" +generated: "A B C minLeft minRight root" diff --git a/test_cases/q3/0-small-tree.test b/test_cases/q3/0-small-tree.test new file mode 100644 index 0000000..a9829d0 --- /dev/null +++ b/test_cases/q3/0-small-tree.test @@ -0,0 +1,36 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + root + / \ + minLeft minRight + / \ / \ + A B C deeper + 4 3 2 | + D + 1000 +""" +num_agents: "2" + +start_state: "root" +win_states: "A C" +lose_states: "B D" + +successors: """ +root pacLeft minLeft +root pacRight minRight +minLeft gLeft A +minLeft gRight B +minRight gLeft C +minRight gRight deeper +deeper pacLeft D +""" + +evaluation: """ +A 4.0 +B 3.0 +C 2.0 +D 1000.0 +""" diff --git a/test_cases/q3/1-1-minmax.solution b/test_cases/q3/1-1-minmax.solution new file mode 100644 index 0000000..2834b29 --- /dev/null +++ b/test_cases/q3/1-1-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/1-1-minmax.test. +action: "Left" +generated: "a b1 b2 c1 c2 cx d1 d2 d3 dx" diff --git a/test_cases/q3/1-1-minmax.test b/test_cases/q3/1-1-minmax.test new file mode 100644 index 0000000..c601316 --- /dev/null +++ b/test_cases/q3/1-1-minmax.test @@ -0,0 +1,47 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | + c1 c2 cx + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -3.01 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -3.01 +""" diff --git a/test_cases/q3/1-2-minmax.solution b/test_cases/q3/1-2-minmax.solution new file mode 100644 index 0000000..8c17bcf --- /dev/null +++ b/test_cases/q3/1-2-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/1-2-minmax.test. +action: "Right" +generated: "a b1 b2 c1 c2 cx d1 d2 d3 dx" diff --git a/test_cases/q3/1-2-minmax.test b/test_cases/q3/1-2-minmax.test new file mode 100644 index 0000000..d42a467 --- /dev/null +++ b/test_cases/q3/1-2-minmax.test @@ -0,0 +1,47 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | + c1 c2 cx + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -2.99 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -2.99 +""" diff --git a/test_cases/q3/1-3-minmax.solution b/test_cases/q3/1-3-minmax.solution new file mode 100644 index 0000000..827cdbd --- /dev/null +++ b/test_cases/q3/1-3-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/1-3-minmax.test. +action: "Left" +generated: "a b1 b2 c3 cx d5 d6 dx" diff --git a/test_cases/q3/1-3-minmax.test b/test_cases/q3/1-3-minmax.test new file mode 100644 index 0000000..0fc2226 --- /dev/null +++ b/test_cases/q3/1-3-minmax.test @@ -0,0 +1,47 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + cx c3 c4 + | / \ / \ + dx d5 d6 d7 d8 + 4.01 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b2 is 4. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 4.01 +""" diff --git a/test_cases/q3/1-4-minmax.solution b/test_cases/q3/1-4-minmax.solution new file mode 100644 index 0000000..f5570d1 --- /dev/null +++ b/test_cases/q3/1-4-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/1-4-minmax.test. +action: "Right" +generated: "a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q3/1-4-minmax.test b/test_cases/q3/1-4-minmax.test new file mode 100644 index 0000000..d8d02e2 --- /dev/null +++ b/test_cases/q3/1-4-minmax.test @@ -0,0 +1,47 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + cx c3 c4 + | / \ / \ + dx d5 d6 d7 d8 + 3.99 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b2 is 4. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 3.99 +""" diff --git a/test_cases/q3/1-5-minmax.solution b/test_cases/q3/1-5-minmax.solution new file mode 100644 index 0000000..06cebde --- /dev/null +++ b/test_cases/q3/1-5-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/1-5-minmax.test. +action: "Right" +generated: "A B C D E F G Z a b1 b2 c1 c2 cx d1 d2 d3 d4 dx" diff --git a/test_cases/q3/1-5-minmax.test b/test_cases/q3/1-5-minmax.test new file mode 100644 index 0000000..2d57290 --- /dev/null +++ b/test_cases/q3/1-5-minmax.test @@ -0,0 +1,75 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | + c1 c2 cx + / \ / \ | + d1 d2 d3 d4 dx + / \ / \ / \ / \ | + A B C D E F G H Z +-3 13 5 9 10 3 -6 8 3.01 + +a - max +b - min +c - max +d - min + +Note the minimax value of b1 is 3. +""" +num_agents: "2" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P Z" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +dx Down Z +""" + +evaluation: """ +A -3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 3.0 +G -6.0 +H 8.0 +Z 3.01 +""" diff --git a/test_cases/q3/1-6-minmax.solution b/test_cases/q3/1-6-minmax.solution new file mode 100644 index 0000000..1ced2ca --- /dev/null +++ b/test_cases/q3/1-6-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/1-6-minmax.test. +action: "Left" +generated: "A B C D E F G Z a b1 b2 c1 c2 cx d1 d2 d3 d4 dx" diff --git a/test_cases/q3/1-6-minmax.test b/test_cases/q3/1-6-minmax.test new file mode 100644 index 0000000..3360e93 --- /dev/null +++ b/test_cases/q3/1-6-minmax.test @@ -0,0 +1,75 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | + c1 c2 cx + / \ / \ | + d1 d2 d3 d4 dx + / \ / \ / \ / \ | + A B C D E F G H Z +-3 13 5 9 10 3 -6 8 2.99 + +a - max +b - min +c - max +d - min + +Note the minimax value of b1 is 3. +""" +num_agents: "2" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P Z" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +dx Down Z +""" + +evaluation: """ +A -3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 3.0 +G -6.0 +H 8.0 +Z 2.99 +""" diff --git a/test_cases/q3/1-7-minmax.solution b/test_cases/q3/1-7-minmax.solution new file mode 100644 index 0000000..74e2da0 --- /dev/null +++ b/test_cases/q3/1-7-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/1-7-minmax.test. +action: "Left" +generated: "I J K M O P Z a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q3/1-7-minmax.test b/test_cases/q3/1-7-minmax.test new file mode 100644 index 0000000..207381d --- /dev/null +++ b/test_cases/q3/1-7-minmax.test @@ -0,0 +1,75 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + cx c3 c4 + | / \ / \ + dx d5 d6 d7 d8 + | / \ / \ / \ / \ + Z I J K L M N O P + -1.99 -1 -9 4 7 2 5 -3 -2 + +a - max +b - min +c - min +d - max + +Note that the minimax value of b2 is -2 +""" +num_agents: "3" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P Z" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +dx Down Z +""" + +evaluation: """ +I -1.0 +J -9.0 +K 4.0 +L 7.0 +M 2.0 +N 5.0 +O -3.0 +P -2.0 +Z -1.99 +""" diff --git a/test_cases/q3/1-8-minmax.solution b/test_cases/q3/1-8-minmax.solution new file mode 100644 index 0000000..bf426b8 --- /dev/null +++ b/test_cases/q3/1-8-minmax.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/1-8-minmax.test. +action: "Right" +generated: "I J K M O P Z a b1 b2 c3 c4 cx d5 d6 d7 d8 dx" diff --git a/test_cases/q3/1-8-minmax.test b/test_cases/q3/1-8-minmax.test new file mode 100644 index 0000000..2272b30 --- /dev/null +++ b/test_cases/q3/1-8-minmax.test @@ -0,0 +1,75 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + cx c3 c4 + | / \ / \ + dx d5 d6 d7 d8 + | / \ / \ / \ / \ + Z I J K L M N O P + -2.01 -1 -9 4 7 2 5 -3 -2 + +a - max +b - min +c - min +d - max + +Note that the minimax value of b2 is -2.01 +""" +num_agents: "3" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P Z" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +dx Down Z +""" + +evaluation: """ +I -1.0 +J -9.0 +K 4.0 +L 7.0 +M 2.0 +N 5.0 +O -3.0 +P -2.0 +Z -2.01 +""" diff --git a/test_cases/q3/2-1a-vary-depth.solution b/test_cases/q3/2-1a-vary-depth.solution new file mode 100644 index 0000000..59d892c --- /dev/null +++ b/test_cases/q3/2-1a-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-1a-vary-depth.test. +action: "Left" +generated: "a b1 b2 c1 c2 cx" diff --git a/test_cases/q3/2-1a-vary-depth.test b/test_cases/q3/2-1a-vary-depth.test new file mode 100644 index 0000000..f8f9431 --- /dev/null +++ b/test_cases/q3/2-1a-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "1" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | +-4 c1 c2 9 cx -4.01 + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -4.01 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3, but the depth=1 limited value is -4. +The values next to c1, c2, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +c1 -4.0 +c2 9.0 +cx -4.01 +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -4.01 +""" diff --git a/test_cases/q3/2-1b-vary-depth.solution b/test_cases/q3/2-1b-vary-depth.solution new file mode 100644 index 0000000..a0f232c --- /dev/null +++ b/test_cases/q3/2-1b-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-1b-vary-depth.test. +action: "Left" +generated: "a b1 b2 c1 c2 cx d1 d2 d3 dx" diff --git a/test_cases/q3/2-1b-vary-depth.test b/test_cases/q3/2-1b-vary-depth.test new file mode 100644 index 0000000..1b161af --- /dev/null +++ b/test_cases/q3/2-1b-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | +-4 c1 c2 9 cx -4.01 + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -4.01 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3, but the depth=1 limited value is -4. +The values next to c1, c2, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +c1 -4.0 +c2 9.0 +cx -4.01 +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -4.01 +""" diff --git a/test_cases/q3/2-2a-vary-depth.solution b/test_cases/q3/2-2a-vary-depth.solution new file mode 100644 index 0000000..6e8d7fd --- /dev/null +++ b/test_cases/q3/2-2a-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-2a-vary-depth.test. +action: "Right" +generated: "a b1 b2 c1 c2 cx" diff --git a/test_cases/q3/2-2a-vary-depth.test b/test_cases/q3/2-2a-vary-depth.test new file mode 100644 index 0000000..b436d21 --- /dev/null +++ b/test_cases/q3/2-2a-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "1" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | +-4 c1 c2 9 cx -3.99 + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -3.99 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3, but the depth=1 limited value is -4. +The values next to c1, c2, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +c1 -4.0 +c2 9.0 +cx -3.99 +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -3.99 +""" diff --git a/test_cases/q3/2-2b-vary-depth.solution b/test_cases/q3/2-2b-vary-depth.solution new file mode 100644 index 0000000..f508aef --- /dev/null +++ b/test_cases/q3/2-2b-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-2b-vary-depth.test. +action: "Left" +generated: "a b1 b2 c1 c2 cx d1 d2 d3 dx" diff --git a/test_cases/q3/2-2b-vary-depth.test b/test_cases/q3/2-2b-vary-depth.test new file mode 100644 index 0000000..c0540a3 --- /dev/null +++ b/test_cases/q3/2-2b-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ | +-4 c1 c2 9 cx -3.99 + / \ / \ | + d1 d2 d3 d4 dx +-3 -9 10 6 -3.99 + +a - max +b - min +c - max + +Note that the minimax value of b1 is -3, but the depth=1 limited value is -4. +The values next to c1, c2, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Down cx +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +cx Down dx +""" + +evaluation: """ +c1 -4.0 +c2 9.0 +cx -3.99 +d1 -3.0 +d2 -9.0 +d3 10.0 +d4 6.0 +dx -3.99 +""" diff --git a/test_cases/q3/2-3a-vary-depth.solution b/test_cases/q3/2-3a-vary-depth.solution new file mode 100644 index 0000000..d805b84 --- /dev/null +++ b/test_cases/q3/2-3a-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-3a-vary-depth.test. +action: "Left" +generated: "a b1 b2 c3 c4 cx" diff --git a/test_cases/q3/2-3a-vary-depth.test b/test_cases/q3/2-3a-vary-depth.test new file mode 100644 index 0000000..853a8d3 --- /dev/null +++ b/test_cases/q3/2-3a-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "1" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + 5.01 cx 8 c3 c4 5 + | / \ / \ + dx d5 d6 d7 d8 + 5.01 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b1 is 4, but the depth=1 limited value is 5. +The values next to c3, c4, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +c3 8.0 +c4 5.0 +cx 5.01 +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 5.01 +""" diff --git a/test_cases/q3/2-3b-vary-depth.solution b/test_cases/q3/2-3b-vary-depth.solution new file mode 100644 index 0000000..32a70c6 --- /dev/null +++ b/test_cases/q3/2-3b-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-3b-vary-depth.test. +action: "Left" +generated: "a b1 b2 c3 cx d5 d6 dx" diff --git a/test_cases/q3/2-3b-vary-depth.test b/test_cases/q3/2-3b-vary-depth.test new file mode 100644 index 0000000..2892005 --- /dev/null +++ b/test_cases/q3/2-3b-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + 5.01 cx 8 c3 c4 5 + | / \ / \ + dx d5 d6 d7 d8 + 5.01 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b1 is 4, but the depth=1 limited value is 5. +The values next to c3, c4, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +c3 8.0 +c4 5.0 +cx 5.01 +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 5.01 +""" diff --git a/test_cases/q3/2-4a-vary-depth.solution b/test_cases/q3/2-4a-vary-depth.solution new file mode 100644 index 0000000..eafdb62 --- /dev/null +++ b/test_cases/q3/2-4a-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-4a-vary-depth.test. +action: "Right" +generated: "a b1 b2 c3 c4 cx" diff --git a/test_cases/q3/2-4a-vary-depth.test b/test_cases/q3/2-4a-vary-depth.test new file mode 100644 index 0000000..73d681b --- /dev/null +++ b/test_cases/q3/2-4a-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "1" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + 4.99 cx 8 c3 c4 5 + | / \ / \ + dx d5 d6 d7 d8 + 4.99 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b1 is 4, but the depth=1 limited value is 5. +The values next to c3, c4, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +c3 8.0 +c4 5.0 +cx 4.99 +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 4.99 +""" diff --git a/test_cases/q3/2-4b-vary-depth.solution b/test_cases/q3/2-4b-vary-depth.solution new file mode 100644 index 0000000..820398a --- /dev/null +++ b/test_cases/q3/2-4b-vary-depth.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-4b-vary-depth.test. +action: "Left" +generated: "a b1 b2 c3 cx d5 d6 dx" diff --git a/test_cases/q3/2-4b-vary-depth.test b/test_cases/q3/2-4b-vary-depth.test new file mode 100644 index 0000000..a7aca5f --- /dev/null +++ b/test_cases/q3/2-4b-vary-depth.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + | / \ + 4.99 cx 8 c3 c4 5 + | / \ / \ + dx d5 d6 d7 d8 + 4.99 4 -7 0 5 + +a - max +b - min +c - max + +Note that the minimax value of b1 is 4, but the depth=1 limited value is 5. +The values next to c3, c4, and cx are the values of the evaluation function, not +necessarily the correct minimax backup. +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8 dx" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Down cx +b2 Left c3 +b2 Right c4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +cx Down dx +""" + +evaluation: """ +c3 8.0 +c4 5.0 +cx 4.99 +d5 4.0 +d6 -7.0 +d7 0.0 +d8 5.0 +dx 4.99 +""" diff --git a/test_cases/q3/2-one-ghost-3level.solution b/test_cases/q3/2-one-ghost-3level.solution new file mode 100644 index 0000000..b22f76f --- /dev/null +++ b/test_cases/q3/2-one-ghost-3level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/2-one-ghost-3level.test. +action: "Left" +generated: "a b1 b2 c1 c2 c3 d1 d2 d3 d5 d6" diff --git a/test_cases/q3/2-one-ghost-3level.test b/test_cases/q3/2-one-ghost-3level.test new file mode 100644 index 0000000..2ec19b4 --- /dev/null +++ b/test_cases/q3/2-one-ghost-3level.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 + 3 9 10 6 4 7 0 5 + +a - max +b - min +c - max +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +""" + +evaluation: """ +d1 3.0 +d2 9.0 +d3 10.0 +d4 6.0 +d5 4.0 +d6 7.0 +d7 0.0 +d8 5.0 +""" diff --git a/test_cases/q3/3-one-ghost-4level.solution b/test_cases/q3/3-one-ghost-4level.solution new file mode 100644 index 0000000..b6a9a0f --- /dev/null +++ b/test_cases/q3/3-one-ghost-4level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/3-one-ghost-4level.test. +action: "Left" +generated: "A B C D E F I K a b1 b2 c1 c2 c3 d1 d2 d3 d5 d6" diff --git a/test_cases/q3/3-one-ghost-4level.test b/test_cases/q3/3-one-ghost-4level.test new file mode 100644 index 0000000..cfa33db --- /dev/null +++ b/test_cases/q3/3-one-ghost-4level.test @@ -0,0 +1,79 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 +/ \ / \ / \ / \ / \ / \ / \ / \ +A B C D E F G H I J K L M N O P +3 13 5 9 10 11 6 8 1 0 4 7 12 15 2 14 + +a - max +b - min +c - max +d - min +""" +num_agents: "2" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +""" + +evaluation: """ +A 3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 11.0 +G 6.0 +H 8.0 +I 1.0 +J 0.0 +K 4.0 +L 7.0 +M 12.0 +N 15.0 +O 2.0 +P 14.0 +""" diff --git a/test_cases/q3/4-two-ghosts-3level.solution b/test_cases/q3/4-two-ghosts-3level.solution new file mode 100644 index 0000000..12e9520 --- /dev/null +++ b/test_cases/q3/4-two-ghosts-3level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/4-two-ghosts-3level.test. +action: "Left" +generated: "a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7" diff --git a/test_cases/q3/4-two-ghosts-3level.test b/test_cases/q3/4-two-ghosts-3level.test new file mode 100644 index 0000000..fd3ac91 --- /dev/null +++ b/test_cases/q3/4-two-ghosts-3level.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 + 3 9 10 6 4 7 0 5 + +a - max +b - min +c - min +""" +num_agents: "3" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +""" + +evaluation: """ +d1 3.0 +d2 9.0 +d3 10.0 +d4 6.0 +d5 4.0 +d6 7.0 +d7 0.0 +d8 5.0 +""" diff --git a/test_cases/q3/5-two-ghosts-4level.solution b/test_cases/q3/5-two-ghosts-4level.solution new file mode 100644 index 0000000..89c534c --- /dev/null +++ b/test_cases/q3/5-two-ghosts-4level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/5-two-ghosts-4level.test. +action: "Left" +generated: "A B C D E G H I J a b1 b2 c1 c2 c3 d1 d2 d3 d4 d5" diff --git a/test_cases/q3/5-two-ghosts-4level.test b/test_cases/q3/5-two-ghosts-4level.test new file mode 100644 index 0000000..ce431fc --- /dev/null +++ b/test_cases/q3/5-two-ghosts-4level.test @@ -0,0 +1,79 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 +/ \ / \ / \ / \ / \ / \ / \ / \ +A B C D E F G H I J K L M N O P +3 13 5 9 10 11 6 8 1 0 4 7 12 15 2 14 + +a - max +b - min +c - min +d - max +""" +num_agents: "3" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +""" + +evaluation: """ +A 3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 11.0 +G 6.0 +H 8.0 +I 1.0 +J 0.0 +K 4.0 +L 7.0 +M 12.0 +N 15.0 +O 2.0 +P 14.0 +""" diff --git a/test_cases/q3/6-tied-root.solution b/test_cases/q3/6-tied-root.solution new file mode 100644 index 0000000..93ece27 --- /dev/null +++ b/test_cases/q3/6-tied-root.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/6-tied-root.test. +action: "Left" +generated: "A B C max min1 min2" diff --git a/test_cases/q3/6-tied-root.test b/test_cases/q3/6-tied-root.test new file mode 100644 index 0000000..b43f4d9 --- /dev/null +++ b/test_cases/q3/6-tied-root.test @@ -0,0 +1,31 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + max + / \ +min1 min2 + | / \ + A B C +10 10 0 +""" +num_agents: "2" + +start_state: "max" +win_states: "A B" +lose_states: "C" + +successors: """ +max Left min1 +max Right min2 +min1 Down A +min2 Left B +min2 Right C +""" + +evaluation: """ +A 10.0 +B 10.0 +C 0.0 +""" diff --git a/test_cases/q3/7-1a-check-depth-one-ghost.solution b/test_cases/q3/7-1a-check-depth-one-ghost.solution new file mode 100644 index 0000000..a3a74c4 --- /dev/null +++ b/test_cases/q3/7-1a-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/7-1a-check-depth-one-ghost.test. +action: "Left" +generated: "a b1 b2 b3 c1 c2 c3" diff --git a/test_cases/q3/7-1a-check-depth-one-ghost.test b/test_cases/q3/7-1a-check-depth-one-ghost.test new file mode 100644 index 0000000..0230cbb --- /dev/null +++ b/test_cases/q3/7-1a-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "1" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 1, the evaluation function is called at level c, +so Left should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q3/7-1b-check-depth-one-ghost.solution b/test_cases/q3/7-1b-check-depth-one-ghost.solution new file mode 100644 index 0000000..8dad3c7 --- /dev/null +++ b/test_cases/q3/7-1b-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/7-1b-check-depth-one-ghost.test. +action: "Center" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3" diff --git a/test_cases/q3/7-1b-check-depth-one-ghost.test b/test_cases/q3/7-1b-check-depth-one-ghost.test new file mode 100644 index 0000000..7e0ced7 --- /dev/null +++ b/test_cases/q3/7-1b-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 2, the evaluation function is called at level e, +so Center should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q3/7-1c-check-depth-one-ghost.solution b/test_cases/q3/7-1c-check-depth-one-ghost.solution new file mode 100644 index 0000000..210bb5d --- /dev/null +++ b/test_cases/q3/7-1c-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/7-1c-check-depth-one-ghost.test. +action: "Right" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3" diff --git a/test_cases/q3/7-1c-check-depth-one-ghost.test b/test_cases/q3/7-1c-check-depth-one-ghost.test new file mode 100644 index 0000000..cd92eb9 --- /dev/null +++ b/test_cases/q3/7-1c-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 3, the evaluation function is called at level g, +so Right should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q3/7-2a-check-depth-two-ghosts.solution b/test_cases/q3/7-2a-check-depth-two-ghosts.solution new file mode 100644 index 0000000..9a08a38 --- /dev/null +++ b/test_cases/q3/7-2a-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/7-2a-check-depth-two-ghosts.test. +action: "Left" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3" diff --git a/test_cases/q3/7-2a-check-depth-two-ghosts.test b/test_cases/q3/7-2a-check-depth-two-ghosts.test new file mode 100644 index 0000000..421a05c --- /dev/null +++ b/test_cases/q3/7-2a-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "1" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 1, the evaluation function is called at level d, +so Left should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q3/7-2b-check-depth-two-ghosts.solution b/test_cases/q3/7-2b-check-depth-two-ghosts.solution new file mode 100644 index 0000000..194c0aa --- /dev/null +++ b/test_cases/q3/7-2b-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/7-2b-check-depth-two-ghosts.test. +action: "Center" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3" diff --git a/test_cases/q3/7-2b-check-depth-two-ghosts.test b/test_cases/q3/7-2b-check-depth-two-ghosts.test new file mode 100644 index 0000000..728806e --- /dev/null +++ b/test_cases/q3/7-2b-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "2" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 2, the evaluation function is called at level g, +so Center should be returned. If your algorithm is returning +a different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q3/7-2c-check-depth-two-ghosts.solution b/test_cases/q3/7-2c-check-depth-two-ghosts.solution new file mode 100644 index 0000000..1e989f3 --- /dev/null +++ b/test_cases/q3/7-2c-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q3/7-2c-check-depth-two-ghosts.test. +action: "Right" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3 h1 h2 h3 i1 i2 i3 j1 j2 j3" diff --git a/test_cases/q3/7-2c-check-depth-two-ghosts.test b/test_cases/q3/7-2c-check-depth-two-ghosts.test new file mode 100644 index 0000000..9e727ce --- /dev/null +++ b/test_cases/q3/7-2c-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "AlphaBetaAgent" +depth: "3" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 3, the evaluation function is called at level j, +so Right should be returned. If your algorithm is returning +a different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q3/8-pacman-game.solution b/test_cases/q3/8-pacman-game.solution new file mode 100644 index 0000000..ec0b0b8 --- /dev/null +++ b/test_cases/q3/8-pacman-game.solution @@ -0,0 +1,444 @@ +optimalActions: """ +[[["West", "East"], 39], [["West", "East"], 27]] +[[["West"], 75], [["West"], 57]] +[[["West"], 95], [["West"], 77]] +[[["West", "North"], 72], [["West", "North"], 54]] +[[["West"], 51], [["West"], 39]] +[[["West", "North"], 76], [["West", "North"], 58]] +[[["West"], 69], [["West"], 51]] +[[["West"], 34], [["West"], 23]] +[[["North"], 55], [["North"], 41]] +[[["North"], 63], [["North"], 32]] +[[["North"], 87], [["North"], 43]] +[[["North"], 69], [["North"], 34]] +[[["Stop", "East"], 116], [["East"], 56]] +[[["East"], 110], [["East"], 52]] +[[["West"], 28], [["West"], 17]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["North"], 28], [["North"], 18]] +[[["North"], 47], [["North"], 30]] +[[["West"], 35], [["West"], 23]] +[[["East"], 28], [["East"], 15]] +[[["North"], 74], [["North"], 48]] +[[["East", "North"], 130], [["East", "North"], 87]] +[[["East", "North"], 213], [["East", "North"], 158]] +[[["North", "South"], 101], [["North", "South"], 73]] +[[["West"], 48], [["West"], 36]] +[[["West"], 60], [["West"], 45]] +[[["West", "Stop"], 49], [["West"], 36]] +[[["West", "Stop", "East"], 69], [["West", "East"], 49]] +[[["West", "Stop", "East"], 61], [["West", "East"], 41]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 28], [["East", "South"], 19]] +[[["Stop", "East", "South"], 34], [["East", "South"], 23]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 81], [["East", "South"], 53]] +[[["Stop", "East", "South"], 64], [["East", "South"], 43]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 81], [["East", "South"], 53]] +[[["Stop", "East", "South"], 102], [["East", "South"], 67]] +[[["Stop", "South"], 23], [["South"], 13]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East", "North"], 28], [["East", "North"], 18]] +[[["East"], 35], [["East"], 22]] +[[["North"], 28], [["North"], 18]] +[[["North"], 38], [["North"], 22]] +[[["East"], 30], [["East"], 20]] +[[["East"], 33], [["East"], 18]] +[[["East"], 18], [["East"], 12]] +[[["East"], 33], [["East"], 23]] +[[["East"], 48], [["East"], 29]] +[[["East"], 49], [["East"], 26]] +[[["East"], 44], [["East"], 29]] +[[["North", "South"], 75], [["North", "South"], 52]] +[[["East", "North"], 113], [["East", "North"], 74]] +[[["East", "North"], 89], [["East", "North"], 65]] +[[["North", "South"], 173], [["North", "South"], 130]] +[[["West", "East"], 54], [["West", "East"], 42]] +[[["West", "Stop", "East"], 130], [["West", "East"], 87]] +[[["Stop", "East", "South"], 58], [["East", "South"], 43]] +[[["Stop", "East"], 110], [["South"], 82]] +[[["East"], 71], [["East"], 45]] +[[["West"], 66], [["West"], 42]] +[[["South"], 70], [["South"], 48]] +[[["South"], 48], [["South"], 37]] +[[["South"], 179], [["South"], 104]] +[[["South"], 68], [["South"], 41]] +[[["West"], 25], [["West"], 18]] +[[["West"], 41], [["West"], 29]] +[[["West"], 14], [["West"], 10]] +[[["West"], 20], [["West"], 14]] +[[["West"], 13], [["West"], 9]] +[[["West"], 13], [["West"], 9]] +[[["West"], 16], [["West"], 12]] +[[["West", "North"], 28], [["West", "North"], 20]] +[[["West"], 30], [["West"], 23]] +[[["West", "Stop", "East", "North"], 66], [["West", "East", "North"], 46]] +[[["West", "Stop", "East"], 126], [["West", "East"], 89]] +[[["West", "Stop", "East"], 30], [["West", "East"], 20]] +[[["Stop", "East", "North"], 67], [["East", "North"], 45]] +[[["Stop", "North"], 52], [["North"], 27]] +[[["North"], 30], [["North"], 19]] +[[["North"], 28], [["North"], 17]] +[[["North"], 17], [["North"], 11]] +[[["North"], 30], [["North"], 19]] +[[["East"], 28], [["East"], 17]] +[[["East"], 17], [["East"], 11]] +[[["East"], 40], [["East"], 29]] +[[["East", "South"], 79], [["East", "South"], 60]] +[[["East", "South"], 90], [["East", "South"], 62]] +[[["South"], 96], [["South"], 61]] +[[["North", "South"], 195], [["North", "South"], 132]] +[[["West"], 80], [["West"], 60]] +[[["West", "Stop", "East", "South"], 83], [["West", "East", "South"], 61]] +[[["West", "Stop", "East", "South"], 90], [["West", "East", "South"], 66]] +[[["West", "Stop", "East"], 134], [["West", "East"], 95]] +[[["West", "Stop", "East"], 82], [["West", "East"], 55]] +[[["Stop", "East", "South"], 142], [["East", "South"], 95]] +[[["Stop", "East", "South"], 95], [["East", "South"], 62]] +[[["Stop", "East", "South"], 128], [["East", "South"], 86]] +[[["Stop", "East", "South"], 82], [["East", "South"], 55]] +[[["Stop", "East", "South"], 85], [["East", "South"], 57]] +[[["Stop", "East", "South"], 182], [["East", "South"], 119]] +[[["Stop", "East", "South"], 154], [["East", "South"], 103]] +[[["Stop", "South"], 46], [["South"], 25]] +[[["South"], 28], [["South"], 17]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East", "North"], 28], [["East", "North"], 18]] +[[["East"], 37], [["East"], 22]] +[[["East", "North"], 34], [["East", "North"], 24]] +[[["East"], 56], [["East"], 29]] +[[["East"], 17], [["East"], 11]] +[[["East"], 26], [["East"], 15]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East"], 27], [["East"], 17]] +[[["East"], 37], [["East"], 22]] +[[["East", "North"], 37], [["East", "North"], 24]] +[[["East"], 56], [["East"], 29]] +[[["East"], 19], [["East"], 11]] +[[["North"], 26], [["North"], 15]] +[[["North"], 19], [["North"], 11]] +[[["North"], 30], [["North"], 17]] +[[["North"], 30], [["North"], 19]] +[[["West"], 28], [["West"], 19]] +[[["West"], 23], [["West"], 13]] +[[["West", "Stop", "East"], 7], [["West", "East"], 3]] +""" +altDepthActions: """ +[["West", "East"], ["West", "East"], ["West", "East"], ["West", "East"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["Stop", "North"], ["North"]] +[["East"], ["East"], ["Stop", "East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["West"], ["West"], ["West"], ["West"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["West"], ["West"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"], ["North"], ["North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West", "Stop"], ["West"]] +[["West"], ["West"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"], ["Stop", "South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North", "South"], ["North", "South"], ["South"], ["South"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"], ["North"], ["North"]] +[["West", "East"], ["West", "East"], ["East"], ["East"]] +[["West"], ["West"], ["East"], ["East"]] +[["Stop", "East", "South"], ["East", "South"], ["East"], ["East"]] +[["Stop", "East"], ["East"], ["Stop", "East"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["West"], ["West"], ["West"], ["West"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["West", "East"], ["West", "East"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East", "North"], ["West", "East", "North"], ["West", "Stop", "East", "North"], ["West", "East", "North"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "North"], ["East", "North"], ["Stop", "East", "North"], ["East", "North"]] +[["Stop", "North"], ["North"], ["Stop", "North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "South"], ["East", "South"], ["East", "South"], ["East", "South"]] +[["East", "South"], ["East", "South"], ["East", "South"], ["East", "South"]] +[["South"], ["South"], ["South"], ["South"]] +[["North", "South"], ["North", "South"], ["North", "South"], ["North", "South"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"], ["Stop", "South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +""" +partialPlyBugActions: """ +[["West", "East"], ["West", "East"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["Stop", "East"], ["East"]] +[["West"], ["West"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["West"], ["West"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "Stop"], ["West"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North", "South"], ["North", "South"]] +[["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"]] +[["West", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East"], ["East"]] +[["East"], ["East"]] +[["West"], ["West"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West", "Stop", "East", "North"], ["West", "East", "North"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "North"], ["East", "North"]] +[["Stop", "North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "South"], ["East", "South"]] +[["East", "South"], ["East", "South"]] +[["South"], ["South"]] +[["North", "South"], ["North", "South"]] +[["West"], ["West"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "Stop", "East"], ["West", "East"]] +""" diff --git a/test_cases/q3/8-pacman-game.test b/test_cases/q3/8-pacman-game.test new file mode 100644 index 0000000..56341ae --- /dev/null +++ b/test_cases/q3/8-pacman-game.test @@ -0,0 +1,19 @@ +class: "PacmanGameTreeTest" +alg: "AlphaBetaAgent" +seed: "0" +depth: "2" +max_points: "4" + +# The following specifies the layout to be used +layoutName: "smallClassic" +layout: """ +%%%%%%%%%%%%%%%%%%%% +%......%G G%......% +%.%%...%% %%...%%.% +%.%o.%........%.o%.% +%.%%.%.%%%%%%.%.%%.% +%........P.........% +%%%%%%%%%%%%%%%%%%%% +""" + + diff --git a/test_cases/q3/CONFIG b/test_cases/q3/CONFIG index e5332c3..a5adc3f 100644 --- a/test_cases/q3/CONFIG +++ b/test_cases/q3/CONFIG @@ -1,2 +1,2 @@ +max_points: "5" class: "PassAllTestsQuestion" -max_points: "3" diff --git a/test_cases/q3/graph_backtrack.solution b/test_cases/q3/graph_backtrack.solution deleted file mode 100644 index d150cb7..0000000 --- a/test_cases/q3/graph_backtrack.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q3/graph_backtrack.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->C 0:C->G" -expanded_states: "A B C D" -rev_solution: "1:A->C 0:C->G" -rev_expanded_states: "A B C D" diff --git a/test_cases/q3/graph_backtrack.test b/test_cases/q3/graph_backtrack.test deleted file mode 100644 index a74bd9e..0000000 --- a/test_cases/q3/graph_backtrack.test +++ /dev/null @@ -1,32 +0,0 @@ -class: "GraphSearchTest" -algorithm: "uniformCostSearch" - -diagram: """ - B - ^ - | -*A --> C --> G - | - V - D - -A is the start state, G is the goal. Arrows mark -possible state transitions. This tests whether -you extract the sequence of actions correctly even -if your search backtracks. If you fail this, your -nodes are not correctly tracking the sequences of -actions required to reach them. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -A 1:A->C C 2.0 -A 2:A->D D 4.0 -C 0:C->G G 8.0 -""" diff --git a/test_cases/q3/graph_bfs_vs_dfs.solution b/test_cases/q3/graph_bfs_vs_dfs.solution deleted file mode 100644 index 5dfffca..0000000 --- a/test_cases/q3/graph_bfs_vs_dfs.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q3/graph_bfs_vs_dfs.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->G" -expanded_states: "A B" -rev_solution: "1:A->G" -rev_expanded_states: "A B" diff --git a/test_cases/q3/graph_bfs_vs_dfs.test b/test_cases/q3/graph_bfs_vs_dfs.test deleted file mode 100644 index 87aa465..0000000 --- a/test_cases/q3/graph_bfs_vs_dfs.test +++ /dev/null @@ -1,30 +0,0 @@ -# Graph where BFS finds the optimal solution but DFS does not -class: "GraphSearchTest" -algorithm: "uniformCostSearch" - -diagram: """ -/-- B -| ^ -| | -| *A -->[G] -| | ^ -| V | -\-->D ----/ - -A is the start state, G is the goal. Arrows -mark possible transitions -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -A 1:A->G G 2.0 -A 2:A->D D 4.0 -B 0:B->D D 8.0 -D 0:D->G G 16.0 -""" diff --git a/test_cases/q3/graph_infinite.solution b/test_cases/q3/graph_infinite.solution deleted file mode 100644 index c6cd195..0000000 --- a/test_cases/q3/graph_infinite.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q3/graph_infinite.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "0:A->B 1:B->C 1:C->G" -expanded_states: "A B C" -rev_solution: "0:A->B 1:B->C 1:C->G" -rev_expanded_states: "A B C" diff --git a/test_cases/q3/graph_infinite.test b/test_cases/q3/graph_infinite.test deleted file mode 100644 index 80d807f..0000000 --- a/test_cases/q3/graph_infinite.test +++ /dev/null @@ -1,30 +0,0 @@ -# Graph where natural action choice leads to an infinite loop -class: "GraphSearchTest" -algorithm: "uniformCostSearch" - -diagram: """ - B <--> C - ^ /| - | / | - V / V -*A<-/ [G] - -A is the start state, G is the goal. Arrows mark -possible state transitions. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -B 0:B->A A 2.0 -B 1:B->C C 4.0 -C 0:C->A A 8.0 -C 1:C->G G 16.0 -C 2:C->B B 32.0 -""" - diff --git a/test_cases/q3/graph_manypaths.solution b/test_cases/q3/graph_manypaths.solution deleted file mode 100644 index 628568f..0000000 --- a/test_cases/q3/graph_manypaths.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q3/graph_manypaths.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->C 0:C->D 1:D->F 0:F->G" -expanded_states: "A B1 C B2 D E1 F E2" -rev_solution: "1:A->C 0:C->D 1:D->F 0:F->G" -rev_expanded_states: "A B1 C B2 D E1 F E2" diff --git a/test_cases/q3/graph_manypaths.test b/test_cases/q3/graph_manypaths.test deleted file mode 100644 index 8c39dc7..0000000 --- a/test_cases/q3/graph_manypaths.test +++ /dev/null @@ -1,39 +0,0 @@ -class: "GraphSearchTest" -algorithm: "uniformCostSearch" - -diagram: """ - B1 E1 - ^ \ ^ \ - / V / V -*A --> C --> D --> F --> [G] - \ ^ \ ^ - V / V / - B2 E2 - -A is the start state, G is the goal. Arrows mark -possible state transitions. This graph has multiple -paths to the goal, where nodes with the same state -are added to the fringe multiple times before they -are expanded. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B1 B1 1.0 -A 1:A->C C 2.0 -A 2:A->B2 B2 4.0 -B1 0:B1->C C 8.0 -B2 0:B2->C C 16.0 -C 0:C->D D 32.0 -D 0:D->E1 E1 64.0 -D 1:D->F F 128.0 -D 2:D->E2 E2 256.0 -E1 0:E1->F F 512.0 -E2 0:E2->F F 1024.0 -F 0:F->G G 2048.0 -""" diff --git a/test_cases/q3/ucs_0_graph.solution b/test_cases/q3/ucs_0_graph.solution deleted file mode 100644 index b8c1509..0000000 --- a/test_cases/q3/ucs_0_graph.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q3/ucs_0_graph.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "Right Down Down" -expanded_states: "A B D C G" -rev_solution: "Right Down Down" -rev_expanded_states: "A B D C G" diff --git a/test_cases/q3/ucs_0_graph.test b/test_cases/q3/ucs_0_graph.test deleted file mode 100644 index e8f3d4c..0000000 --- a/test_cases/q3/ucs_0_graph.test +++ /dev/null @@ -1,39 +0,0 @@ -class: "GraphSearchTest" -algorithm: "uniformCostSearch" - -diagram: """ - C - ^ - | 2 - 2 V 4 -*A <----> B -----> [H] - |1 - 1.5 V 2.5 - G <----- D -----> E - | - 2 | - V - [F] - -A is the start state, F and H is the goal. Arrows mark possible state -transitions. The number next to the arrow is the cost of that transition. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: H F -A Right B 2.0 -B Right H 4.0 -B Down D 1.0 -B Up C 2.0 -B Left A 2.0 -C Down B 2.0 -D Right E 2.5 -D Down F 2.0 -D Left G 1.5 -""" - diff --git a/test_cases/q3/ucs_1_problemC.solution b/test_cases/q3/ucs_1_problemC.solution deleted file mode 100644 index dc8fc4c..0000000 --- a/test_cases/q3/ucs_1_problemC.solution +++ /dev/null @@ -1,22 +0,0 @@ -# This is the solution file for test_cases/q3/ucs_1_problemC.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -# Number of nodes expanded must be with a factor of 1.1 of the numbers below. -solution: """ -West West West West West West West West West South South East East -South South South West West West North West West West West South South -South East East East East East East East South South South South South -South South West West West West West West West West West West West -West West West West West West South West West West West West West West -West West -""" -expanded_nodes: "269" -rev_solution: """ -West West West West West West West West West South South East East -South South South West West West North West West West West South South -South East East East East East East East South South South South South -South South West West West West West West West West West West West -West West West West West West South West West West West West West West -West West -""" -rev_expanded_nodes: "269" diff --git a/test_cases/q3/ucs_1_problemC.test b/test_cases/q3/ucs_1_problemC.test deleted file mode 100644 index 1ce714d..0000000 --- a/test_cases/q3/ucs_1_problemC.test +++ /dev/null @@ -1,28 +0,0 @@ -class: "PacmanSearchTest" -algorithm: "uniformCostSearch" -points: "0.5" - -# The following specifies the layout to be used -layoutName: "mediumMaze" -layout: """ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% % -% %% % % %%%%%%% %% % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % %% %% % -% %% % % % % % %%%% %%% %%%%%% % -% % % % % % %% %%%%%%%% % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% % -% %%%%%% %%%%%%% %% %%%%%% % -%%%%%% % %%%% %% % % -% %%%%%% %%%%% % %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%%%% %%%%%%%%%%% %% %% % -%%%%%%%%%% %%%%%% % -%. %%%%%%%%%%%%%%%% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -""" -leewayFactor: "1.1" -#costFn: "lambda pos: 1" diff --git a/test_cases/q3/ucs_2_problemE.solution b/test_cases/q3/ucs_2_problemE.solution deleted file mode 100644 index d84245f..0000000 --- a/test_cases/q3/ucs_2_problemE.solution +++ /dev/null @@ -1,22 +0,0 @@ -# This is the solution file for test_cases/q3/ucs_2_problemE.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -# Number of nodes expanded must be with a factor of 1.1 of the numbers below. -solution: """ -South South West West West West South South East East East East South -South West West West West South South East East East East South South -West West West West South South East East East East South South South -West West West West West West West North West West West West West West -West West West West West West West West West West West South West West -West West West West West West West -""" -expanded_nodes: "260" -rev_solution: """ -South South West West West West South South East East East East South -South West West West West South South East East East East South South -West West West West South South East East East East South South South -West West West West West West West North West West West West West West -West West West West West West West West West West West South West West -West West West West West West West -""" -rev_expanded_nodes: "260" diff --git a/test_cases/q3/ucs_2_problemE.test b/test_cases/q3/ucs_2_problemE.test deleted file mode 100644 index 3c609f2..0000000 --- a/test_cases/q3/ucs_2_problemE.test +++ /dev/null @@ -1,28 +0,0 @@ -class: "PacmanSearchTest" -algorithm: "uniformCostSearch" -points: "0.5" - -# The following specifies the layout to be used -layoutName: "mediumMaze" -layout: """ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% % -% %% % % %%%%%%% %% % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % %% %% % -% %% % % % % % %%%% %%% %%%%%% % -% % % % % % %% %%%%%%%% % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% % -% %%%%%% %%%%%%% %% %%%%%% % -%%%%%% % %%%% %% % % -% %%%%%% %%%%% % %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%%%% %%%%%%%%%%% %% %% % -%%%%%%%%%% %%%%%% % -%. %%%%%%%%%%%%%%%% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -""" -leewayFactor: "1.1" -costFn: "lambda pos: .5 ** pos[0]" diff --git a/test_cases/q3/ucs_3_problemW.solution b/test_cases/q3/ucs_3_problemW.solution deleted file mode 100644 index e04325d..0000000 --- a/test_cases/q3/ucs_3_problemW.solution +++ /dev/null @@ -1,34 +0,0 @@ -# This is the solution file for test_cases/q3/ucs_3_problemW.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -# Number of nodes expanded must be with a factor of 1.1 of the numbers below. -solution: """ -West West West West West West West West West West West West West West -West West West West West West West West West West West West West West -West West West West West South South South South South South South -South South East East East North North North North North North North -East East South South South South South South East East North North -North North North North East East South South South South East East -North North East East South South East East East South South West West -West West West West South South West West West West West South West -West West West West South South East East East East East East East -North East East East East East North North East East East East East -East South South West West West West South South West West West West -West South West West West West West West West West West -""" -expanded_nodes: "173" -rev_solution: """ -West West West West West West West West West West West West West West -West West West West West West West West West West West West West West -West West West West West South South South South South South South -South South East East East North North North North North North North -East East South South South South South South East East North North -North North North North East East South South South South East East -North North East East South South East East East South South West West -West West West West South South West West West West West South West -West West West West South South East East East East East East East -North East East East East East North North East East East East East -East South South West West West West South South West West West West -West South West West West West West West West West West -""" -rev_expanded_nodes: "173" diff --git a/test_cases/q3/ucs_3_problemW.test b/test_cases/q3/ucs_3_problemW.test deleted file mode 100644 index fbc2fad..0000000 --- a/test_cases/q3/ucs_3_problemW.test +++ /dev/null @@ -1,28 +0,0 @@ -class: "PacmanSearchTest" -algorithm: "uniformCostSearch" -points: "0.5" - -# The following specifies the layout to be used -layoutName: "mediumMaze" -layout: """ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% % -% %% % % %%%%%%% %% % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % %% %% % -% %% % % % % % %%%% %%% %%%%%% % -% % % % % % %% %%%%%%%% % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% % -% %%%%%% %%%%%%% %% %%%%%% % -%%%%%% % %%%% %% % % -% %%%%%% %%%%% % %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%%%% %%%%%%%%%%% %% %% % -%%%%%%%%%% %%%%%% % -%. %%%%%%%%%%%%%%%% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -""" -leewayFactor: "1.1" -costFn: "lambda pos: 2 ** pos[0]" diff --git a/test_cases/q3/ucs_4_testSearch.solution b/test_cases/q3/ucs_4_testSearch.solution deleted file mode 100644 index b8c5303..0000000 --- a/test_cases/q3/ucs_4_testSearch.solution +++ /dev/null @@ -1,12 +0,0 @@ -# This is the solution file for test_cases/q3/ucs_4_testSearch.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -# Number of nodes expanded must be with a factor of 2.0 of the numbers below. -solution: """ -West East East South South West West -""" -expanded_nodes: "14" -rev_solution: """ -West East East South South West West -""" -rev_expanded_nodes: "13" diff --git a/test_cases/q3/ucs_4_testSearch.test b/test_cases/q3/ucs_4_testSearch.test deleted file mode 100644 index a16c6d8..0000000 --- a/test_cases/q3/ucs_4_testSearch.test +++ /dev/null @@ -1,16 +0,0 @@ -class: "PacmanSearchTest" -algorithm: "uniformCostSearch" -points: "0.5" - -# The following specifies the layout to be used -layoutName: "testSearch" -layout: """ -%%%%% -%.P % -%%% % -%. % -%%%%% -""" -searchProblemClass: "FoodSearchProblem" -leewayFactor: "2" - diff --git a/test_cases/q3/ucs_5_goalAtDequeue.solution b/test_cases/q3/ucs_5_goalAtDequeue.solution deleted file mode 100644 index 7d6c982..0000000 --- a/test_cases/q3/ucs_5_goalAtDequeue.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q3/ucs_5_goalAtDequeue.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->B 0:B->C 0:C->G" -expanded_states: "A B C" -rev_solution: "1:A->B 0:B->C 0:C->G" -rev_expanded_states: "A B C" diff --git a/test_cases/q3/ucs_5_goalAtDequeue.test b/test_cases/q3/ucs_5_goalAtDequeue.test deleted file mode 100644 index 72b35bc..0000000 --- a/test_cases/q3/ucs_5_goalAtDequeue.test +++ /dev/null @@ -1,29 +0,0 @@ -class: "GraphSearchTest" -algorithm: "uniformCostSearch" - -diagram: """ - 1 1 1 -*A ---> B ---> C ---> [G] - | ^ - | 10 | - \---------------------/ - -A is the start state, G is the goal. Arrows mark possible state -transitions. The number next to the arrow is the cost of that transition. - -If you fail this test case, you may be incorrectly testing if a node is a goal -before adding it into the queue, instead of testing when you remove the node -from the queue. See the algorithm pseudocode in lecture. -""" - -graph: """ -start_state: A -goal_states: G -A 0:A->G G 10.0 -A 1:A->B B 1.0 -B 0:B->C C 1.0 -C 0:C->G G 1.0 -""" -# We only care about the solution, not the expansion order. -exactExpansionOrder: "False" - diff --git a/test_cases/q4/0-eval-function-lose-states-1.solution b/test_cases/q4/0-eval-function-lose-states-1.solution new file mode 100644 index 0000000..6409bcc --- /dev/null +++ b/test_cases/q4/0-eval-function-lose-states-1.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/0-eval-function-lose-states-1.test. +action: "Left" +generated: "lose1 lose2 root" diff --git a/test_cases/q4/0-eval-function-lose-states-1.test b/test_cases/q4/0-eval-function-lose-states-1.test new file mode 100644 index 0000000..db78a7b --- /dev/null +++ b/test_cases/q4/0-eval-function-lose-states-1.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "2" + +diagram: """ + root + / \ + lose1 lose2 + 1 0 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on losing states. +""" +num_agents: "2" + +start_state: "root" +win_states: "" +lose_states: "lose1 lose2" + +successors: """ +root Left lose1 +root Right lose2 +""" + +evaluation: """ +lose1 1.0 +lose2 0.0 +""" + diff --git a/test_cases/q4/0-eval-function-lose-states-2.solution b/test_cases/q4/0-eval-function-lose-states-2.solution new file mode 100644 index 0000000..e4d7abc --- /dev/null +++ b/test_cases/q4/0-eval-function-lose-states-2.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/0-eval-function-lose-states-2.test. +action: "Right" +generated: "lose1 lose2 root" diff --git a/test_cases/q4/0-eval-function-lose-states-2.test b/test_cases/q4/0-eval-function-lose-states-2.test new file mode 100644 index 0000000..181ae48 --- /dev/null +++ b/test_cases/q4/0-eval-function-lose-states-2.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "2" + +diagram: """ + root + / \ + lose1 lose2 + 0 1 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on losing states. +""" +num_agents: "2" + +start_state: "root" +win_states: "" +lose_states: "lose1 lose2" + +successors: """ +root Left lose1 +root Right lose2 +""" + +evaluation: """ +lose1 0.0 +lose2 1.0 +""" + diff --git a/test_cases/q4/0-eval-function-win-states-1.solution b/test_cases/q4/0-eval-function-win-states-1.solution new file mode 100644 index 0000000..cb5d436 --- /dev/null +++ b/test_cases/q4/0-eval-function-win-states-1.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/0-eval-function-win-states-1.test. +action: "Left" +generated: "root win1 win2" diff --git a/test_cases/q4/0-eval-function-win-states-1.test b/test_cases/q4/0-eval-function-win-states-1.test new file mode 100644 index 0000000..d4ffd1b --- /dev/null +++ b/test_cases/q4/0-eval-function-win-states-1.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "2" + +diagram: """ + root + / \ + win1 win2 + 1 0 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on winning states. +""" +num_agents: "2" + +start_state: "root" +win_states: "win1 win2" +lose_states: "" + +successors: """ +root Left win1 +root Right win2 +""" + +evaluation: """ +win1 1.0 +win2 0.0 +""" + diff --git a/test_cases/q4/0-eval-function-win-states-2.solution b/test_cases/q4/0-eval-function-win-states-2.solution new file mode 100644 index 0000000..76d6e48 --- /dev/null +++ b/test_cases/q4/0-eval-function-win-states-2.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/0-eval-function-win-states-2.test. +action: "Right" +generated: "root win1 win2" diff --git a/test_cases/q4/0-eval-function-win-states-2.test b/test_cases/q4/0-eval-function-win-states-2.test new file mode 100644 index 0000000..4fdd8fc --- /dev/null +++ b/test_cases/q4/0-eval-function-win-states-2.test @@ -0,0 +1,30 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "2" + +diagram: """ + root + / \ + win1 win2 + 0 1 + +If your algorithm is returning a different +action, make sure you are calling the +evaluation function on winning states. +""" +num_agents: "2" + +start_state: "root" +win_states: "win1 win2" +lose_states: "" + +successors: """ +root Left win1 +root Right win2 +""" + +evaluation: """ +win1 0.0 +win2 1.0 +""" + diff --git a/test_cases/q4/0-expectimax1.solution b/test_cases/q4/0-expectimax1.solution new file mode 100644 index 0000000..ff7dfe6 --- /dev/null +++ b/test_cases/q4/0-expectimax1.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/0-expectimax1.test. +action: "Left" +generated: "A B C D E F G H I exp1 exp2 exp3 max" diff --git a/test_cases/q4/0-expectimax1.test b/test_cases/q4/0-expectimax1.test new file mode 100644 index 0000000..deee59a --- /dev/null +++ b/test_cases/q4/0-expectimax1.test @@ -0,0 +1,48 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "2" + +# Tree adapted from lecture 6 slides +diagram: """ + max + /-/ | \--\ + / | \ + / | \ + exp1 exp2 exp3 + /|\ /|\ /|\ + / | \ / | \ / | \ +A B C D E F G H I +3 12 8 2 4 6 14 5 2 +""" +num_agents: "2" + +start_state: "max" +win_states: "A B C D E F G H I" +lose_states: "" + +successors: """ +max Left exp1 +max Center exp2 +max Right exp3 +exp1 Left A +exp1 Center B +exp1 Right C +exp2 Left D +exp2 Center E +exp2 Right F +exp3 Left G +exp3 Center H +exp3 Right I +""" + +evaluation: """ +A 3.0 +B 12.0 +C 8.0 +D 2.0 +E 4.0 +F 6.0 +G 14.0 +H 5.0 +I 2.0 +""" diff --git a/test_cases/q4/1-expectimax2.solution b/test_cases/q4/1-expectimax2.solution new file mode 100644 index 0000000..30c8768 --- /dev/null +++ b/test_cases/q4/1-expectimax2.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/1-expectimax2.test. +action: "Left" +generated: "A B C D E F G H I exp1 exp2 exp3 max" diff --git a/test_cases/q4/1-expectimax2.test b/test_cases/q4/1-expectimax2.test new file mode 100644 index 0000000..d220fe6 --- /dev/null +++ b/test_cases/q4/1-expectimax2.test @@ -0,0 +1,48 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "2" + +# Tree from lecture 7 slides +diagram: """ + max + /-/ | \--\ + / | \ + / | \ + exp1 exp2 exp3 + /|\ /|\ /|\ + / | \ / | \ / | \ +A B C D E F G H I +3 12 9 2 4 6 15 6 0 +""" +num_agents: "2" + +start_state: "max" +win_states: "A B C D E F G H I" +lose_states: "" + +successors: """ +max Left exp1 +max Center exp2 +max Right exp3 +exp1 Left A +exp1 Center B +exp1 Right C +exp2 Left D +exp2 Center E +exp2 Right F +exp3 Left G +exp3 Center H +exp3 Right I +""" + +evaluation: """ +A 3.0 +B 12.0 +C 9.0 +D 2.0 +E 4.0 +F 6.0 +G 15.0 +H 6.0 +I 0.0 +""" diff --git a/test_cases/q4/2-one-ghost-3level.solution b/test_cases/q4/2-one-ghost-3level.solution new file mode 100644 index 0000000..bde5c83 --- /dev/null +++ b/test_cases/q4/2-one-ghost-3level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/2-one-ghost-3level.test. +action: "Left" +generated: "a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7 d8" diff --git a/test_cases/q4/2-one-ghost-3level.test b/test_cases/q4/2-one-ghost-3level.test new file mode 100644 index 0000000..5778a1d --- /dev/null +++ b/test_cases/q4/2-one-ghost-3level.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 + 3 9 10 6 4 7 0 5 + +a - max +b - exp +c - max +""" +num_agents: "2" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +""" + +evaluation: """ +d1 3.0 +d2 9.0 +d3 10.0 +d4 6.0 +d5 4.0 +d6 7.0 +d7 0.0 +d8 5.0 +""" diff --git a/test_cases/q4/3-one-ghost-4level.solution b/test_cases/q4/3-one-ghost-4level.solution new file mode 100644 index 0000000..4ba2b47 --- /dev/null +++ b/test_cases/q4/3-one-ghost-4level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/3-one-ghost-4level.test. +action: "Right" +generated: "A B C D E F G H I J K L M N O P a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7 d8" diff --git a/test_cases/q4/3-one-ghost-4level.test b/test_cases/q4/3-one-ghost-4level.test new file mode 100644 index 0000000..6490a48 --- /dev/null +++ b/test_cases/q4/3-one-ghost-4level.test @@ -0,0 +1,79 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 +/ \ / \ / \ / \ / \ / \ / \ / \ +A B C D E F G H I J K L M N O P +3 13 5 9 10 11 6 8 1 0 4 7 12 15 2 14 + +a - max +b - exp +c - max +d - exp +""" +num_agents: "2" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +""" + +evaluation: """ +A 3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 11.0 +G 6.0 +H 8.0 +I 1.0 +J 0.0 +K 4.0 +L 7.0 +M 12.0 +N 15.0 +O 2.0 +P 14.0 +""" diff --git a/test_cases/q4/4-two-ghosts-3level.solution b/test_cases/q4/4-two-ghosts-3level.solution new file mode 100644 index 0000000..6dbd664 --- /dev/null +++ b/test_cases/q4/4-two-ghosts-3level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/4-two-ghosts-3level.test. +action: "Left" +generated: "a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7 d8" diff --git a/test_cases/q4/4-two-ghosts-3level.test b/test_cases/q4/4-two-ghosts-3level.test new file mode 100644 index 0000000..d39bf1c --- /dev/null +++ b/test_cases/q4/4-two-ghosts-3level.test @@ -0,0 +1,52 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "3" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 + 3 9 10 6 4 7 0 5 + +a - max +b - exp +c - exp +""" +num_agents: "3" + +start_state: "a" +win_states: "d1 d2 d3 d4 d5 d6 d7 d8" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +""" + +evaluation: """ +d1 3.0 +d2 9.0 +d3 10.0 +d4 6.0 +d5 4.0 +d6 7.0 +d7 0.0 +d8 5.0 +""" diff --git a/test_cases/q4/5-two-ghosts-4level.solution b/test_cases/q4/5-two-ghosts-4level.solution new file mode 100644 index 0000000..caccbea --- /dev/null +++ b/test_cases/q4/5-two-ghosts-4level.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/5-two-ghosts-4level.test. +action: "Left" +generated: "A B C D E F G H I J K L M N O P a b1 b2 c1 c2 c3 c4 d1 d2 d3 d4 d5 d6 d7 d8" diff --git a/test_cases/q4/5-two-ghosts-4level.test b/test_cases/q4/5-two-ghosts-4level.test new file mode 100644 index 0000000..b2d2733 --- /dev/null +++ b/test_cases/q4/5-two-ghosts-4level.test @@ -0,0 +1,79 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "4" + +diagram: """ + /-----a------\ + / \ + / \ + b1 b2 + / \ / \ + c1 c2 c3 c4 + / \ / \ / \ / \ + d1 d2 d3 d4 d5 d6 d7 d8 +/ \ / \ / \ / \ / \ / \ / \ / \ +A B C D E F G H I J K L M N O P +3 13 5 9 10 11 6 8 1 0 4 7 12 15 2 14 + +a - max +b - exp +c - exp +d - max +""" +num_agents: "3" + +start_state: "a" +win_states: "A B C D E F G H I J K L M N O P" +lose_states: "" + +successors: """ +a Left b1 +a Right b2 +b1 Left c1 +b1 Right c2 +b2 Left c3 +b2 Right c4 +c1 Left d1 +c1 Right d2 +c2 Left d3 +c2 Right d4 +c3 Left d5 +c3 Right d6 +c4 Left d7 +c4 Right d8 +d1 Left A +d1 Right B +d2 Left C +d2 Right D +d3 Left E +d3 Right F +d4 Left G +d4 Right H +d5 Left I +d5 Right J +d6 Left K +d6 Right L +d7 Left M +d7 Right N +d8 Left O +d8 Right P +""" + +evaluation: """ +A 3.0 +B 13.0 +C 5.0 +D 9.0 +E 10.0 +F 11.0 +G 6.0 +H 8.0 +I 1.0 +J 0.0 +K 4.0 +L 7.0 +M 12.0 +N 15.0 +O 2.0 +P 14.0 +""" diff --git a/test_cases/q4/6-1a-check-depth-one-ghost.solution b/test_cases/q4/6-1a-check-depth-one-ghost.solution new file mode 100644 index 0000000..22aebdc --- /dev/null +++ b/test_cases/q4/6-1a-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/6-1a-check-depth-one-ghost.test. +action: "Left" +generated: "a b1 b2 b3 c1 c2 c3" diff --git a/test_cases/q4/6-1a-check-depth-one-ghost.test b/test_cases/q4/6-1a-check-depth-one-ghost.test new file mode 100644 index 0000000..4d36ea5 --- /dev/null +++ b/test_cases/q4/6-1a-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "1" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 1, the evaluation function is called at level c, +so Left should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q4/6-1b-check-depth-one-ghost.solution b/test_cases/q4/6-1b-check-depth-one-ghost.solution new file mode 100644 index 0000000..e34e3d3 --- /dev/null +++ b/test_cases/q4/6-1b-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/6-1b-check-depth-one-ghost.test. +action: "Center" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3" diff --git a/test_cases/q4/6-1b-check-depth-one-ghost.test b/test_cases/q4/6-1b-check-depth-one-ghost.test new file mode 100644 index 0000000..a63d167 --- /dev/null +++ b/test_cases/q4/6-1b-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "2" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 2, the evaluation function is called at level e, +so Center should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q4/6-1c-check-depth-one-ghost.solution b/test_cases/q4/6-1c-check-depth-one-ghost.solution new file mode 100644 index 0000000..cd33b5a --- /dev/null +++ b/test_cases/q4/6-1c-check-depth-one-ghost.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/6-1c-check-depth-one-ghost.test. +action: "Right" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3" diff --git a/test_cases/q4/6-1c-check-depth-one-ghost.test b/test_cases/q4/6-1c-check-depth-one-ghost.test new file mode 100644 index 0000000..84e78f0 --- /dev/null +++ b/test_cases/q4/6-1c-check-depth-one-ghost.test @@ -0,0 +1,83 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "3" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 10 c1 0 c2 c3 8 + | | | + 0 d1 0 d2 d3 8 + | | | + 0 e1 10 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + g1 g2 g3 + 0 0 8 + +a - max +b - min +c - max +d - min +e - max +f - min + +At depth 3, the evaluation function is called at level g, +so Right should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "2" + +start_state: "a" +win_states: "g1 g2 g3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 10.0 +c2 0.0 +c3 8.0 +d1 0.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 10.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 0.0 +g3 8.0 +""" + + diff --git a/test_cases/q4/6-2a-check-depth-two-ghosts.solution b/test_cases/q4/6-2a-check-depth-two-ghosts.solution new file mode 100644 index 0000000..0e9c9e9 --- /dev/null +++ b/test_cases/q4/6-2a-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/6-2a-check-depth-two-ghosts.test. +action: "Left" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3" diff --git a/test_cases/q4/6-2a-check-depth-two-ghosts.test b/test_cases/q4/6-2a-check-depth-two-ghosts.test new file mode 100644 index 0000000..36ecd4e --- /dev/null +++ b/test_cases/q4/6-2a-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "1" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 1, the evaluation function is called at level d, +so Left should be returned. If your algorithm is returning a +different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q4/6-2b-check-depth-two-ghosts.solution b/test_cases/q4/6-2b-check-depth-two-ghosts.solution new file mode 100644 index 0000000..3fcde21 --- /dev/null +++ b/test_cases/q4/6-2b-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/6-2b-check-depth-two-ghosts.test. +action: "Center" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3" diff --git a/test_cases/q4/6-2b-check-depth-two-ghosts.test b/test_cases/q4/6-2b-check-depth-two-ghosts.test new file mode 100644 index 0000000..d1b85b7 --- /dev/null +++ b/test_cases/q4/6-2b-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "2" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 2, the evaluation function is called at level g, +so Center should be returned. If your algorithm is returning +a different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q4/6-2c-check-depth-two-ghosts.solution b/test_cases/q4/6-2c-check-depth-two-ghosts.solution new file mode 100644 index 0000000..bad1cf9 --- /dev/null +++ b/test_cases/q4/6-2c-check-depth-two-ghosts.solution @@ -0,0 +1,3 @@ +# This is the solution file for test_cases/q4/6-2c-check-depth-two-ghosts.test. +action: "Right" +generated: "a b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3 g1 g2 g3 h1 h2 h3 i1 i2 i3 j1 j2 j3" diff --git a/test_cases/q4/6-2c-check-depth-two-ghosts.test b/test_cases/q4/6-2c-check-depth-two-ghosts.test new file mode 100644 index 0000000..6c4c9ea --- /dev/null +++ b/test_cases/q4/6-2c-check-depth-two-ghosts.test @@ -0,0 +1,110 @@ +class: "GraphGameTreeTest" +alg: "ExpectimaxAgent" +depth: "3" + +diagram: """ + a + /-/ | \--\ + / | \ + 0 b1 0 b2 b3 8 + | | | + 0 c1 0 c2 c3 8 + | | | + 10 d1 0 d2 d3 8 + | | | + 0 e1 0 e2 e3 8 + | | | + 0 f1 0 f2 f3 8 + | | | + 0 g1 10 g2 g3 8 + | | | + 0 h1 0 h2 h3 8 + | | | + 0 i1 0 i2 i3 8 + | | | + j1 j2 j3 + 0 0 8 + +a - max +b - min +c - min +d - max +e - min +f - min +g - max +h - min +i - min + +At depth 3, the evaluation function is called at level j, +so Right should be returned. If your algorithm is returning +a different action, check how you implemented your depth. +""" + +num_agents: "3" + +start_state: "a" +win_states: "j1 j2 j3" +lose_states: "" + +successors: """ +a Left b1 +a Center b2 +a Right b3 +b1 Center c1 +b2 Center c2 +b3 Center c3 +c1 Center d1 +c2 Center d2 +c3 Center d3 +d1 Center e1 +d2 Center e2 +d3 Center e3 +e1 Center f1 +e2 Center f2 +e3 Center f3 +f1 Center g1 +f2 Center g2 +f3 Center g3 +g1 Center h1 +g2 Center h2 +g3 Center h3 +h1 Center i1 +h2 Center i2 +h3 Center i3 +i1 Center j1 +i2 Center j2 +i3 Center j3 +""" + + +evaluation: """ +b1 0.0 +b2 0.0 +b3 8.0 +c1 0.0 +c2 0.0 +c3 8.0 +d1 10.0 +d2 0.0 +d3 8.0 +e1 0.0 +e2 0.0 +e3 8.0 +f1 0.0 +f2 0.0 +f3 8.0 +g1 0.0 +g2 10.0 +g3 8.0 +h1 0.0 +h2 0.0 +h3 8.0 +i1 0.0 +i2 0.0 +i3 8.0 +j1 0.0 +j2 0.0 +j3 8.0 +""" + + diff --git a/test_cases/q4/7-pacman-game.solution b/test_cases/q4/7-pacman-game.solution new file mode 100644 index 0000000..ecc544b --- /dev/null +++ b/test_cases/q4/7-pacman-game.solution @@ -0,0 +1,444 @@ +optimalActions: """ +[[["West", "East"], 59], [["West", "East"], 35]] +[[["West"], 190], [["West"], 127]] +[[["West"], 190], [["West"], 135]] +[[["West", "North"], 120], [["West", "North"], 82]] +[[["West"], 77], [["West"], 57]] +[[["West", "North"], 143], [["West", "North"], 97]] +[[["West"], 155], [["West"], 110]] +[[["West"], 40], [["West"], 27]] +[[["North"], 64], [["North"], 43]] +[[["North"], 85], [["North"], 57]] +[[["North"], 106], [["North"], 71]] +[[["North"], 97], [["North"], 65]] +[[["East"], 154], [["East"], 103]] +[[["Stop"], 130], [["West"], 85]] +[[["West"], 30], [["West"], 17]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["North"], 29], [["North"], 18]] +[[["North"], 50], [["North"], 31]] +[[["West"], 55], [["West"], 36]] +[[["East"], 29], [["East"], 16]] +[[["North"], 89], [["North"], 61]] +[[["East", "North"], 161], [["East", "North"], 121]] +[[["East", "North"], 221], [["East", "North"], 166]] +[[["North", "South"], 105], [["North", "South"], 77]] +[[["West"], 69], [["West"], 51]] +[[["West"], 94], [["West"], 69]] +[[["West", "Stop"], 57], [["West"], 42]] +[[["West", "Stop", "East"], 69], [["West", "East"], 49]] +[[["West", "Stop", "East"], 61], [["West", "East"], 41]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 28], [["East", "South"], 19]] +[[["Stop", "East", "South"], 34], [["East", "South"], 23]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 55], [["East", "South"], 37]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 85], [["East", "South"], 57]] +[[["Stop", "East", "South"], 64], [["East", "South"], 43]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 61], [["East", "South"], 41]] +[[["Stop", "East", "South"], 85], [["East", "South"], 57]] +[[["Stop", "East", "South"], 102], [["East", "South"], 67]] +[[["Stop", "South"], 23], [["South"], 13]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East", "North"], 29], [["East", "North"], 18]] +[[["East"], 38], [["East"], 22]] +[[["North"], 29], [["North"], 18]] +[[["North"], 38], [["North"], 22]] +[[["East"], 33], [["East"], 22]] +[[["East"], 37], [["East"], 18]] +[[["East"], 18], [["East"], 12]] +[[["East"], 37], [["East"], 26]] +[[["East"], 69], [["East"], 41]] +[[["East"], 56], [["East"], 26]] +[[["East"], 44], [["East"], 29]] +[[["North", "South"], 83], [["North", "South"], 52]] +[[["East", "North"], 121], [["East", "North"], 74]] +[[["East", "North"], 97], [["East", "North"], 73]] +[[["North", "South"], 173], [["North", "South"], 130]] +[[["West", "East"], 90], [["West", "East"], 66]] +[[["West", "Stop", "East"], 161], [["West", "East"], 118]] +[[["Stop", "East", "South"], 58], [["East", "South"], 43]] +[[["Stop", "East"], 120], [["East"], 85]] +[[["East"], 78], [["East"], 45]] +[[["West"], 77], [["West"], 42]] +[[["South"], 83], [["South"], 48]] +[[["South"], 49], [["South"], 37]] +[[["South"], 185], [["South"], 104]] +[[["South"], 68], [["South"], 41]] +[[["West"], 30], [["West"], 18]] +[[["West"], 56], [["West"], 29]] +[[["West"], 14], [["West"], 10]] +[[["West"], 20], [["West"], 14]] +[[["West"], 13], [["West"], 9]] +[[["West"], 13], [["West"], 9]] +[[["West"], 16], [["West"], 12]] +[[["West", "North"], 30], [["West", "North"], 20]] +[[["West"], 38], [["West"], 23]] +[[["West", "Stop", "East", "North"], 70], [["West", "East", "North"], 46]] +[[["West", "Stop", "East"], 128], [["West", "East"], 89]] +[[["West", "Stop", "East"], 31], [["West", "East"], 20]] +[[["Stop", "East", "North"], 69], [["East", "North"], 45]] +[[["Stop", "North"], 58], [["North"], 31]] +[[["North"], 34], [["North"], 19]] +[[["North"], 30], [["North"], 17]] +[[["North"], 19], [["North"], 11]] +[[["North"], 34], [["North"], 19]] +[[["East"], 30], [["East"], 17]] +[[["East"], 19], [["East"], 11]] +[[["East"], 44], [["East"], 29]] +[[["East", "South"], 87], [["East", "South"], 60]] +[[["East", "South"], 108], [["East", "South"], 62]] +[[["South"], 120], [["South"], 61]] +[[["North", "South"], 209], [["North", "South"], 132]] +[[["West"], 108], [["West"], 60]] +[[["West", "Stop", "East", "South"], 83], [["West", "East", "South"], 61]] +[[["West", "Stop", "East", "South"], 90], [["West", "East", "South"], 66]] +[[["West", "Stop", "East"], 134], [["West", "East"], 95]] +[[["West", "Stop", "East"], 82], [["West", "East"], 55]] +[[["Stop", "East", "South"], 142], [["East", "South"], 95]] +[[["Stop", "East", "South"], 98], [["East", "South"], 65]] +[[["Stop", "East", "South"], 128], [["East", "South"], 86]] +[[["Stop", "East", "South"], 82], [["East", "South"], 55]] +[[["Stop", "East", "South"], 85], [["East", "South"], 57]] +[[["Stop", "East", "South"], 190], [["East", "South"], 127]] +[[["Stop", "East", "South"], 158], [["East", "South"], 103]] +[[["Stop", "South"], 50], [["South"], 27]] +[[["South"], 30], [["South"], 17]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["South"], 15], [["South"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East", "North"], 29], [["East", "North"], 18]] +[[["East"], 37], [["East"], 22]] +[[["East", "North"], 41], [["East", "North"], 24]] +[[["East"], 59], [["East"], 29]] +[[["East"], 19], [["East"], 11]] +[[["East"], 26], [["East"], 15]] +[[["East"], 15], [["East"], 9]] +[[["East"], 15], [["East"], 9]] +[[["East"], 18], [["East"], 12]] +[[["East"], 29], [["East"], 18]] +[[["East"], 37], [["East"], 22]] +[[["East", "North"], 41], [["East", "North"], 24]] +[[["East"], 59], [["East"], 29]] +[[["East"], 19], [["East"], 11]] +[[["North"], 26], [["North"], 15]] +[[["North"], 19], [["North"], 11]] +[[["North"], 30], [["North"], 17]] +[[["North"], 34], [["North"], 19]] +[[["West"], 34], [["West"], 19]] +[[["West"], 25], [["West"], 13]] +[[["West", "Stop", "East"], 7], [["West", "East"], 3]] +""" +altDepthActions: """ +[["West", "East"], ["West", "East"], ["West", "East"], ["West", "East"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["East"], ["East"], ["East"], ["East"]] +[["West", "Stop"], ["West"], ["Stop"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["West"], ["West"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"], ["East"], ["East"]] +[["North", "South"], ["North", "South"], ["North"], ["North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West", "Stop"], ["West"]] +[["West"], ["West"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"], ["Stop", "South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North", "South"], ["North", "South"], ["South"], ["South"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"], ["North"], ["North"]] +[["West", "East"], ["West", "East"], ["East"], ["East"]] +[["West"], ["West"], ["East"], ["East"]] +[["Stop", "East", "South"], ["East", "South"], ["East"], ["East"]] +[["Stop", "East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["West"], ["West"], ["West"], ["West"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["West", "East"], ["West", "East"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "North"], ["West", "North"], ["West", "North"], ["West", "North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East", "North"], ["West", "East", "North"], ["West", "Stop", "East", "North"], ["West", "East", "North"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "North"], ["East", "North"], ["Stop", "East", "North"], ["East", "North"]] +[["Stop", "North"], ["North"], ["Stop", "North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "South"], ["East", "South"], ["East", "South"], ["East", "South"]] +[["East", "South"], ["East", "South"], ["East", "South"], ["East", "South"]] +[["South"], ["South"], ["South"], ["South"]] +[["North", "South"], ["North", "South"], ["North", "South"], ["North", "South"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"], ["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"], ["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"], ["Stop", "South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["South"], ["South"], ["South"], ["South"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East", "North"], ["East", "North"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East", "North"], ["East", "North"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["East"], ["East"], ["East"], ["East"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["North"], ["North"], ["North"], ["North"]] +[["West"], ["West"], ["West"], ["West"]] +[["West"], ["West"], ["West"], ["West"]] +[["West", "Stop", "East"], ["West", "East"], ["West", "Stop", "East"], ["West", "East"]] +""" +partialPlyBugActions: """ +[["West", "East"], ["West", "East"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["Stop"], ["West"]] +[["West"], ["West"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["West"], ["West"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "Stop"], ["West"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North", "South"], ["North", "South"]] +[["East", "North"], ["East", "North"]] +[["East", "North"], ["East", "North"]] +[["North", "South"], ["North", "South"]] +[["West", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East"], ["East"]] +[["East"], ["East"]] +[["West"], ["West"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "North"], ["West", "North"]] +[["West"], ["West"]] +[["West", "Stop", "East", "North"], ["West", "East", "North"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "North"], ["East", "North"]] +[["Stop", "North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "South"], ["East", "South"]] +[["East", "South"], ["East", "South"]] +[["South"], ["South"]] +[["North", "South"], ["North", "South"]] +[["West"], ["West"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East", "South"], ["West", "East", "South"]] +[["West", "Stop", "East"], ["West", "East"]] +[["West", "Stop", "East"], ["West", "East"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "East", "South"], ["East", "South"]] +[["Stop", "South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["South"], ["South"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["East", "North"], ["East", "North"]] +[["East"], ["East"]] +[["East"], ["East"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["North"], ["North"]] +[["West"], ["West"]] +[["West"], ["West"]] +[["West", "Stop", "East"], ["West", "East"]] +""" diff --git a/test_cases/q4/7-pacman-game.test b/test_cases/q4/7-pacman-game.test new file mode 100644 index 0000000..435cf2f --- /dev/null +++ b/test_cases/q4/7-pacman-game.test @@ -0,0 +1,19 @@ +class: "PacmanGameTreeTest" +alg: "ExpectimaxAgent" +seed: "0" +depth: "2" +max_points: "4" + +# The following specifies the layout to be used +layoutName: "smallClassic" +layout: """ +%%%%%%%%%%%%%%%%%%%% +%......%G G%......% +%.%%...%% %%...%%.% +%.%o.%........%.o%.% +%.%%.%.%%%%%%.%.%%.% +%........P.........% +%%%%%%%%%%%%%%%%%%%% +""" + + diff --git a/test_cases/q4/CONFIG b/test_cases/q4/CONFIG index b24223d..a5adc3f 100644 --- a/test_cases/q4/CONFIG +++ b/test_cases/q4/CONFIG @@ -1,2 +1,2 @@ +max_points: "5" class: "PassAllTestsQuestion" -max_points: "3" \ No newline at end of file diff --git a/test_cases/q4/astar_0.solution b/test_cases/q4/astar_0.solution deleted file mode 100644 index 459cadd..0000000 --- a/test_cases/q4/astar_0.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q4/astar_0.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "Right Down Down" -expanded_states: "A B D C G" -rev_solution: "Right Down Down" -rev_expanded_states: "A B D C G" diff --git a/test_cases/q4/astar_0.test b/test_cases/q4/astar_0.test deleted file mode 100644 index 9b3b539..0000000 --- a/test_cases/q4/astar_0.test +++ /dev/null @@ -1,39 +0,0 @@ -class: "GraphSearchTest" -algorithm: "aStarSearch" - -diagram: """ - C - ^ - | 2 - 2 V 4 -*A <----> B -----> [H] - | - 1.5 V 2.5 - G <----- D -----> E - | - 2 | - V - [F] - -A is the start state, F and H is the goal. Arrows mark possible state -transitions. The number next to the arrow is the cost of that transition. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: H F -A Right B 2.0 -B Right H 4.0 -B Down D 1.0 -B Up C 2.0 -B Left A 2.0 -C Down B 2.0 -D Right E 2.5 -D Down F 2.0 -D Left G 1.5 -""" - diff --git a/test_cases/q4/astar_1_graph_heuristic.solution b/test_cases/q4/astar_1_graph_heuristic.solution deleted file mode 100644 index 7767c27..0000000 --- a/test_cases/q4/astar_1_graph_heuristic.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q4/astar_1_graph_heuristic.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "0 0 2" -expanded_states: "S A D C" -rev_solution: "0 0 2" -rev_expanded_states: "S A D C" diff --git a/test_cases/q4/astar_1_graph_heuristic.test b/test_cases/q4/astar_1_graph_heuristic.test deleted file mode 100644 index b5afd79..0000000 --- a/test_cases/q4/astar_1_graph_heuristic.test +++ /dev/null @@ -1,54 +0,0 @@ -class: "GraphSearchTest" -algorithm: "aStarSearch" - -diagram: """ - 2 3 2 - S --- A --- C ---> G - | \ / ^ -3 | \ 5 / 1 / - | \ / / - B --- D -------/ - 4 5 - -S is the start state, G is the goal. Arrows mark possible state -transitions. The number next to the arrow is the cost of that transition. - -The heuristic value of each state is: - S 6.0 - A 2.5 - B 5.25 - C 1.125 - D 1.0625 - G 0 -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: S -goal_states: G -S 0 A 2.0 -S 1 B 3.0 -S 2 D 5.0 -A 0 C 3.0 -A 1 S 2.0 -B 0 D 4.0 -B 1 S 3.0 -C 0 A 3.0 -C 1 D 1.0 -C 2 G 2.0 -D 0 B 4.0 -D 1 C 1.0 -D 2 G 5.0 -D 3 S 5.0 -""" -heuristic: """ -S 6.0 -A 2.5 -B 5.25 -C 1.125 -D 1.0625 -G 0 -""" diff --git a/test_cases/q4/astar_2_manhattan.solution b/test_cases/q4/astar_2_manhattan.solution deleted file mode 100644 index 65bf5f5..0000000 --- a/test_cases/q4/astar_2_manhattan.solution +++ /dev/null @@ -1,22 +0,0 @@ -# This is the solution file for test_cases/q4/astar_2_manhattan.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -# Number of nodes expanded must be with a factor of 1.1 of the numbers below. -solution: """ -West West West West West West West West West South South East East -South South South West West West North West West West West South South -South East East East East East East East South South South South South -South South West West West West West West West West West West West -West West West West West West South West West West West West West West -West West -""" -expanded_nodes: "221" -rev_solution: """ -West West West West West West West West West South South East East -South South South West West West North West West West West South South -South East East East East East East East South South South South South -South South West West West West West West West West West West West -West West West West West West South West West West West West West West -West West -""" -rev_expanded_nodes: "221" diff --git a/test_cases/q4/astar_2_manhattan.test b/test_cases/q4/astar_2_manhattan.test deleted file mode 100644 index e936195..0000000 --- a/test_cases/q4/astar_2_manhattan.test +++ /dev/null @@ -1,27 +0,0 @@ -class: "PacmanSearchTest" -algorithm: "aStarSearch" - -# The following specifies the layout to be used -layoutName: "mediumMaze" -layout: """ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% P% -% %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% % -% %% % % %%%%%%% %% % -% %% % % % % %%%% %%%%%%%%% %% %%%%% -% %% % % % % %% %% % -% %% % % % % % %%%% %%% %%%%%% % -% % % % % % %% %%%%%%%% % -% %% % % %%%%%%%% %% %% %%%%% -% %% % %% %%%%%%%%% %% % -% %%%%%% %%%%%%% %% %%%%%% % -%%%%%% % %%%% %% % % -% %%%%%% %%%%% % %% %% %%%%% -% %%%%%% % %%%%% %% % -% %%%%%% %%%%%%%%%%% %% %% % -%%%%%%%%%% %%%%%% % -%. %%%%%%%%%%%%%%%% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -""" -leewayFactor: "1.1" -heuristic: "manhattanHeuristic" diff --git a/test_cases/q4/astar_3_goalAtDequeue.solution b/test_cases/q4/astar_3_goalAtDequeue.solution deleted file mode 100644 index edb3502..0000000 --- a/test_cases/q4/astar_3_goalAtDequeue.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q4/astar_3_goalAtDequeue.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->B 0:B->C 0:C->G" -expanded_states: "A B C" -rev_solution: "1:A->B 0:B->C 0:C->G" -rev_expanded_states: "A B C" diff --git a/test_cases/q4/astar_3_goalAtDequeue.test b/test_cases/q4/astar_3_goalAtDequeue.test deleted file mode 100644 index c4d1903..0000000 --- a/test_cases/q4/astar_3_goalAtDequeue.test +++ /dev/null @@ -1,29 +0,0 @@ -class: "GraphSearchTest" -algorithm: "aStarSearch" - -diagram: """ - 1 1 1 -*A ---> B ---> C ---> [G] - | ^ - | 10 | - \---------------------/ - -A is the start state, G is the goal. Arrows mark possible state -transitions. The number next to the arrow is the cost of that transition. - -If you fail this test case, you may be incorrectly testing if a node is a goal -before adding it into the queue, instead of testing when you remove the node -from the queue. See the algorithm pseudocode in lecture. -""" - -graph: """ -start_state: A -goal_states: G -A 0:A->G G 10.0 -A 1:A->B B 1.0 -B 0:B->C C 1.0 -C 0:C->G G 1.0 -""" -# We only care about the solution, not the expansion order. -exactExpansionOrder: "False" - diff --git a/test_cases/q4/graph_backtrack.solution b/test_cases/q4/graph_backtrack.solution deleted file mode 100644 index fc51794..0000000 --- a/test_cases/q4/graph_backtrack.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q4/graph_backtrack.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->C 0:C->G" -expanded_states: "A B C D" -rev_solution: "1:A->C 0:C->G" -rev_expanded_states: "A B C D" diff --git a/test_cases/q4/graph_backtrack.test b/test_cases/q4/graph_backtrack.test deleted file mode 100644 index 84e0126..0000000 --- a/test_cases/q4/graph_backtrack.test +++ /dev/null @@ -1,32 +0,0 @@ -class: "GraphSearchTest" -algorithm: "aStarSearch" - -diagram: """ - B - ^ - | -*A --> C --> G - | - V - D - -A is the start state, G is the goal. Arrows mark -possible state transitions. This tests whether -you extract the sequence of actions correctly even -if your search backtracks. If you fail this, your -nodes are not correctly tracking the sequences of -actions required to reach them. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B B 1.0 -A 1:A->C C 2.0 -A 2:A->D D 4.0 -C 0:C->G G 8.0 -""" diff --git a/test_cases/q4/graph_manypaths.solution b/test_cases/q4/graph_manypaths.solution deleted file mode 100644 index 0caa767..0000000 --- a/test_cases/q4/graph_manypaths.solution +++ /dev/null @@ -1,7 +0,0 @@ -# This is the solution file for test_cases/q4/graph_manypaths.test. -# This solution is designed to support both right-to-left -# and left-to-right implementations. -solution: "1:A->C 0:C->D 1:D->F 0:F->G" -expanded_states: "A B1 C B2 D E1 F E2" -rev_solution: "1:A->C 0:C->D 1:D->F 0:F->G" -rev_expanded_states: "A B1 C B2 D E1 F E2" diff --git a/test_cases/q4/graph_manypaths.test b/test_cases/q4/graph_manypaths.test deleted file mode 100644 index 82fdf87..0000000 --- a/test_cases/q4/graph_manypaths.test +++ /dev/null @@ -1,39 +0,0 @@ -class: "GraphSearchTest" -algorithm: "aStarSearch" - -diagram: """ - B1 E1 - ^ \ ^ \ - / V / V -*A --> C --> D --> F --> [G] - \ ^ \ ^ - V / V / - B2 E2 - -A is the start state, G is the goal. Arrows mark -possible state transitions. This graph has multiple -paths to the goal, where nodes with the same state -are added to the fringe multiple times before they -are expanded. -""" -# The following section specifies the search problem and the solution. -# The graph is specified by first the set of start states, followed by -# the set of goal states, and lastly by the state transitions which are -# of the form: -# -graph: """ -start_state: A -goal_states: G -A 0:A->B1 B1 1.0 -A 1:A->C C 2.0 -A 2:A->B2 B2 4.0 -B1 0:B1->C C 8.0 -B2 0:B2->C C 16.0 -C 0:C->D D 32.0 -D 0:D->E1 E1 64.0 -D 1:D->F F 128.0 -D 2:D->E2 E2 256.0 -E1 0:E1->F F 512.0 -E2 0:E2->F F 1024.0 -F 0:F->G G 2048.0 -""" diff --git a/test_cases/q5/CONFIG b/test_cases/q5/CONFIG index e7c6582..df50d84 100644 --- a/test_cases/q5/CONFIG +++ b/test_cases/q5/CONFIG @@ -1,3 +1,2 @@ -class: "PassAllTestsQuestion" -max_points: "3" -depends: "q2" \ No newline at end of file +max_points: "6" +class: "PartialCreditQuestion" diff --git a/test_cases/q5/corner_tiny_corner.solution b/test_cases/q5/corner_tiny_corner.solution deleted file mode 100644 index 161bf15..0000000 --- a/test_cases/q5/corner_tiny_corner.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q5/corner_tiny_corner.test. -solution_length: "28" diff --git a/test_cases/q5/corner_tiny_corner.test b/test_cases/q5/corner_tiny_corner.test deleted file mode 100644 index 823bd47..0000000 --- a/test_cases/q5/corner_tiny_corner.test +++ /dev/null @@ -1,14 +0,0 @@ -class: "CornerProblemTest" - -layoutName: "tinyCorner" -layout: """ -%%%%%%%% -%. .% -% P % -% %%%% % -% % % -% % %%%% -%.% .% -%%%%%%%% -""" - diff --git a/test_cases/q5/grade-agent.solution b/test_cases/q5/grade-agent.solution new file mode 100644 index 0000000..55fcfc8 --- /dev/null +++ b/test_cases/q5/grade-agent.solution @@ -0,0 +1,2 @@ +# This is the solution file for test_cases/q5/grade-agent.test. +# File intentionally blank. diff --git a/test_cases/q5/grade-agent.test b/test_cases/q5/grade-agent.test new file mode 100644 index 0000000..4109586 --- /dev/null +++ b/test_cases/q5/grade-agent.test @@ -0,0 +1,18 @@ +class: "EvalAgentTest" + +agentName: "ExpectimaxAgent" +agentArgs: "evalFn=better" +layoutName: "smallClassic" +maxTime: "120" +numGames: "10" + +nonTimeoutMinimum: "0" +nonTimeoutThresholds: "10" + +scoreThresholds: "500 1000" + +winsMinimum: "1" +winsThresholds: "1 5 10" + +randomSeed: "0" +ghosts: "[RandomGhost(1)]" diff --git a/test_cases/q6/CONFIG b/test_cases/q6/CONFIG deleted file mode 100644 index b76e0eb..0000000 --- a/test_cases/q6/CONFIG +++ /dev/null @@ -1,3 +0,0 @@ -class: "Q6PartialCreditQuestion" -max_points: "3" -depends: "q4" \ No newline at end of file diff --git a/test_cases/q6/corner_sanity_1.solution b/test_cases/q6/corner_sanity_1.solution deleted file mode 100644 index 4385d9b..0000000 --- a/test_cases/q6/corner_sanity_1.solution +++ /dev/null @@ -1,7 +0,0 @@ -# In order for a heuristic to be admissible, the value -# of the heuristic must be less at each state than the -# true cost of the optimal path from that state to a goal. -cost: "8" -path: """ -North South South East East East North North -""" diff --git a/test_cases/q6/corner_sanity_1.test b/test_cases/q6/corner_sanity_1.test deleted file mode 100644 index 93379ac..0000000 --- a/test_cases/q6/corner_sanity_1.test +++ /dev/null @@ -1,12 +0,0 @@ -class: "CornerHeuristicSanity" -points: "1" - -# The following specifies the layout to be used -layout: """ -%%%%%% -%. .% -%P % -%. .% -%%%%%% -""" - diff --git a/test_cases/q6/corner_sanity_2.solution b/test_cases/q6/corner_sanity_2.solution deleted file mode 100644 index 1aebe8a..0000000 --- a/test_cases/q6/corner_sanity_2.solution +++ /dev/null @@ -1,7 +0,0 @@ -# In order for a heuristic to be admissible, the value -# of the heuristic must be less at each state than the -# true cost of the optimal path from that state to a goal. -cost: "8" -path: """ -West North North East East East South South -""" diff --git a/test_cases/q6/corner_sanity_2.test b/test_cases/q6/corner_sanity_2.test deleted file mode 100644 index 18184a8..0000000 --- a/test_cases/q6/corner_sanity_2.test +++ /dev/null @@ -1,12 +0,0 @@ -class: "CornerHeuristicSanity" -points: "1" - -# The following specifies the layout to be used -layout: """ -%%%%%% -%. .% -% %% % -%.P%.% -%%%%%% -""" - diff --git a/test_cases/q6/corner_sanity_3.solution b/test_cases/q6/corner_sanity_3.solution deleted file mode 100644 index c02dd57..0000000 --- a/test_cases/q6/corner_sanity_3.solution +++ /dev/null @@ -1,9 +0,0 @@ -# In order for a heuristic to be admissible, the value -# of the heuristic must be less at each state than the -# true cost of the optimal path from that state to a goal. -cost: "28" -path: """ -South South South West West West West East East East East East North -North North North North West West West South South South West West -North North North -""" diff --git a/test_cases/q6/corner_sanity_3.test b/test_cases/q6/corner_sanity_3.test deleted file mode 100644 index 8f30442..0000000 --- a/test_cases/q6/corner_sanity_3.test +++ /dev/null @@ -1,15 +0,0 @@ -class: "CornerHeuristicSanity" -points: "1" - -# The following specifies the layout to be used -layout: """ -%%%%%%%% -%.% .% -% % % % -% % %P % -% % % -%%%%% % -%. .% -%%%%%%%% -""" - diff --git a/test_cases/q6/medium_corners.solution b/test_cases/q6/medium_corners.solution deleted file mode 100644 index 913dc45..0000000 --- a/test_cases/q6/medium_corners.solution +++ /dev/null @@ -1,16 +0,0 @@ -# This solution file specifies the length of the optimal path -# as well as the thresholds on number of nodes expanded to be -# used in scoring. -cost: "106" -path: """ -North East East East East North North West West West West North North -North North North North North North West West West West South South -East East East East South South South South South South West West -South South South West West East East North North North East East East -East East East East East South South East East East East East North -North East East North North East East North North East East East East -South South South South East East North North East East South South -South South South North North North North North North North West West -North North East East North North -""" -thresholds: "2000 1600 1200" diff --git a/test_cases/q6/medium_corners.test b/test_cases/q6/medium_corners.test deleted file mode 100644 index dfa0a68..0000000 --- a/test_cases/q6/medium_corners.test +++ /dev/null @@ -1,19 +0,0 @@ -class: "CornerHeuristicPacman" - -# The following specifies the layout to be used -layout: """ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%. % % % %.% -% % % %%%%%% %%%%%%% % % -% % % % % % -%%%%% %%%%% %%% %% %%%%% % %%% -% % % % % % % % % -% %%% % % % %%%%%%%% %%% %%% % -% % %% % % % % -%%% % %%%%%%% %%%% %%% % % % % -% % %% % % % -% % %%%%% % %%%% % %%% %%% % % -% % % % % % %%% % -%. %P%%%%% % %%% % .% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -""" diff --git a/test_cases/q7/food_heuristic_1.solution b/test_cases/q7/food_heuristic_1.solution deleted file mode 100644 index 7a287f8..0000000 --- a/test_cases/q7/food_heuristic_1.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_1.test. -solution_cost: "0" diff --git a/test_cases/q7/food_heuristic_1.test b/test_cases/q7/food_heuristic_1.test deleted file mode 100644 index 7545a7a..0000000 --- a/test_cases/q7/food_heuristic_1.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 1" -layout: """ -%%%%%% -% % -% % -%P % -%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_10.solution b/test_cases/q7/food_heuristic_10.solution deleted file mode 100644 index 1917f05..0000000 --- a/test_cases/q7/food_heuristic_10.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_10.test. -solution_cost: "7" diff --git a/test_cases/q7/food_heuristic_10.test b/test_cases/q7/food_heuristic_10.test deleted file mode 100644 index 212c7bd..0000000 --- a/test_cases/q7/food_heuristic_10.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 10" -layout: """ -%%%%%%%% -% % -%. P .% -% % -%%%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_11.solution b/test_cases/q7/food_heuristic_11.solution deleted file mode 100644 index 11c3289..0000000 --- a/test_cases/q7/food_heuristic_11.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_11.test. -solution_cost: "8" diff --git a/test_cases/q7/food_heuristic_11.test b/test_cases/q7/food_heuristic_11.test deleted file mode 100644 index f5e6ed4..0000000 --- a/test_cases/q7/food_heuristic_11.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 11" -layout: """ -%%%%%%%% -% % -% P % -%. . .% -%%%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_12.solution b/test_cases/q7/food_heuristic_12.solution deleted file mode 100644 index 0edcc02..0000000 --- a/test_cases/q7/food_heuristic_12.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_12.test. -solution_cost: "1" diff --git a/test_cases/q7/food_heuristic_12.test b/test_cases/q7/food_heuristic_12.test deleted file mode 100644 index cc99a25..0000000 --- a/test_cases/q7/food_heuristic_12.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 12" -layout: """ -%%%%%%%% -% % -% P.% -% % -%%%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_13.solution b/test_cases/q7/food_heuristic_13.solution deleted file mode 100644 index c25d50b..0000000 --- a/test_cases/q7/food_heuristic_13.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_13.test. -solution_cost: "5" diff --git a/test_cases/q7/food_heuristic_13.test b/test_cases/q7/food_heuristic_13.test deleted file mode 100644 index 09d6f1e..0000000 --- a/test_cases/q7/food_heuristic_13.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 13" -layout: """ -%%%%%%%% -% % -%P. .% -% % -%%%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_14.solution b/test_cases/q7/food_heuristic_14.solution deleted file mode 100644 index e6cc475..0000000 --- a/test_cases/q7/food_heuristic_14.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_14.test. -solution_cost: "31" diff --git a/test_cases/q7/food_heuristic_14.test b/test_cases/q7/food_heuristic_14.test deleted file mode 100644 index 58982e3..0000000 --- a/test_cases/q7/food_heuristic_14.test +++ /dev/null @@ -1,19 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 14" -layout: """ -%%%%%%%%%% -% % -% ...%...% -% .%.%.%.% -% .%.%.%.% -% .%.%.%.% -% .%.%.%.% -% .%.%.%.% -%P.%...%.% -% % -%%%%%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_15.solution b/test_cases/q7/food_heuristic_15.solution deleted file mode 100644 index 4eca0f1..0000000 --- a/test_cases/q7/food_heuristic_15.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_15.test. -solution_cost: "21" diff --git a/test_cases/q7/food_heuristic_15.test b/test_cases/q7/food_heuristic_15.test deleted file mode 100644 index df605c1..0000000 --- a/test_cases/q7/food_heuristic_15.test +++ /dev/null @@ -1,32 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 15" -layout: """ -%%% -% % -% % -% % -% % -% % -%.% -%.% -% % -% % -% % -% % -% % -% % -% % -%.% -% % -%P% -% % -% % -% % -% % -%.% -%%% -""" - diff --git a/test_cases/q7/food_heuristic_16.solution b/test_cases/q7/food_heuristic_16.solution deleted file mode 100644 index 8d89992..0000000 --- a/test_cases/q7/food_heuristic_16.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_16.test. -solution_cost: "7" diff --git a/test_cases/q7/food_heuristic_16.test b/test_cases/q7/food_heuristic_16.test deleted file mode 100644 index 762b433..0000000 --- a/test_cases/q7/food_heuristic_16.test +++ /dev/null @@ -1,15 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 16" -layout: """ -%%%% -% .% -% % -%P % -% % -% .% -%%%% -""" - diff --git a/test_cases/q7/food_heuristic_17.solution b/test_cases/q7/food_heuristic_17.solution deleted file mode 100644 index 63a9a1b..0000000 --- a/test_cases/q7/food_heuristic_17.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_17.test. -solution_cost: "16" diff --git a/test_cases/q7/food_heuristic_17.test b/test_cases/q7/food_heuristic_17.test deleted file mode 100644 index a923f67..0000000 --- a/test_cases/q7/food_heuristic_17.test +++ /dev/null @@ -1,14 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 17" -layout: """ -%%%%%%%% -%.%....% -%.% %%.% -%.%P%%.% -%... .% -%%%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_2.solution b/test_cases/q7/food_heuristic_2.solution deleted file mode 100644 index ca5aba1..0000000 --- a/test_cases/q7/food_heuristic_2.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_2.test. -solution_cost: "0" diff --git a/test_cases/q7/food_heuristic_2.test b/test_cases/q7/food_heuristic_2.test deleted file mode 100644 index 956e75d..0000000 --- a/test_cases/q7/food_heuristic_2.test +++ /dev/null @@ -1,32 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 2" -layout: """ -%%% -% % -% % -% % -% % -% % -% % -% % -% % -% % -% % -% % -% % -% % -% % -% % -% % -%P% -% % -% % -% % -% % -% % -%%% -""" - diff --git a/test_cases/q7/food_heuristic_3.solution b/test_cases/q7/food_heuristic_3.solution deleted file mode 100644 index d1694b5..0000000 --- a/test_cases/q7/food_heuristic_3.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_3.test. -solution_cost: "0" diff --git a/test_cases/q7/food_heuristic_3.test b/test_cases/q7/food_heuristic_3.test deleted file mode 100644 index 250a8b1..0000000 --- a/test_cases/q7/food_heuristic_3.test +++ /dev/null @@ -1,15 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 3" -layout: """ -%%%% -% % -% % -%P % -% % -% % -%%%% -""" - diff --git a/test_cases/q7/food_heuristic_4.solution b/test_cases/q7/food_heuristic_4.solution deleted file mode 100644 index 6e1e82a..0000000 --- a/test_cases/q7/food_heuristic_4.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_4.test. -solution_cost: "0" diff --git a/test_cases/q7/food_heuristic_4.test b/test_cases/q7/food_heuristic_4.test deleted file mode 100644 index ed86a0c..0000000 --- a/test_cases/q7/food_heuristic_4.test +++ /dev/null @@ -1,14 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 4" -layout: """ -%%%%%%%% -% % % -% % %% % -% %P%% % -% % -%%%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_5.solution b/test_cases/q7/food_heuristic_5.solution deleted file mode 100644 index 779e9e6..0000000 --- a/test_cases/q7/food_heuristic_5.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_5.test. -solution_cost: "11" diff --git a/test_cases/q7/food_heuristic_5.test b/test_cases/q7/food_heuristic_5.test deleted file mode 100644 index 1f44c48..0000000 --- a/test_cases/q7/food_heuristic_5.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 5" -layout: """ -%%%%%% -%....% -%....% -%P...% -%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_6.solution b/test_cases/q7/food_heuristic_6.solution deleted file mode 100644 index 906b510..0000000 --- a/test_cases/q7/food_heuristic_6.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_6.test. -solution_cost: "5" diff --git a/test_cases/q7/food_heuristic_6.test b/test_cases/q7/food_heuristic_6.test deleted file mode 100644 index 01d7f32..0000000 --- a/test_cases/q7/food_heuristic_6.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 6" -layout: """ -%%%%%% -% .% -%.P..% -% % -%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_7.solution b/test_cases/q7/food_heuristic_7.solution deleted file mode 100644 index 5994a7b..0000000 --- a/test_cases/q7/food_heuristic_7.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_7.test. -solution_cost: "7" diff --git a/test_cases/q7/food_heuristic_7.test b/test_cases/q7/food_heuristic_7.test deleted file mode 100644 index b1db372..0000000 --- a/test_cases/q7/food_heuristic_7.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 7" -layout: """ -%%%%%%% -% .% -%. P..% -% % -%%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_8.solution b/test_cases/q7/food_heuristic_8.solution deleted file mode 100644 index 0e4fb08..0000000 --- a/test_cases/q7/food_heuristic_8.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_8.test. -solution_cost: "5" diff --git a/test_cases/q7/food_heuristic_8.test b/test_cases/q7/food_heuristic_8.test deleted file mode 100644 index b9430af..0000000 --- a/test_cases/q7/food_heuristic_8.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 8" -layout: """ -%%%%%% -% .% -% .% -%P .% -%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_9.solution b/test_cases/q7/food_heuristic_9.solution deleted file mode 100644 index 1470d9a..0000000 --- a/test_cases/q7/food_heuristic_9.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_9.test. -solution_cost: "6" diff --git a/test_cases/q7/food_heuristic_9.test b/test_cases/q7/food_heuristic_9.test deleted file mode 100644 index 799b41d..0000000 --- a/test_cases/q7/food_heuristic_9.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "HeuristicTest" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "Test 9" -layout: """ -%%%%%% -% %. % -% %%.% -%P. .% -%%%%%% -""" - diff --git a/test_cases/q7/food_heuristic_grade_tricky.solution b/test_cases/q7/food_heuristic_grade_tricky.solution deleted file mode 100644 index cd6fd7d..0000000 --- a/test_cases/q7/food_heuristic_grade_tricky.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q7/food_heuristic_grade_tricky.test. -# File intentionally blank. diff --git a/test_cases/q7/food_heuristic_grade_tricky.test b/test_cases/q7/food_heuristic_grade_tricky.test deleted file mode 100644 index 081fb0d..0000000 --- a/test_cases/q7/food_heuristic_grade_tricky.test +++ /dev/null @@ -1,19 +0,0 @@ -class: "HeuristicGrade" - -heuristic: "foodHeuristic" -searchProblemClass: "FoodSearchProblem" -layoutName: "trickySearch" -layout: """ -%%%%%%%%%%%%%%%%%%%% -%. ..% % -%.%%.%%.%%.%%.%% % % -% P % % -%%%%%%%%%%%%%%%%%% % -%..... % -%%%%%%%%%%%%%%%%%%%% -""" -# One point always, an extra point for each -# threshold passed. -basePoints: "1" -gradingThresholds: "15000 12000 9000 7000" - diff --git a/test_cases/q8/CONFIG b/test_cases/q8/CONFIG deleted file mode 100644 index b24223d..0000000 --- a/test_cases/q8/CONFIG +++ /dev/null @@ -1,2 +0,0 @@ -class: "PassAllTestsQuestion" -max_points: "3" \ No newline at end of file diff --git a/test_cases/q8/closest_dot_1.solution b/test_cases/q8/closest_dot_1.solution deleted file mode 100644 index 300fc25..0000000 --- a/test_cases/q8/closest_dot_1.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_1.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_1.test b/test_cases/q8/closest_dot_1.test deleted file mode 100644 index 672989f..0000000 --- a/test_cases/q8/closest_dot_1.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 1" -layout: """ -%%%%%% -%....% -%....% -%P...% -%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_10.solution b/test_cases/q8/closest_dot_10.solution deleted file mode 100644 index 174b5dd..0000000 --- a/test_cases/q8/closest_dot_10.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_10.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_10.test b/test_cases/q8/closest_dot_10.test deleted file mode 100644 index b1e0f33..0000000 --- a/test_cases/q8/closest_dot_10.test +++ /dev/null @@ -1,17 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 10" -layout: """ -%%%%%%%%%% -% % -% ...%...% -% .%.%.%.% -% .%.%.%.% -% .%.%.%.% -% .%.%.%.% -% .%.%.%.% -%P.%...%.% -% % -%%%%%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_11.solution b/test_cases/q8/closest_dot_11.solution deleted file mode 100644 index 80bbe38..0000000 --- a/test_cases/q8/closest_dot_11.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_11.test. -solution_length: "2" diff --git a/test_cases/q8/closest_dot_11.test b/test_cases/q8/closest_dot_11.test deleted file mode 100644 index 0310a1e..0000000 --- a/test_cases/q8/closest_dot_11.test +++ /dev/null @@ -1,30 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 11" -layout: """ -%%% -% % -% % -% % -% % -% % -%.% -%.% -% % -% % -% % -% % -% % -% % -% % -%.% -% % -%P% -% % -% % -% % -% % -%.% -%%% -""" - diff --git a/test_cases/q8/closest_dot_12.solution b/test_cases/q8/closest_dot_12.solution deleted file mode 100644 index 6f38bcb..0000000 --- a/test_cases/q8/closest_dot_12.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_12.test. -solution_length: "3" diff --git a/test_cases/q8/closest_dot_12.test b/test_cases/q8/closest_dot_12.test deleted file mode 100644 index a17b628..0000000 --- a/test_cases/q8/closest_dot_12.test +++ /dev/null @@ -1,13 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 12" -layout: """ -%%%% -% .% -% % -%P % -% % -% .% -%%%% -""" - diff --git a/test_cases/q8/closest_dot_13.solution b/test_cases/q8/closest_dot_13.solution deleted file mode 100644 index 7afa908..0000000 --- a/test_cases/q8/closest_dot_13.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_13.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_13.test b/test_cases/q8/closest_dot_13.test deleted file mode 100644 index 87c423d..0000000 --- a/test_cases/q8/closest_dot_13.test +++ /dev/null @@ -1,12 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 13" -layout: """ -%%%%%%%% -%.%....% -%.% %%.% -%.%P%%.% -%... .% -%%%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_2.solution b/test_cases/q8/closest_dot_2.solution deleted file mode 100644 index 16d75de..0000000 --- a/test_cases/q8/closest_dot_2.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_2.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_2.test b/test_cases/q8/closest_dot_2.test deleted file mode 100644 index 4b59602..0000000 --- a/test_cases/q8/closest_dot_2.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 2" -layout: """ -%%%%%% -% .% -%.P..% -% % -%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_3.solution b/test_cases/q8/closest_dot_3.solution deleted file mode 100644 index cbd5974..0000000 --- a/test_cases/q8/closest_dot_3.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_3.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_3.test b/test_cases/q8/closest_dot_3.test deleted file mode 100644 index aa2a3af..0000000 --- a/test_cases/q8/closest_dot_3.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 3" -layout: """ -%%%%%%% -% .% -%. P..% -% % -%%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_4.solution b/test_cases/q8/closest_dot_4.solution deleted file mode 100644 index ca520b5..0000000 --- a/test_cases/q8/closest_dot_4.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_4.test. -solution_length: "3" diff --git a/test_cases/q8/closest_dot_4.test b/test_cases/q8/closest_dot_4.test deleted file mode 100644 index 8499f6d..0000000 --- a/test_cases/q8/closest_dot_4.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 4" -layout: """ -%%%%%% -% .% -% .% -%P .% -%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_5.solution b/test_cases/q8/closest_dot_5.solution deleted file mode 100644 index 5c526a2..0000000 --- a/test_cases/q8/closest_dot_5.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_5.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_5.test b/test_cases/q8/closest_dot_5.test deleted file mode 100644 index dfaee3d..0000000 --- a/test_cases/q8/closest_dot_5.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 5" -layout: """ -%%%%%% -% %. % -% %%.% -%P. .% -%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_6.solution b/test_cases/q8/closest_dot_6.solution deleted file mode 100644 index b06468a..0000000 --- a/test_cases/q8/closest_dot_6.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_6.test. -solution_length: "2" diff --git a/test_cases/q8/closest_dot_6.test b/test_cases/q8/closest_dot_6.test deleted file mode 100644 index bc50c57..0000000 --- a/test_cases/q8/closest_dot_6.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 6" -layout: """ -%%%%%%%% -% % -%. P .% -% % -%%%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_7.solution b/test_cases/q8/closest_dot_7.solution deleted file mode 100644 index 3231b28..0000000 --- a/test_cases/q8/closest_dot_7.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_7.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_7.test b/test_cases/q8/closest_dot_7.test deleted file mode 100644 index 746e89a..0000000 --- a/test_cases/q8/closest_dot_7.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 7" -layout: """ -%%%%%%%% -% % -% P % -%. . .% -%%%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_8.solution b/test_cases/q8/closest_dot_8.solution deleted file mode 100644 index 646e621..0000000 --- a/test_cases/q8/closest_dot_8.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_8.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_8.test b/test_cases/q8/closest_dot_8.test deleted file mode 100644 index c266ae1..0000000 --- a/test_cases/q8/closest_dot_8.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 8" -layout: """ -%%%%%%%% -% % -% P.% -% % -%%%%%%%% -""" - diff --git a/test_cases/q8/closest_dot_9.solution b/test_cases/q8/closest_dot_9.solution deleted file mode 100644 index 6c94aa5..0000000 --- a/test_cases/q8/closest_dot_9.solution +++ /dev/null @@ -1,2 +0,0 @@ -# This is the solution file for test_cases/q8/closest_dot_9.test. -solution_length: "1" diff --git a/test_cases/q8/closest_dot_9.test b/test_cases/q8/closest_dot_9.test deleted file mode 100644 index da078de..0000000 --- a/test_cases/q8/closest_dot_9.test +++ /dev/null @@ -1,11 +0,0 @@ -class: "ClosestDotTest" - -layoutName: "Test 9" -layout: """ -%%%%%%%% -% % -%P. .% -% % -%%%%%%%% -""" - diff --git a/textDisplay.py b/textDisplay.py index 8e25a46..b39fd9e 100644 --- a/textDisplay.py +++ b/textDisplay.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -13,18 +13,19 @@ import time -try: +try: import pacman except: pass DRAW_EVERY = 1 -SLEEP_TIME = 0 # This can be overwritten by __init__ +SLEEP_TIME = 0 # This can be overwritten by __init__ DISPLAY_MOVES = False -QUIET = False # Supresses output +QUIET = False # Supresses output + class NullGraphics: - def initialize(self, state, isBlue = False): + def initialize(self, state, isBlue=False): pass def update(self, state): @@ -45,13 +46,14 @@ class NullGraphics: def finish(self): pass + class PacmanGraphics: def __init__(self, speed=None): if speed != None: global SLEEP_TIME SLEEP_TIME = speed - def initialize(self, state, isBlue = False): + def initialize(self, state, isBlue=False): self.draw(state) self.pause() self.turn = 0 @@ -63,8 +65,10 @@ class PacmanGraphics: if self.agentCounter == 0: self.turn += 1 if DISPLAY_MOVES: - ghosts = [pacman.nearestPoint(state.getGhostPosition(i)) for i in range(1, numAgents)] - print("%4d) P: %-8s" % (self.turn, str(pacman.nearestPoint(state.getPacmanPosition()))),'| Score: %-5d' % state.score,'| Ghosts:', ghosts) + ghosts = [pacman.nearestPoint( + state.getGhostPosition(i)) for i in range(1, numAgents)] + print("%4d) P: %-8s" % (self.turn, str(pacman.nearestPoint(state.getPacmanPosition()))), + '| Score: %-5d' % state.score, '| Ghosts:', ghosts) if self.turn % DRAW_EVERY == 0: self.draw(state) self.pause() diff --git a/util.py b/util.py index d81667f..4bf3e1e 100644 --- a/util.py +++ b/util.py @@ -4,7 +4,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -18,7 +18,7 @@ # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. -# +# # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). @@ -28,114 +28,119 @@ import sys import inspect -import heapq, random +import heapq +import random +import io class FixedRandom: def __init__(self): - fixedState = (3, (2147483648, 507801126, 683453281, 310439348, 2597246090, \ - 2209084787, 2267831527, 979920060, 3098657677, 37650879, 807947081, 3974896263, \ - 881243242, 3100634921, 1334775171, 3965168385, 746264660, 4074750168, 500078808, \ - 776561771, 702988163, 1636311725, 2559226045, 157578202, 2498342920, 2794591496, \ - 4130598723, 496985844, 2944563015, 3731321600, 3514814613, 3362575829, 3038768745, \ - 2206497038, 1108748846, 1317460727, 3134077628, 988312410, 1674063516, 746456451, \ - 3958482413, 1857117812, 708750586, 1583423339, 3466495450, 1536929345, 1137240525, \ - 3875025632, 2466137587, 1235845595, 4214575620, 3792516855, 657994358, 1241843248, \ - 1695651859, 3678946666, 1929922113, 2351044952, 2317810202, 2039319015, 460787996, \ - 3654096216, 4068721415, 1814163703, 2904112444, 1386111013, 574629867, 2654529343, \ - 3833135042, 2725328455, 552431551, 4006991378, 1331562057, 3710134542, 303171486, \ - 1203231078, 2670768975, 54570816, 2679609001, 578983064, 1271454725, 3230871056, \ - 2496832891, 2944938195, 1608828728, 367886575, 2544708204, 103775539, 1912402393, \ - 1098482180, 2738577070, 3091646463, 1505274463, 2079416566, 659100352, 839995305, \ - 1696257633, 274389836, 3973303017, 671127655, 1061109122, 517486945, 1379749962, \ - 3421383928, 3116950429, 2165882425, 2346928266, 2892678711, 2936066049, 1316407868, \ - 2873411858, 4279682888, 2744351923, 3290373816, 1014377279, 955200944, 4220990860, \ - 2386098930, 1772997650, 3757346974, 1621616438, 2877097197, 442116595, 2010480266, \ - 2867861469, 2955352695, 605335967, 2222936009, 2067554933, 4129906358, 1519608541, \ - 1195006590, 1942991038, 2736562236, 279162408, 1415982909, 4099901426, 1732201505, \ - 2934657937, 860563237, 2479235483, 3081651097, 2244720867, 3112631622, 1636991639, \ - 3860393305, 2312061927, 48780114, 1149090394, 2643246550, 1764050647, 3836789087, \ - 3474859076, 4237194338, 1735191073, 2150369208, 92164394, 756974036, 2314453957, \ - 323969533, 4267621035, 283649842, 810004843, 727855536, 1757827251, 3334960421, \ - 3261035106, 38417393, 2660980472, 1256633965, 2184045390, 811213141, 2857482069, \ - 2237770878, 3891003138, 2787806886, 2435192790, 2249324662, 3507764896, 995388363, \ - 856944153, 619213904, 3233967826, 3703465555, 3286531781, 3863193356, 2992340714, \ - 413696855, 3865185632, 1704163171, 3043634452, 2225424707, 2199018022, 3506117517, \ - 3311559776, 3374443561, 1207829628, 668793165, 1822020716, 2082656160, 1160606415, \ - 3034757648, 741703672, 3094328738, 459332691, 2702383376, 1610239915, 4162939394, \ - 557861574, 3805706338, 3832520705, 1248934879, 3250424034, 892335058, 74323433, \ - 3209751608, 3213220797, 3444035873, 3743886725, 1783837251, 610968664, 580745246, \ - 4041979504, 201684874, 2673219253, 1377283008, 3497299167, 2344209394, 2304982920, \ - 3081403782, 2599256854, 3184475235, 3373055826, 695186388, 2423332338, 222864327, \ - 1258227992, 3627871647, 3487724980, 4027953808, 3053320360, 533627073, 3026232514, \ - 2340271949, 867277230, 868513116, 2158535651, 2487822909, 3428235761, 3067196046, \ - 3435119657, 1908441839, 788668797, 3367703138, 3317763187, 908264443, 2252100381, \ - 764223334, 4127108988, 384641349, 3377374722, 1263833251, 1958694944, 3847832657, \ - 1253909612, 1096494446, 555725445, 2277045895, 3340096504, 1383318686, 4234428127, \ - 1072582179, 94169494, 1064509968, 2681151917, 2681864920, 734708852, 1338914021, \ - 1270409500, 1789469116, 4191988204, 1716329784, 2213764829, 3712538840, 919910444, \ - 1318414447, 3383806712, 3054941722, 3378649942, 1205735655, 1268136494, 2214009444, \ - 2532395133, 3232230447, 230294038, 342599089, 772808141, 4096882234, 3146662953, \ - 2784264306, 1860954704, 2675279609, 2984212876, 2466966981, 2627986059, 2985545332, \ - 2578042598, 1458940786, 2944243755, 3959506256, 1509151382, 325761900, 942251521, \ - 4184289782, 2756231555, 3297811774, 1169708099, 3280524138, 3805245319, 3227360276, \ - 3199632491, 2235795585, 2865407118, 36763651, 2441503575, 3314890374, 1755526087, \ - 17915536, 1196948233, 949343045, 3815841867, 489007833, 2654997597, 2834744136, \ - 417688687, 2843220846, 85621843, 747339336, 2043645709, 3520444394, 1825470818, \ - 647778910, 275904777, 1249389189, 3640887431, 4200779599, 323384601, 3446088641, \ - 4049835786, 1718989062, 3563787136, 44099190, 3281263107, 22910812, 1826109246, \ - 745118154, 3392171319, 1571490704, 354891067, 815955642, 1453450421, 940015623, \ - 796817754, 1260148619, 3898237757, 176670141, 1870249326, 3317738680, 448918002, \ - 4059166594, 2003827551, 987091377, 224855998, 3520570137, 789522610, 2604445123, \ - 454472869, 475688926, 2990723466, 523362238, 3897608102, 806637149, 2642229586, \ - 2928614432, 1564415411, 1691381054, 3816907227, 4082581003, 1895544448, 3728217394, \ - 3214813157, 4054301607, 1882632454, 2873728645, 3694943071, 1297991732, 2101682438, \ - 3952579552, 678650400, 1391722293, 478833748, 2976468591, 158586606, 2576499787, \ - 662690848, 3799889765, 3328894692, 2474578497, 2383901391, 1718193504, 3003184595, \ - 3630561213, 1929441113, 3848238627, 1594310094, 3040359840, 3051803867, 2462788790, \ - 954409915, 802581771, 681703307, 545982392, 2738993819, 8025358, 2827719383, \ - 770471093, 3484895980, 3111306320, 3900000891, 2116916652, 397746721, 2087689510, \ - 721433935, 1396088885, 2751612384, 1998988613, 2135074843, 2521131298, 707009172, \ - 2398321482, 688041159, 2264560137, 482388305, 207864885, 3735036991, 3490348331, \ - 1963642811, 3260224305, 3493564223, 1939428454, 1128799656, 1366012432, 2858822447, \ - 1428147157, 2261125391, 1611208390, 1134826333, 2374102525, 3833625209, 2266397263, \ - 3189115077, 770080230, 2674657172, 4280146640, 3604531615, 4235071805, 3436987249, \ - 509704467, 2582695198, 4256268040, 3391197562, 1460642842, 1617931012, 457825497, \ - 1031452907, 1330422862, 4125947620, 2280712485, 431892090, 2387410588, 2061126784, \ - 896457479, 3480499461, 2488196663, 4021103792, 1877063114, 2744470201, 1046140599, \ - 2129952955, 3583049218, 4217723693, 2720341743, 820661843, 1079873609, 3360954200, \ - 3652304997, 3335838575, 2178810636, 1908053374, 4026721976, 1793145418, 476541615, \ - 973420250, 515553040, 919292001, 2601786155, 1685119450, 3030170809, 1590676150, \ - 1665099167, 651151584, 2077190587, 957892642, 646336572, 2743719258, 866169074, \ - 851118829, 4225766285, 963748226, 799549420, 1955032629, 799460000, 2425744063, \ - 2441291571, 1928963772, 528930629, 2591962884, 3495142819, 1896021824, 901320159, \ - 3181820243, 843061941, 3338628510, 3782438992, 9515330, 1705797226, 953535929, \ - 764833876, 3202464965, 2970244591, 519154982, 3390617541, 566616744, 3438031503, \ - 1853838297, 170608755, 1393728434, 676900116, 3184965776, 1843100290, 78995357, \ - 2227939888, 3460264600, 1745705055, 1474086965, 572796246, 4081303004, 882828851, \ - 1295445825, 137639900, 3304579600, 2722437017, 4093422709, 273203373, 2666507854, \ - 3998836510, 493829981, 1623949669, 3482036755, 3390023939, 833233937, 1639668730, \ - 1499455075, 249728260, 1210694006, 3836497489, 1551488720, 3253074267, 3388238003, \ - 2372035079, 3945715164, 2029501215, 3362012634, 2007375355, 4074709820, 631485888, \ - 3135015769, 4273087084, 3648076204, 2739943601, 1374020358, 1760722448, 3773939706, \ - 1313027823, 1895251226, 4224465911, 421382535, 1141067370, 3660034846, 3393185650, \ - 1850995280, 1451917312, 3841455409, 3926840308, 1397397252, 2572864479, 2500171350, \ - 3119920613, 531400869, 1626487579, 1099320497, 407414753, 2438623324, 99073255, \ - 3175491512, 656431560, 1153671785, 236307875, 2824738046, 2320621382, 892174056, \ - 230984053, 719791226, 2718891946, 624), None) + fixedState = (3, (2147483648, 507801126, 683453281, 310439348, 2597246090, + 2209084787, 2267831527, 979920060, 3098657677, 37650879, 807947081, 3974896263, + 881243242, 3100634921, 1334775171, 3965168385, 746264660, 4074750168, 500078808, + 776561771, 702988163, 1636311725, 2559226045, 157578202, 2498342920, 2794591496, + 4130598723, 496985844, 2944563015, 3731321600, 3514814613, 3362575829, 3038768745, + 2206497038, 1108748846, 1317460727, 3134077628, 988312410, 1674063516, 746456451, + 3958482413, 1857117812, 708750586, 1583423339, 3466495450, 1536929345, 1137240525, + 3875025632, 2466137587, 1235845595, 4214575620, 3792516855, 657994358, 1241843248, + 1695651859, 3678946666, 1929922113, 2351044952, 2317810202, 2039319015, 460787996, + 3654096216, 4068721415, 1814163703, 2904112444, 1386111013, 574629867, 2654529343, + 3833135042, 2725328455, 552431551, 4006991378, 1331562057, 3710134542, 303171486, + 1203231078, 2670768975, 54570816, 2679609001, 578983064, 1271454725, 3230871056, + 2496832891, 2944938195, 1608828728, 367886575, 2544708204, 103775539, 1912402393, + 1098482180, 2738577070, 3091646463, 1505274463, 2079416566, 659100352, 839995305, + 1696257633, 274389836, 3973303017, 671127655, 1061109122, 517486945, 1379749962, + 3421383928, 3116950429, 2165882425, 2346928266, 2892678711, 2936066049, 1316407868, + 2873411858, 4279682888, 2744351923, 3290373816, 1014377279, 955200944, 4220990860, + 2386098930, 1772997650, 3757346974, 1621616438, 2877097197, 442116595, 2010480266, + 2867861469, 2955352695, 605335967, 2222936009, 2067554933, 4129906358, 1519608541, + 1195006590, 1942991038, 2736562236, 279162408, 1415982909, 4099901426, 1732201505, + 2934657937, 860563237, 2479235483, 3081651097, 2244720867, 3112631622, 1636991639, + 3860393305, 2312061927, 48780114, 1149090394, 2643246550, 1764050647, 3836789087, + 3474859076, 4237194338, 1735191073, 2150369208, 92164394, 756974036, 2314453957, + 323969533, 4267621035, 283649842, 810004843, 727855536, 1757827251, 3334960421, + 3261035106, 38417393, 2660980472, 1256633965, 2184045390, 811213141, 2857482069, + 2237770878, 3891003138, 2787806886, 2435192790, 2249324662, 3507764896, 995388363, + 856944153, 619213904, 3233967826, 3703465555, 3286531781, 3863193356, 2992340714, + 413696855, 3865185632, 1704163171, 3043634452, 2225424707, 2199018022, 3506117517, + 3311559776, 3374443561, 1207829628, 668793165, 1822020716, 2082656160, 1160606415, + 3034757648, 741703672, 3094328738, 459332691, 2702383376, 1610239915, 4162939394, + 557861574, 3805706338, 3832520705, 1248934879, 3250424034, 892335058, 74323433, + 3209751608, 3213220797, 3444035873, 3743886725, 1783837251, 610968664, 580745246, + 4041979504, 201684874, 2673219253, 1377283008, 3497299167, 2344209394, 2304982920, + 3081403782, 2599256854, 3184475235, 3373055826, 695186388, 2423332338, 222864327, + 1258227992, 3627871647, 3487724980, 4027953808, 3053320360, 533627073, 3026232514, + 2340271949, 867277230, 868513116, 2158535651, 2487822909, 3428235761, 3067196046, + 3435119657, 1908441839, 788668797, 3367703138, 3317763187, 908264443, 2252100381, + 764223334, 4127108988, 384641349, 3377374722, 1263833251, 1958694944, 3847832657, + 1253909612, 1096494446, 555725445, 2277045895, 3340096504, 1383318686, 4234428127, + 1072582179, 94169494, 1064509968, 2681151917, 2681864920, 734708852, 1338914021, + 1270409500, 1789469116, 4191988204, 1716329784, 2213764829, 3712538840, 919910444, + 1318414447, 3383806712, 3054941722, 3378649942, 1205735655, 1268136494, 2214009444, + 2532395133, 3232230447, 230294038, 342599089, 772808141, 4096882234, 3146662953, + 2784264306, 1860954704, 2675279609, 2984212876, 2466966981, 2627986059, 2985545332, + 2578042598, 1458940786, 2944243755, 3959506256, 1509151382, 325761900, 942251521, + 4184289782, 2756231555, 3297811774, 1169708099, 3280524138, 3805245319, 3227360276, + 3199632491, 2235795585, 2865407118, 36763651, 2441503575, 3314890374, 1755526087, + 17915536, 1196948233, 949343045, 3815841867, 489007833, 2654997597, 2834744136, + 417688687, 2843220846, 85621843, 747339336, 2043645709, 3520444394, 1825470818, + 647778910, 275904777, 1249389189, 3640887431, 4200779599, 323384601, 3446088641, + 4049835786, 1718989062, 3563787136, 44099190, 3281263107, 22910812, 1826109246, + 745118154, 3392171319, 1571490704, 354891067, 815955642, 1453450421, 940015623, + 796817754, 1260148619, 3898237757, 176670141, 1870249326, 3317738680, 448918002, + 4059166594, 2003827551, 987091377, 224855998, 3520570137, 789522610, 2604445123, + 454472869, 475688926, 2990723466, 523362238, 3897608102, 806637149, 2642229586, + 2928614432, 1564415411, 1691381054, 3816907227, 4082581003, 1895544448, 3728217394, + 3214813157, 4054301607, 1882632454, 2873728645, 3694943071, 1297991732, 2101682438, + 3952579552, 678650400, 1391722293, 478833748, 2976468591, 158586606, 2576499787, + 662690848, 3799889765, 3328894692, 2474578497, 2383901391, 1718193504, 3003184595, + 3630561213, 1929441113, 3848238627, 1594310094, 3040359840, 3051803867, 2462788790, + 954409915, 802581771, 681703307, 545982392, 2738993819, 8025358, 2827719383, + 770471093, 3484895980, 3111306320, 3900000891, 2116916652, 397746721, 2087689510, + 721433935, 1396088885, 2751612384, 1998988613, 2135074843, 2521131298, 707009172, + 2398321482, 688041159, 2264560137, 482388305, 207864885, 3735036991, 3490348331, + 1963642811, 3260224305, 3493564223, 1939428454, 1128799656, 1366012432, 2858822447, + 1428147157, 2261125391, 1611208390, 1134826333, 2374102525, 3833625209, 2266397263, + 3189115077, 770080230, 2674657172, 4280146640, 3604531615, 4235071805, 3436987249, + 509704467, 2582695198, 4256268040, 3391197562, 1460642842, 1617931012, 457825497, + 1031452907, 1330422862, 4125947620, 2280712485, 431892090, 2387410588, 2061126784, + 896457479, 3480499461, 2488196663, 4021103792, 1877063114, 2744470201, 1046140599, + 2129952955, 3583049218, 4217723693, 2720341743, 820661843, 1079873609, 3360954200, + 3652304997, 3335838575, 2178810636, 1908053374, 4026721976, 1793145418, 476541615, + 973420250, 515553040, 919292001, 2601786155, 1685119450, 3030170809, 1590676150, + 1665099167, 651151584, 2077190587, 957892642, 646336572, 2743719258, 866169074, + 851118829, 4225766285, 963748226, 799549420, 1955032629, 799460000, 2425744063, + 2441291571, 1928963772, 528930629, 2591962884, 3495142819, 1896021824, 901320159, + 3181820243, 843061941, 3338628510, 3782438992, 9515330, 1705797226, 953535929, + 764833876, 3202464965, 2970244591, 519154982, 3390617541, 566616744, 3438031503, + 1853838297, 170608755, 1393728434, 676900116, 3184965776, 1843100290, 78995357, + 2227939888, 3460264600, 1745705055, 1474086965, 572796246, 4081303004, 882828851, + 1295445825, 137639900, 3304579600, 2722437017, 4093422709, 273203373, 2666507854, + 3998836510, 493829981, 1623949669, 3482036755, 3390023939, 833233937, 1639668730, + 1499455075, 249728260, 1210694006, 3836497489, 1551488720, 3253074267, 3388238003, + 2372035079, 3945715164, 2029501215, 3362012634, 2007375355, 4074709820, 631485888, + 3135015769, 4273087084, 3648076204, 2739943601, 1374020358, 1760722448, 3773939706, + 1313027823, 1895251226, 4224465911, 421382535, 1141067370, 3660034846, 3393185650, + 1850995280, 1451917312, 3841455409, 3926840308, 1397397252, 2572864479, 2500171350, + 3119920613, 531400869, 1626487579, 1099320497, 407414753, 2438623324, 99073255, + 3175491512, 656431560, 1153671785, 236307875, 2824738046, 2320621382, 892174056, + 230984053, 719791226, 2718891946, 624), None) self.random = random.Random() self.random.setstate(fixedState) + """ Data structures useful for implementing SearchAgents """ + class Stack: "A container with a last-in-first-out (LIFO) queuing policy." + def __init__(self): self.list = [] - def push(self,item): + def push(self, item): "Push 'item' onto the stack" self.list.append(item) @@ -147,19 +152,21 @@ class Stack: "Returns true if the stack is empty" return len(self.list) == 0 + class Queue: "A container with a first-in-first-out (FIFO) queuing policy." + def __init__(self): self.list = [] - def push(self,item): + def push(self, item): "Enqueue the 'item' into the queue" - self.list.insert(0,item) + self.list.insert(0, item) def pop(self): """ - Dequeue the earliest enqueued item still in the queue. This - operation removes the item from the queue. + Dequeue the earliest enqueued item still in the queue. This + operation removes the item from the queue. """ return self.list.pop() @@ -167,14 +174,16 @@ class Queue: "Returns true if the queue is empty" return len(self.list) == 0 + class PriorityQueue: """ - Implements a priority queue data structure. Each inserted item - has a priority associated with it and the client is usually interested - in quick retrieval of the lowest-priority item in the queue. This - data structure allows O(1) access to the lowest-priority item. + Implements a priority queue data structure. Each inserted item + has a priority associated with it and the client is usually interested + in quick retrieval of the lowest-priority item in the queue. This + data structure allows O(1) access to the lowest-priority item. """ - def __init__(self): + + def __init__(self): self.heap = [] self.count = 0 @@ -205,6 +214,7 @@ class PriorityQueue: else: self.push(item, priority) + class PriorityQueueWithFunction(PriorityQueue): """ Implements a priority queue with the same push/pop signature of the @@ -212,7 +222,8 @@ class PriorityQueueWithFunction(PriorityQueue): those two classes. The caller has to provide a priority function, which extracts each item's priority. """ - def __init__(self, priorityFunction): + + def __init__(self, priorityFunction): "priorityFunction (item) -> priority" self.priorityFunction = priorityFunction # store the priority function PriorityQueue.__init__(self) # super-class initializer @@ -222,16 +233,18 @@ class PriorityQueueWithFunction(PriorityQueue): PriorityQueue.push(self, item, self.priorityFunction(item)) -def manhattanDistance( xy1, xy2 ): +def manhattanDistance(xy1, xy2): "Returns the Manhattan distance between points xy1 and xy2" - return abs( xy1[0] - xy2[0] ) + abs( xy1[1] - xy2[1] ) + return abs(xy1[0] - xy2[0]) + abs(xy1[1] - xy2[1]) + """ - Data structures and functions useful for various course projects +Data structures and functions useful for various course projects - The search project should not need anything below this line. +The search project should not need anything below this line. """ + class Counter(dict): """ A counter keeps track of counts for a set of keys. @@ -243,12 +256,12 @@ class Counter(dict): all keys are defaulted to have value 0. Using a dictionary: a = {} - print(a['test']) + print a['test'] would give an error, while the Counter class analogue: >>> a = Counter() - >>> print(a['test']) + >>> print a['test'] 0 returns the default 0 value. Note that to reference a key @@ -257,14 +270,14 @@ class Counter(dict): >>> a = Counter() >>> a['test'] = 2 - >>> print(a['test']) + >>> print a['test'] 2 This is very useful for counting things without initializing their counts, see for example: >>> a['blah'] += 1 - >>> print(a['blah']) + >>> print a['blah'] 1 The counter also includes additional functionality useful in implementing @@ -272,6 +285,7 @@ class Counter(dict): subtracted or multiplied together. See below for details. They can also be normalized and their total count and arg max can be extracted. """ + def __getitem__(self, idx): self.setdefault(idx, 0) return dict.__getitem__(self, idx) @@ -294,8 +308,9 @@ class Counter(dict): """ Returns the key with the highest value. """ - if len(self.keys()) == 0: return None - all = self.items() + if len(list(self.keys())) == 0: + return None + all = list(self.items()) values = [x[1] for x in all] maxIndex = values.index(max(values)) return all[maxIndex][0] @@ -312,8 +327,9 @@ class Counter(dict): >>> a.sortedKeys() ['second', 'third', 'first'] """ - sortedItems = self.items() - compare = lambda x, y: sign(y[1] - x[1]) + sortedItems = list(self.items()) + + def compare(x, y): return sign(y[1] - x[1]) sortedItems.sort(cmp=compare) return [x[0] for x in sortedItems] @@ -331,8 +347,9 @@ class Counter(dict): Counter will result in an error. """ total = float(self.totalCount()) - if total == 0: return - for key in self.keys(): + if total == 0: + return + for key in list(self.keys()): self[key] = self[key] / total def divideAll(self, divisor): @@ -349,7 +366,7 @@ class Counter(dict): """ return Counter(dict.copy(self)) - def __mul__(self, y ): + def __mul__(self, y): """ Multiplying two counters gives the dot product of their vectors where each unique label is a vector element. @@ -368,7 +385,7 @@ class Counter(dict): sum = 0 x = self if len(x) > len(y): - x,y = y,x + x, y = y, x for key in x: if key not in y: continue @@ -390,10 +407,10 @@ class Counter(dict): >>> a['first'] 1 """ - for key, value in y.items(): + for key, value in list(y.items()): self[key] += value - def __add__( self, y ): + def __add__(self, y): """ Adding two counters gives a counter with the union of all keys and counts of the second added to counts of the first. @@ -419,7 +436,7 @@ class Counter(dict): addend[key] = y[key] return addend - def __sub__( self, y ): + def __sub__(self, y): """ Subtracting a counter from another gives a counter with the union of all keys and counts of the second subtracted from counts of the first. @@ -445,40 +462,46 @@ class Counter(dict): addend[key] = -1 * y[key] return addend + def raiseNotDefined(): fileName = inspect.stack()[1][1] line = inspect.stack()[1][2] method = inspect.stack()[1][3] - print("*** Method not implemented: %s at line %s of %s" % (method, line, fileName)) + print("*** Method not implemented: %s at line %s of %s" % + (method, line, fileName)) sys.exit(1) + def normalize(vectorOrCounter): """ - normalize a vector or counter by dividing each value by the sum of all values + Normalize a vector or counter by dividing each value by the sum of all values """ normalizedCounter = Counter() if type(vectorOrCounter) == type(normalizedCounter): counter = vectorOrCounter total = float(counter.totalCount()) - if total == 0: return counter - for key in counter.keys(): + if total == 0: + return counter + for key in list(counter.keys()): value = counter[key] normalizedCounter[key] = value / total return normalizedCounter else: vector = vectorOrCounter s = float(sum(vector)) - if s == 0: return vector + if s == 0: + return vector return [el / s for el in vector] + def nSample(distribution, values, n): if sum(distribution) != 1: distribution = normalize(distribution) rand = [random.random() for i in range(n)] rand.sort() samples = [] - samplePos, distPos, cdf = 0,0, distribution[0] + samplePos, distPos, cdf = 0, 0, distribution[0] while samplePos < n: if rand[samplePos] < cdf: samplePos += 1 @@ -488,7 +511,8 @@ def nSample(distribution, values, n): cdf += distribution[distPos] return samples -def sample(distribution, values = None): + +def sample(distribution, values=None): if type(distribution) == Counter: items = sorted(distribution.items()) distribution = [i[1] for i in items] @@ -496,20 +520,22 @@ def sample(distribution, values = None): if sum(distribution) != 1: distribution = normalize(distribution) choice = random.random() - i, total= 0, distribution[0] + i, total = 0, distribution[0] while choice > total: i += 1 total += distribution[i] return values[i] + def sampleFromCounter(ctr): items = sorted(ctr.items()) - return sample([v for k,v in items], [k for k,v in items]) + return sample([v for k, v in items], [k for k, v in items]) + def getProbability(value, distribution, values): """ - Gives the probability of a value under a discrete distribution - defined by (distributions, values). + Gives the probability of a value under a discrete distribution + defined by (distributions, values). """ total = 0.0 for prob, val in zip(distribution, values): @@ -517,11 +543,13 @@ def getProbability(value, distribution, values): total += prob return total -def flipCoin( p ): + +def flipCoin(p): r = random.random() return r < p -def chooseFromDistribution( distribution ): + +def chooseFromDistribution(distribution): "Takes either a counter or a list of (prob, key) pairs and samples" if type(distribution) == dict or type(distribution) == Counter: return sample(distribution) @@ -529,27 +557,31 @@ def chooseFromDistribution( distribution ): base = 0.0 for prob, element in distribution: base += prob - if r <= base: return element + if r <= base: + return element -def nearestPoint( pos ): + +def nearestPoint(pos): """ Finds the nearest grid point to a position (discretizes). """ - ( current_row, current_col ) = pos + (current_row, current_col) = pos - grid_row = int( current_row + 0.5 ) - grid_col = int( current_col + 0.5 ) - return ( grid_row, grid_col ) + grid_row = int(current_row + 0.5) + grid_col = int(current_col + 0.5) + return (grid_row, grid_col) -def sign( x ): + +def sign(x): """ Returns 1 or -1 depending on the sign of x """ - if( x >= 0 ): + if(x >= 0): return 1 else: return -1 + def arrayInvert(array): """ Inverts a matrix stored as a list of lists. @@ -560,18 +592,20 @@ def arrayInvert(array): result[inner].append(outer[inner]) return result -def matrixAsList( matrix, value = True ): + +def matrixAsList(matrix, value=True): """ Turns a matrix into a list of coordinates matching the specified value """ - rows, cols = len( matrix ), len( matrix[0] ) + rows, cols = len(matrix), len(matrix[0]) cells = [] - for row in range( rows ): - for col in range( cols ): + for row in range(rows): + for col in range(cols): if matrix[row][col] == value: - cells.append( ( row, col ) ) + cells.append((row, col)) return cells + def lookup(name, namespace): """ Get a method or class from any imported module from its name. @@ -579,22 +613,30 @@ def lookup(name, namespace): """ dots = name.count('.') if dots > 0: - moduleName, objName = '.'.join(name.split('.')[:-1]), name.split('.')[-1] + moduleName, objName = '.'.join( + name.split('.')[:-1]), name.split('.')[-1] module = __import__(moduleName) return getattr(module, objName) else: - modules = [obj for obj in namespace.values() if str(type(obj)) == ""] - options = [getattr(module, name) for module in modules if name in dir(module)] - options += [obj[1] for obj in namespace.items() if obj[0] == name ] - if len(options) == 1: return options[0] - if len(options) > 1: raise Exception('Name conflict for %s') + modules = [obj for obj in list(namespace.values()) if str( + type(obj)) == ""] + options = [getattr(module, name) + for module in modules if name in dir(module)] + options += [obj[1] + for obj in list(namespace.items()) if obj[0] == name] + if len(options) == 1: + return options[0] + if len(options) > 1: + raise Exception('Name conflict for %s') raise Exception('%s not found as a method or class' % name) + def pause(): """ Pauses the output stream awaiting user feedback. """ - input("") + print("") + input() # code to handle timeouts @@ -607,6 +649,8 @@ def pause(): # import signal import time + + class TimeoutFunctionException(Exception): """Exception to raise on a timeout""" pass @@ -641,15 +685,16 @@ class TimeoutFunction: return result - _ORIGINAL_STDOUT = None _ORIGINAL_STDERR = None _MUTED = False + class WritableNull: def write(self, string): pass + def mutePrint(): global _ORIGINAL_STDOUT, _ORIGINAL_STDERR, _MUTED if _MUTED: @@ -661,6 +706,7 @@ def mutePrint(): sys.stdout = WritableNull() #sys.stderr = WritableNull() + def unmutePrint(): global _ORIGINAL_STDOUT, _ORIGINAL_STDERR, _MUTED if not _MUTED: @@ -669,4 +715,3 @@ def unmutePrint(): sys.stdout = _ORIGINAL_STDOUT #sys.stderr = _ORIGINAL_STDERR -