From 30a833b0f1c226cdc64dce67da31a0d7492bac6d Mon Sep 17 00:00:00 2001 From: huangjielun <2872405629@qq.com> Date: Fri, 16 Sep 2022 20:45:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- search/.idea/.gitignore | 3 + .../inspectionProfiles/profiles_settings.xml | 6 + search/.idea/misc.xml | 4 + search/.idea/modules.xml | 8 + search/.idea/search.iml | 12 + search/.idea/vcs.xml | 7 + search/VERSION | 1 + search/autograder.py | 358 ++++++++ search/commands.txt | 22 + search/eightpuzzle.py | 281 ++++++ search/game.py | 729 ++++++++++++++++ search/game.pyc | Bin 0 -> 23225 bytes search/ghostAgents.py | 81 ++ search/ghostAgents.pyc | Bin 0 -> 3341 bytes search/grading.py | 323 +++++++ search/graphicsDisplay.py | 679 +++++++++++++++ search/graphicsDisplay.pyc | Bin 0 -> 24599 bytes search/graphicsUtils.py | 402 +++++++++ search/graphicsUtils.pyc | Bin 0 -> 13218 bytes search/keyboardAgents.py | 84 ++ search/keyboardAgents.pyc | Bin 0 -> 2784 bytes search/layout.py | 149 ++++ search/layout.pyc | Bin 0 -> 6269 bytes search/layouts/bigCorners.lay | 37 + search/layouts/bigMaze.lay | 37 + search/layouts/bigSafeSearch.lay | 8 + search/layouts/bigSearch.lay | 15 + search/layouts/boxSearch.lay | 14 + search/layouts/capsuleClassic.lay | 7 + search/layouts/contestClassic.lay | 9 + search/layouts/contoursMaze.lay | 11 + search/layouts/greedySearch.lay | 8 + search/layouts/mediumClassic.lay | 11 + search/layouts/mediumCorners.lay | 14 + search/layouts/mediumDottedMaze.lay | 18 + search/layouts/mediumMaze.lay | 18 + search/layouts/mediumSafeSearch.lay | 6 + search/layouts/mediumScaryMaze.lay | 18 + search/layouts/mediumSearch.lay | 8 + search/layouts/minimaxClassic.lay | 5 + search/layouts/oddSearch.lay | 7 + search/layouts/openClassic.lay | 9 + search/layouts/openMaze.lay | 23 + search/layouts/openSearch.lay | 7 + search/layouts/originalClassic.lay | 27 + search/layouts/powerClassic.lay | 7 + search/layouts/smallClassic.lay | 7 + search/layouts/smallMaze.lay | 10 + search/layouts/smallSafeSearch.lay | 15 + search/layouts/smallSearch.lay | 5 + search/layouts/testClassic.lay | 10 + search/layouts/testMaze.lay | 3 + search/layouts/testSearch.lay | 5 + search/layouts/tinyCorners.lay | 8 + search/layouts/tinyMaze.lay | 7 + search/layouts/tinySafeSearch.lay | 7 + search/layouts/tinySearch.lay | 7 + search/layouts/trappedClassic.lay | 5 + search/layouts/trickyClassic.lay | 13 + search/layouts/trickySearch.lay | 7 + search/pacman.py | 684 +++++++++++++++ search/pacman.pyc | Bin 0 -> 25577 bytes search/pacmanAgents.py | 52 ++ search/pacmanAgents.pyc | Bin 0 -> 2225 bytes search/projectParams.py | 18 + search/search.py | 191 ++++ search/search.pyc | Bin 0 -> 6082 bytes search/searchAgents.py | 654 ++++++++++++++ search/searchAgents.pyc | Bin 0 -> 25662 bytes search/searchTestClasses.py | 821 ++++++++++++++++++ search/submission_autograder.py | 41 + search/testClasses.py | 206 +++++ search/testParser.py | 85 ++ search/test_cases/CONFIG | 1 + search/test_cases/q1/CONFIG | 2 + search/test_cases/q1/graph_backtrack.solution | 7 + search/test_cases/q1/graph_backtrack.test | 32 + .../test_cases/q1/graph_bfs_vs_dfs.solution | 7 + search/test_cases/q1/graph_bfs_vs_dfs.test | 30 + search/test_cases/q1/graph_infinite.solution | 7 + search/test_cases/q1/graph_infinite.test | 30 + search/test_cases/q1/graph_manypaths.solution | 7 + search/test_cases/q1/graph_manypaths.test | 39 + search/test_cases/q1/pacman_1.solution | 40 + search/test_cases/q1/pacman_1.test | 27 + search/test_cases/q2/CONFIG | 2 + search/test_cases/q2/graph_backtrack.solution | 7 + search/test_cases/q2/graph_backtrack.test | 32 + .../test_cases/q2/graph_bfs_vs_dfs.solution | 7 + search/test_cases/q2/graph_bfs_vs_dfs.test | 30 + search/test_cases/q2/graph_infinite.solution | 7 + search/test_cases/q2/graph_infinite.test | 30 + search/test_cases/q2/graph_manypaths.solution | 7 + search/test_cases/q2/graph_manypaths.test | 39 + search/test_cases/q2/pacman_1.solution | 22 + search/test_cases/q2/pacman_1.test | 27 + search/test_cases/q3/CONFIG | 2 + search/test_cases/q3/graph_backtrack.solution | 7 + search/test_cases/q3/graph_backtrack.test | 32 + .../test_cases/q3/graph_bfs_vs_dfs.solution | 7 + search/test_cases/q3/graph_bfs_vs_dfs.test | 30 + search/test_cases/q3/graph_infinite.solution | 7 + search/test_cases/q3/graph_infinite.test | 30 + search/test_cases/q3/graph_manypaths.solution | 7 + search/test_cases/q3/graph_manypaths.test | 39 + search/test_cases/q3/ucs_0_graph.solution | 7 + search/test_cases/q3/ucs_0_graph.test | 39 + search/test_cases/q3/ucs_1_problemC.solution | 22 + search/test_cases/q3/ucs_1_problemC.test | 28 + search/test_cases/q3/ucs_2_problemE.solution | 22 + search/test_cases/q3/ucs_2_problemE.test | 28 + search/test_cases/q3/ucs_3_problemW.solution | 34 + search/test_cases/q3/ucs_3_problemW.test | 28 + .../test_cases/q3/ucs_4_testSearch.solution | 12 + search/test_cases/q3/ucs_4_testSearch.test | 16 + .../q3/ucs_5_goalAtDequeue.solution | 7 + search/test_cases/q3/ucs_5_goalAtDequeue.test | 29 + search/test_cases/q4/CONFIG | 2 + search/test_cases/q4/astar_0.solution | 7 + search/test_cases/q4/astar_0.test | 39 + .../q4/astar_1_graph_heuristic.solution | 7 + .../q4/astar_1_graph_heuristic.test | 54 ++ .../test_cases/q4/astar_2_manhattan.solution | 22 + search/test_cases/q4/astar_2_manhattan.test | 27 + .../q4/astar_3_goalAtDequeue.solution | 7 + .../test_cases/q4/astar_3_goalAtDequeue.test | 29 + search/test_cases/q4/graph_backtrack.solution | 7 + search/test_cases/q4/graph_backtrack.test | 32 + search/test_cases/q4/graph_manypaths.solution | 7 + search/test_cases/q4/graph_manypaths.test | 39 + search/test_cases/q5/CONFIG | 3 + .../test_cases/q5/corner_tiny_corner.solution | 2 + search/test_cases/q5/corner_tiny_corner.test | 14 + search/test_cases/q6/CONFIG | 3 + search/test_cases/q6/corner_sanity_1.solution | 7 + search/test_cases/q6/corner_sanity_1.test | 12 + search/test_cases/q6/corner_sanity_2.solution | 7 + search/test_cases/q6/corner_sanity_2.test | 12 + search/test_cases/q6/corner_sanity_3.solution | 9 + search/test_cases/q6/corner_sanity_3.test | 15 + search/test_cases/q6/medium_corners.solution | 16 + search/test_cases/q6/medium_corners.test | 19 + search/test_cases/q7/CONFIG | 3 + .../test_cases/q7/food_heuristic_1.solution | 2 + search/test_cases/q7/food_heuristic_1.test | 13 + .../test_cases/q7/food_heuristic_10.solution | 2 + search/test_cases/q7/food_heuristic_10.test | 13 + .../test_cases/q7/food_heuristic_11.solution | 2 + search/test_cases/q7/food_heuristic_11.test | 13 + .../test_cases/q7/food_heuristic_12.solution | 2 + search/test_cases/q7/food_heuristic_12.test | 13 + .../test_cases/q7/food_heuristic_13.solution | 2 + search/test_cases/q7/food_heuristic_13.test | 13 + .../test_cases/q7/food_heuristic_14.solution | 2 + search/test_cases/q7/food_heuristic_14.test | 19 + .../test_cases/q7/food_heuristic_15.solution | 2 + search/test_cases/q7/food_heuristic_15.test | 32 + .../test_cases/q7/food_heuristic_16.solution | 2 + search/test_cases/q7/food_heuristic_16.test | 15 + .../test_cases/q7/food_heuristic_17.solution | 2 + search/test_cases/q7/food_heuristic_17.test | 14 + .../test_cases/q7/food_heuristic_2.solution | 2 + search/test_cases/q7/food_heuristic_2.test | 32 + .../test_cases/q7/food_heuristic_3.solution | 2 + search/test_cases/q7/food_heuristic_3.test | 15 + .../test_cases/q7/food_heuristic_4.solution | 2 + search/test_cases/q7/food_heuristic_4.test | 14 + .../test_cases/q7/food_heuristic_5.solution | 2 + search/test_cases/q7/food_heuristic_5.test | 13 + .../test_cases/q7/food_heuristic_6.solution | 2 + search/test_cases/q7/food_heuristic_6.test | 13 + .../test_cases/q7/food_heuristic_7.solution | 2 + search/test_cases/q7/food_heuristic_7.test | 13 + .../test_cases/q7/food_heuristic_8.solution | 2 + search/test_cases/q7/food_heuristic_8.test | 13 + .../test_cases/q7/food_heuristic_9.solution | 2 + search/test_cases/q7/food_heuristic_9.test | 13 + .../q7/food_heuristic_grade_tricky.solution | 2 + .../q7/food_heuristic_grade_tricky.test | 19 + search/test_cases/q8/CONFIG | 2 + search/test_cases/q8/closest_dot_1.solution | 2 + search/test_cases/q8/closest_dot_1.test | 11 + search/test_cases/q8/closest_dot_10.solution | 2 + search/test_cases/q8/closest_dot_10.test | 17 + search/test_cases/q8/closest_dot_11.solution | 2 + search/test_cases/q8/closest_dot_11.test | 30 + search/test_cases/q8/closest_dot_12.solution | 2 + search/test_cases/q8/closest_dot_12.test | 13 + search/test_cases/q8/closest_dot_13.solution | 2 + search/test_cases/q8/closest_dot_13.test | 12 + search/test_cases/q8/closest_dot_2.solution | 2 + search/test_cases/q8/closest_dot_2.test | 11 + search/test_cases/q8/closest_dot_3.solution | 2 + search/test_cases/q8/closest_dot_3.test | 11 + search/test_cases/q8/closest_dot_4.solution | 2 + search/test_cases/q8/closest_dot_4.test | 11 + search/test_cases/q8/closest_dot_5.solution | 2 + search/test_cases/q8/closest_dot_5.test | 11 + search/test_cases/q8/closest_dot_6.solution | 2 + search/test_cases/q8/closest_dot_6.test | 11 + search/test_cases/q8/closest_dot_7.solution | 2 + search/test_cases/q8/closest_dot_7.test | 11 + search/test_cases/q8/closest_dot_8.solution | 2 + search/test_cases/q8/closest_dot_8.test | 11 + search/test_cases/q8/closest_dot_9.solution | 2 + search/test_cases/q8/closest_dot_9.test | 11 + search/textDisplay.py | 81 ++ search/util.py | 674 ++++++++++++++ search/util.pyc | Bin 0 -> 33496 bytes 209 files changed, 8887 insertions(+) create mode 100644 search/.idea/.gitignore create mode 100644 search/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 search/.idea/misc.xml create mode 100644 search/.idea/modules.xml create mode 100644 search/.idea/search.iml create mode 100644 search/.idea/vcs.xml create mode 100644 search/VERSION create mode 100644 search/autograder.py create mode 100644 search/commands.txt create mode 100644 search/eightpuzzle.py create mode 100644 search/game.py create mode 100644 search/game.pyc create mode 100644 search/ghostAgents.py create mode 100644 search/ghostAgents.pyc create mode 100644 search/grading.py create mode 100644 search/graphicsDisplay.py create mode 100644 search/graphicsDisplay.pyc create mode 100644 search/graphicsUtils.py create mode 100644 search/graphicsUtils.pyc create mode 100644 search/keyboardAgents.py create mode 100644 search/keyboardAgents.pyc create mode 100644 search/layout.py create mode 100644 search/layout.pyc create mode 100644 search/layouts/bigCorners.lay create mode 100644 search/layouts/bigMaze.lay create mode 100644 search/layouts/bigSafeSearch.lay create mode 100644 search/layouts/bigSearch.lay create mode 100644 search/layouts/boxSearch.lay create mode 100644 search/layouts/capsuleClassic.lay create mode 100644 search/layouts/contestClassic.lay create mode 100644 search/layouts/contoursMaze.lay create mode 100644 search/layouts/greedySearch.lay create mode 100644 search/layouts/mediumClassic.lay create mode 100644 search/layouts/mediumCorners.lay create mode 100644 search/layouts/mediumDottedMaze.lay create mode 100644 search/layouts/mediumMaze.lay create mode 100644 search/layouts/mediumSafeSearch.lay create mode 100644 search/layouts/mediumScaryMaze.lay create mode 100644 search/layouts/mediumSearch.lay create mode 100644 search/layouts/minimaxClassic.lay create mode 100644 search/layouts/oddSearch.lay create mode 100644 search/layouts/openClassic.lay create mode 100644 search/layouts/openMaze.lay create mode 100644 search/layouts/openSearch.lay create mode 100644 search/layouts/originalClassic.lay create mode 100644 search/layouts/powerClassic.lay create mode 100644 search/layouts/smallClassic.lay create mode 100644 search/layouts/smallMaze.lay create mode 100644 search/layouts/smallSafeSearch.lay create mode 100644 search/layouts/smallSearch.lay create mode 100644 search/layouts/testClassic.lay create mode 100644 search/layouts/testMaze.lay create mode 100644 search/layouts/testSearch.lay create mode 100644 search/layouts/tinyCorners.lay create mode 100644 search/layouts/tinyMaze.lay create mode 100644 search/layouts/tinySafeSearch.lay create mode 100644 search/layouts/tinySearch.lay create mode 100644 search/layouts/trappedClassic.lay create mode 100644 search/layouts/trickyClassic.lay create mode 100644 search/layouts/trickySearch.lay create mode 100644 search/pacman.py create mode 100644 search/pacman.pyc create mode 100644 search/pacmanAgents.py create mode 100644 search/pacmanAgents.pyc create mode 100644 search/projectParams.py create mode 100644 search/search.py create mode 100644 search/search.pyc create mode 100644 search/searchAgents.py create mode 100644 search/searchAgents.pyc create mode 100644 search/searchTestClasses.py create mode 100644 search/submission_autograder.py create mode 100644 search/testClasses.py create mode 100644 search/testParser.py create mode 100644 search/test_cases/CONFIG create mode 100644 search/test_cases/q1/CONFIG create mode 100644 search/test_cases/q1/graph_backtrack.solution create mode 100644 search/test_cases/q1/graph_backtrack.test create mode 100644 search/test_cases/q1/graph_bfs_vs_dfs.solution create mode 100644 search/test_cases/q1/graph_bfs_vs_dfs.test create mode 100644 search/test_cases/q1/graph_infinite.solution create mode 100644 search/test_cases/q1/graph_infinite.test create mode 100644 search/test_cases/q1/graph_manypaths.solution create mode 100644 search/test_cases/q1/graph_manypaths.test create mode 100644 search/test_cases/q1/pacman_1.solution create mode 100644 search/test_cases/q1/pacman_1.test create mode 100644 search/test_cases/q2/CONFIG create mode 100644 search/test_cases/q2/graph_backtrack.solution create mode 100644 search/test_cases/q2/graph_backtrack.test create mode 100644 search/test_cases/q2/graph_bfs_vs_dfs.solution create mode 100644 search/test_cases/q2/graph_bfs_vs_dfs.test create mode 100644 search/test_cases/q2/graph_infinite.solution create mode 100644 search/test_cases/q2/graph_infinite.test create mode 100644 search/test_cases/q2/graph_manypaths.solution create mode 100644 search/test_cases/q2/graph_manypaths.test create mode 100644 search/test_cases/q2/pacman_1.solution create mode 100644 search/test_cases/q2/pacman_1.test create mode 100644 search/test_cases/q3/CONFIG create mode 100644 search/test_cases/q3/graph_backtrack.solution create mode 100644 search/test_cases/q3/graph_backtrack.test create mode 100644 search/test_cases/q3/graph_bfs_vs_dfs.solution create mode 100644 search/test_cases/q3/graph_bfs_vs_dfs.test create mode 100644 search/test_cases/q3/graph_infinite.solution create mode 100644 search/test_cases/q3/graph_infinite.test create mode 100644 search/test_cases/q3/graph_manypaths.solution create mode 100644 search/test_cases/q3/graph_manypaths.test create mode 100644 search/test_cases/q3/ucs_0_graph.solution create mode 100644 search/test_cases/q3/ucs_0_graph.test create mode 100644 search/test_cases/q3/ucs_1_problemC.solution create mode 100644 search/test_cases/q3/ucs_1_problemC.test create mode 100644 search/test_cases/q3/ucs_2_problemE.solution create mode 100644 search/test_cases/q3/ucs_2_problemE.test create mode 100644 search/test_cases/q3/ucs_3_problemW.solution create mode 100644 search/test_cases/q3/ucs_3_problemW.test create mode 100644 search/test_cases/q3/ucs_4_testSearch.solution create mode 100644 search/test_cases/q3/ucs_4_testSearch.test create mode 100644 search/test_cases/q3/ucs_5_goalAtDequeue.solution create mode 100644 search/test_cases/q3/ucs_5_goalAtDequeue.test create mode 100644 search/test_cases/q4/CONFIG create mode 100644 search/test_cases/q4/astar_0.solution create mode 100644 search/test_cases/q4/astar_0.test create mode 100644 search/test_cases/q4/astar_1_graph_heuristic.solution create mode 100644 search/test_cases/q4/astar_1_graph_heuristic.test create mode 100644 search/test_cases/q4/astar_2_manhattan.solution create mode 100644 search/test_cases/q4/astar_2_manhattan.test create mode 100644 search/test_cases/q4/astar_3_goalAtDequeue.solution create mode 100644 search/test_cases/q4/astar_3_goalAtDequeue.test create mode 100644 search/test_cases/q4/graph_backtrack.solution create mode 100644 search/test_cases/q4/graph_backtrack.test create mode 100644 search/test_cases/q4/graph_manypaths.solution create mode 100644 search/test_cases/q4/graph_manypaths.test create mode 100644 search/test_cases/q5/CONFIG create mode 100644 search/test_cases/q5/corner_tiny_corner.solution create mode 100644 search/test_cases/q5/corner_tiny_corner.test create mode 100644 search/test_cases/q6/CONFIG create mode 100644 search/test_cases/q6/corner_sanity_1.solution create mode 100644 search/test_cases/q6/corner_sanity_1.test create mode 100644 search/test_cases/q6/corner_sanity_2.solution create mode 100644 search/test_cases/q6/corner_sanity_2.test create mode 100644 search/test_cases/q6/corner_sanity_3.solution create mode 100644 search/test_cases/q6/corner_sanity_3.test create mode 100644 search/test_cases/q6/medium_corners.solution create mode 100644 search/test_cases/q6/medium_corners.test create mode 100644 search/test_cases/q7/CONFIG create mode 100644 search/test_cases/q7/food_heuristic_1.solution create mode 100644 search/test_cases/q7/food_heuristic_1.test create mode 100644 search/test_cases/q7/food_heuristic_10.solution create mode 100644 search/test_cases/q7/food_heuristic_10.test create mode 100644 search/test_cases/q7/food_heuristic_11.solution create mode 100644 search/test_cases/q7/food_heuristic_11.test create mode 100644 search/test_cases/q7/food_heuristic_12.solution create mode 100644 search/test_cases/q7/food_heuristic_12.test create mode 100644 search/test_cases/q7/food_heuristic_13.solution create mode 100644 search/test_cases/q7/food_heuristic_13.test create mode 100644 search/test_cases/q7/food_heuristic_14.solution create mode 100644 search/test_cases/q7/food_heuristic_14.test create mode 100644 search/test_cases/q7/food_heuristic_15.solution create mode 100644 search/test_cases/q7/food_heuristic_15.test create mode 100644 search/test_cases/q7/food_heuristic_16.solution create mode 100644 search/test_cases/q7/food_heuristic_16.test create mode 100644 search/test_cases/q7/food_heuristic_17.solution create mode 100644 search/test_cases/q7/food_heuristic_17.test create mode 100644 search/test_cases/q7/food_heuristic_2.solution create mode 100644 search/test_cases/q7/food_heuristic_2.test create mode 100644 search/test_cases/q7/food_heuristic_3.solution create mode 100644 search/test_cases/q7/food_heuristic_3.test create mode 100644 search/test_cases/q7/food_heuristic_4.solution create mode 100644 search/test_cases/q7/food_heuristic_4.test create mode 100644 search/test_cases/q7/food_heuristic_5.solution create mode 100644 search/test_cases/q7/food_heuristic_5.test create mode 100644 search/test_cases/q7/food_heuristic_6.solution create mode 100644 search/test_cases/q7/food_heuristic_6.test create mode 100644 search/test_cases/q7/food_heuristic_7.solution create mode 100644 search/test_cases/q7/food_heuristic_7.test create mode 100644 search/test_cases/q7/food_heuristic_8.solution create mode 100644 search/test_cases/q7/food_heuristic_8.test create mode 100644 search/test_cases/q7/food_heuristic_9.solution create mode 100644 search/test_cases/q7/food_heuristic_9.test create mode 100644 search/test_cases/q7/food_heuristic_grade_tricky.solution create mode 100644 search/test_cases/q7/food_heuristic_grade_tricky.test create mode 100644 search/test_cases/q8/CONFIG create mode 100644 search/test_cases/q8/closest_dot_1.solution create mode 100644 search/test_cases/q8/closest_dot_1.test create mode 100644 search/test_cases/q8/closest_dot_10.solution create mode 100644 search/test_cases/q8/closest_dot_10.test create mode 100644 search/test_cases/q8/closest_dot_11.solution create mode 100644 search/test_cases/q8/closest_dot_11.test create mode 100644 search/test_cases/q8/closest_dot_12.solution create mode 100644 search/test_cases/q8/closest_dot_12.test create mode 100644 search/test_cases/q8/closest_dot_13.solution create mode 100644 search/test_cases/q8/closest_dot_13.test create mode 100644 search/test_cases/q8/closest_dot_2.solution create mode 100644 search/test_cases/q8/closest_dot_2.test create mode 100644 search/test_cases/q8/closest_dot_3.solution create mode 100644 search/test_cases/q8/closest_dot_3.test create mode 100644 search/test_cases/q8/closest_dot_4.solution create mode 100644 search/test_cases/q8/closest_dot_4.test create mode 100644 search/test_cases/q8/closest_dot_5.solution create mode 100644 search/test_cases/q8/closest_dot_5.test create mode 100644 search/test_cases/q8/closest_dot_6.solution create mode 100644 search/test_cases/q8/closest_dot_6.test create mode 100644 search/test_cases/q8/closest_dot_7.solution create mode 100644 search/test_cases/q8/closest_dot_7.test create mode 100644 search/test_cases/q8/closest_dot_8.solution create mode 100644 search/test_cases/q8/closest_dot_8.test create mode 100644 search/test_cases/q8/closest_dot_9.solution create mode 100644 search/test_cases/q8/closest_dot_9.test create mode 100644 search/textDisplay.py create mode 100644 search/util.py create mode 100644 search/util.pyc diff --git a/search/.idea/.gitignore b/search/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/search/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/search/.idea/inspectionProfiles/profiles_settings.xml b/search/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/search/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/search/.idea/misc.xml b/search/.idea/misc.xml new file mode 100644 index 0000000..7ba73c2 --- /dev/null +++ b/search/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/search/.idea/modules.xml b/search/.idea/modules.xml new file mode 100644 index 0000000..c3e7a57 --- /dev/null +++ b/search/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/search/.idea/search.iml b/search/.idea/search.iml new file mode 100644 index 0000000..86d1115 --- /dev/null +++ b/search/.idea/search.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/search/.idea/vcs.xml b/search/.idea/vcs.xml new file mode 100644 index 0000000..584ca7f --- /dev/null +++ b/search/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/search/VERSION b/search/VERSION new file mode 100644 index 0000000..7c7fa2f --- /dev/null +++ b/search/VERSION @@ -0,0 +1 @@ +v1.001 diff --git a/search/autograder.py b/search/autograder.py new file mode 100644 index 0000000..4abe64d --- /dev/null +++ b/search/autograder.py @@ -0,0 +1,358 @@ +# autograder.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). + + +# imports from python standard library +import grading +import imp +import optparse +import os +import re +import sys +import projectParams +import random +random.seed(0) +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.add_option('--test-directory', + 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') + parser.add_option('--code-directory', + 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') + parser.add_option('--generate-solutions', + 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') + parser.add_option('--gradescope-output', + 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') + parser.add_option('--print-tests', '-p', + 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.') + parser.add_option('--question', '-q', + 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.') + (options, args) = parser.parse_args(argv) + return options + + +# confirm we should author solution files +def confirmGenerate(): + print 'WARNING: this action will overwrite any solution files.' + print 'Are you sure you want to proceed? (yes/no)' + while True: + ans = sys.stdin.readline().strip() + if ans == 'yes': + break + elif ans == 'no': + sys.exit(0) + else: + print 'please answer either "yes" or "no"' + + +# TODO: Fix this so that it tracebacks work correctly +# Looking at source of the traceback module, presuming it works +# the same as the intepreters, it uses co_filename. This is, +# however, a readonly attribute. +def setModuleName(module, filename): + functionType = type(confirmGenerate) + classType = type(optparse.Option) + + for i in dir(module): + o = getattr(module, i) + 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) + + +#from cStringIO import StringIO + +def loadModuleString(moduleSource): + # Below broken, imp doesn't believe its being passed a file: + # ValueError: load_module arg#2 should be a file or None + # + #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__ + 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)) + + +def readFile(path, root=""): + "Read file from disk at specified path and return as string" + with open(os.path.join(root, path), 'r') as handle: + return handle.read() + + +####################################################################### +# Error Hint Map +####################################################################### + +# TODO: use these +ERROR_HINT_MAP = { + '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 + or assuming a certain number of actions available from a given + state. Try making your code more general (no hardcoded indices) + and submit again! + """ + }, + '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 + a line of code assuming that the state is (x, y) and we run your code + on a state space with (x, y, z), this error could be thrown. Try + making your code more general and submit again! + + """ + } +} + +import pprint + +def splitStrings(d): + d2 = dict(d) + for k in d: + if k[0:2] == "__": + del d2[k] + continue + if d2[k].find("\n") >= 0: + d2[k] = d2[k].split("\n") + return d2 + + +def printTest(testDict, solutionDict): + pp = pprint.PrettyPrinter(indent=4) + print "Test case:" + for line in testDict["__raw_lines__"]: + print " |", line + print "Solution:" + for line in solutionDict["__raw_lines__"]: + print " |", line + + +def runTest(testName, moduleDict, printTestCase=False, display=None): + import testParser + import testClasses + for module in moduleDict: + setattr(sys.modules[__name__], module, moduleDict[module]) + + testDict = testParser.TestParser(testName + ".test").parse() + solutionDict = testParser.TestParser(testName + ".solution").parse() + test_out_file = os.path.join('%s.test_output' % testName) + testDict['test_out_file'] = test_out_file + testClass = getattr(projectTestClasses, testDict['class']) + + questionClass = getattr(testClasses, 'Question') + question = questionClass({'max_points': 0}, display) + testCase = testClass(question, testDict) + + if printTestCase: + printTest(testDict, solutionDict) + + # This is a fragile hack to create a stub grades object + 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() + if 'depends' in questionDict: + depends = questionDict['depends'].split() + for d in depends: + # run dependencies first + allDeps = getDepends(testParser, testRoot, d) + allDeps + return allDeps + +# get list of questions to grade +def getTestSubdirs(testParser, testRoot, questionToGrade): + 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) + return questions + if 'order' in problemDict: + return problemDict['order'].split() + return sorted(os.listdir(testRoot)) + + +# evaluate student code +def evaluate(generateSolutions, testRoot, moduleDict, exceptionMap=ERROR_HINT_MAP, + edxOutput=False, muteOutput=False, gsOutput=False, + 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 + import testClasses + for module in moduleDict: + setattr(sys.modules[__name__], module, moduleDict[module]) + + questions = [] + questionDicts = {} + test_subdirs = getTestSubdirs(testParser, testRoot, questionToGrade) + for q in test_subdirs: + subdir_path = os.path.join(testRoot, q) + if not os.path.isdir(subdir_path) or q[0] == '.': + continue + + # create a question object + 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) + 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) + test_out_file = os.path.join(subdir_path, '%s.test_output' % t) + testDict = testParser.TestParser(test_file).parse() + if testDict.get("disabled", "false").lower() == "true": + continue + 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 + return lambda grades: testCase.writeSolution(moduleDict, solution_file) + else: + # read in solution dictionary and pass as an argument + testDict = testParser.TestParser(test_file).parse() + solutionDict = testParser.TestParser(solution_file).parse() + if printTestCase: + return lambda grades: printTest(testDict, solutionDict) or testCase.execute(grades, moduleDict, solutionDict) + else: + return lambda grades: testCase.execute(grades, moduleDict, solutionDict) + question.addTestCase(testCase, makefun(testCase, solution_file)) + + # Note extra function is necessary for scoping reasons + def makefun(question): + return lambda grades: question.execute(grades) + setattr(sys.modules[__name__], q, makefun(question)) + questions.append((q, question.getMaxPoints())) + + grades = grading.Grades(projectParams.PROJECT_NAME, questions, + gsOutput=gsOutput, edxOutput=edxOutput, muteOutput=muteOutput) + if questionToGrade == None: + for q in questionDicts: + for prereq in questionDicts[q].get('depends', '').split(): + grades.addPrereq(q, prereq) + + 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: + graphics = False + if graphics: + try: + import graphicsDisplay + return graphicsDisplay.PacmanGraphics(1, frameTime=.05) + except ImportError: + pass + import textDisplay + return textDisplay.NullGraphics() + + + + +if __name__ == '__main__': + options = readCommand(sys.argv) + if options.generateSolutions: + confirmGenerate() + codePaths = options.studentCode.split(',') + # moduleCodeDict = {} + # for cp in codePaths: + # moduleName = re.match('.*?([^/]*)\.py', cp).group(1) + # moduleCodeDict[moduleName] = readFile(cp, root=options.codeRoot) + # moduleCodeDict['projectTestClasses'] = readFile(options.testCaseCode, root=options.codeRoot) + # moduleDict = loadModuleDict(moduleCodeDict) + + moduleDict = {} + for cp in codePaths: + moduleName = re.match('.*?([^/]*)\.py', cp).group(1) + 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)) + + + if options.runTest != None: + 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)) diff --git a/search/commands.txt b/search/commands.txt new file mode 100644 index 0000000..d5c70e2 --- /dev/null +++ b/search/commands.txt @@ -0,0 +1,22 @@ +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 +python pacman.py -l bigSearch -p ApproximateSearchAgent -z .5 -q diff --git a/search/eightpuzzle.py b/search/eightpuzzle.py new file mode 100644 index 0000000..6aa376c --- /dev/null +++ b/search/eightpuzzle.py @@ -0,0 +1,281 @@ +# 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) + + raw_input("Press return for the next state...") # wait for key stroke + i += 1 diff --git a/search/game.py b/search/game.py new file mode 100644 index 0000000..e34d6cf --- /dev/null +++ b/search/game.py @@ -0,0 +1,729 @@ +# game.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). + + +# game.py +# ------- +# Licensing Information: Please do not distribute or publish solutions to this +# project. You are free to use and extend these projects for educational +# purposes. The Pacman AI projects were developed at UC Berkeley, primarily by +# John DeNero (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# For more info, see http://inst.eecs.berkeley.edu/~cs188/sp09/pacman.html + +from util import * +import time, os +import traceback +import sys + +####################### +# Parts worth reading # +####################### + +class Agent: + """ + An agent must define a getAction method, but may also define the + following methods which will be called if they exist: + + def registerInitialState(self, state): # inspects the starting state + """ + def __init__(self, index=0): + self.index = index + + def getAction(self, state): + """ + The Agent will receive a GameState (from either {pacman, capture, sonar}.py) and + must return an action from Directions.{North, South, East, West, Stop} + """ + raiseNotDefined() + +class Directions: + NORTH = 'North' + SOUTH = 'South' + EAST = 'East' + WEST = 'West' + STOP = 'Stop' + + LEFT = {NORTH: WEST, + SOUTH: EAST, + EAST: NORTH, + WEST: SOUTH, + STOP: STOP} + + RIGHT = dict([(y,x) for x, y in LEFT.items()]) + + REVERSE = {NORTH: SOUTH, + SOUTH: NORTH, + EAST: WEST, + WEST: EAST, + STOP: STOP} + +class Configuration: + """ + A Configuration holds the (x,y) coordinate of a character, along with its + traveling direction. + + The convention for positions, like a graph, is that (0,0) is the lower left corner, x increases + horizontally and y increases vertically. Therefore, north is the direction of increasing y, or (0,1). + """ + + def __init__(self, pos, direction): + self.pos = pos + self.direction = direction + + def getPosition(self): + return (self.pos) + + def getDirection(self): + return self.direction + + def isInteger(self): + x,y = self.pos + return x == int(x) and y == int(y) + + def __eq__(self, other): + if other == None: return False + return (self.pos == other.pos and self.direction == other.direction) + + def __hash__(self): + x = hash(self.pos) + y = hash(self.direction) + return hash(x + 13 * y) + + def __str__(self): + return "(x,y)="+str(self.pos)+", "+str(self.direction) + + def generateSuccessor(self, vector): + """ + Generates a new configuration reached by translating the current + configuration by the action vector. This is a low-level call and does + not attempt to respect the legality of the movement. + + Actions are movement vectors. + """ + x, y= self.pos + dx, dy = vector + direction = Actions.vectorToDirection(vector) + if direction == Directions.STOP: + 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 ): + self.start = startConfiguration + self.configuration = startConfiguration + self.isPacman = isPacman + self.scaredTimer = 0 + self.numCarrying = 0 + self.numReturned = 0 + + def __str__( self ): + if self.isPacman: + return "Pacman: " + str( self.configuration ) + else: + return "Ghost: " + str( self.configuration ) + + def __eq__( self, other ): + if other == None: + return False + return self.configuration == other.configuration and self.scaredTimer == other.scaredTimer + + def __hash__(self): + return hash(hash(self.configuration) + 13 * hash(self.scaredTimer)) + + def copy( self ): + state = AgentState( self.start, self.isPacman ) + state.configuration = self.configuration + state.scaredTimer = self.scaredTimer + state.numCarrying = self.numCarrying + state.numReturned = self.numReturned + return state + + def getPosition(self): + 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 + via grid[x][y] where (x,y) are positions on a Pacman map with x horizontal, + y vertical and the origin (0,0) in the bottom left corner. + + 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') + self.CELLS_PER_INT = 30 + + self.width = width + self.height = height + self.data = [[initialValue for y in range(height)] for x in range(width)] + if bitRepresentation: + self._unpackBits(bitRepresentation) + + def __getitem__(self, i): + return self.data[i] + + def __setitem__(self, key, item): + 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.reverse() + return '\n'.join([''.join(x) for x in out]) + + def __eq__(self, other): + if other == None: return False + return self.data == other.data + + def __hash__(self): + # return hash(str(self)) + base = 1 + h = 0 + for l in self.data: + for i in l: + if i: + h += base + base *= 2 + return hash(h) + + def copy(self): + g = Grid(self.width, self.height) + g.data = [x[:] for x in self.data] + return g + + def deepCopy(self): + return self.copy() + + def shallowCopy(self): + g = Grid(self.width, self.height) + g.data = self.data + return g + + def count(self, item =True ): + return sum([x.count(item) for x in self.data]) + + 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) ) + return list + + def packBits(self): + """ + Returns an efficient int list representation + + (width, height, bitPackedInts...) + """ + bits = [self.width, self.height] + currentInt = 0 + for i in range(self.height * self.width): + bit = self.CELLS_PER_INT - (i % self.CELLS_PER_INT) - 1 + x, y = self._cellIndexToPosition(i) + if self[x][y]: + currentInt += 2 ** bit + if (i + 1) % self.CELLS_PER_INT == 0: + bits.append(currentInt) + currentInt = 0 + bits.append(currentInt) + return tuple(bits) + + def _cellIndexToPosition(self, index): + x = index / self.height + y = index % self.height + return x, y + + def _unpackBits(self, bits): + """ + Fills in data from a bit-level representation + """ + cell = 0 + for packed in bits: + for bit in self._unpackInt(packed, self.CELLS_PER_INT): + 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" + for i in range(size): + n = 2 ** (self.CELLS_PER_INT - i - 1) + if packed >= n: + bools.append(True) + packed -= n + else: + bools.append(False) + return bools + +def reconstituteGrid(bitRep): + if type(bitRep) is not type((1,2)): + return bitRep + width, height = 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.EAST: (1, 0), + Directions.WEST: (-1, 0), + Directions.STOP: (0, 0)} + + _directionsAsList = _directions.items() + + TOLERANCE = .001 + + def reverseDirection(action): + if action == Directions.NORTH: + return Directions.SOUTH + if action == Directions.SOUTH: + return Directions.NORTH + if action == Directions.EAST: + return Directions.WEST + if action == Directions.WEST: + return Directions.EAST + return action + reverseDirection = staticmethod(reverseDirection) + + def vectorToDirection(vector): + dx, dy = vector + if dy > 0: + return Directions.NORTH + if dy < 0: + return Directions.SOUTH + if dx < 0: + return Directions.WEST + if dx > 0: + return Directions.EAST + return Directions.STOP + vectorToDirection = staticmethod(vectorToDirection) + + def directionToVector(direction, speed = 1.0): + dx, dy = Actions._directions[direction] + return (dx * speed, dy * speed) + directionToVector = staticmethod(directionToVector) + + def getPossibleActions(config, walls): + possible = [] + x, y = config.pos + 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): + 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) + + return possible + + getPossibleActions = staticmethod(getPossibleActions) + + def getLegalNeighbors(position, walls): + 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 + 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)) + return neighbors + getLegalNeighbors = staticmethod(getLegalNeighbors) + + def getSuccessor(position, action): + dx, dy = Actions.directionToVector(action) + x, y = position + return (x + dx, y + dy) + getSuccessor = staticmethod(getSuccessor) + +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.layout = prevState.layout + self._eaten = prevState._eaten + self.score = prevState.score + + self._foodEaten = None + self._foodAdded = None + self._capsuleEaten = None + self._agentMoved = None + self._lose = False + self._win = False + self.scoreChange = 0 + + def deepCopy( self ): + state = GameStateData( self ) + state.food = self.food.deepCopy() + state.layout = self.layout.deepCopy() + state._agentMoved = self._agentMoved + state._foodEaten = self._foodEaten + state._foodAdded = self._foodAdded + state._capsuleEaten = self._capsuleEaten + return state + + def copyAgentStates( self, agentStates ): + copiedStates = [] + for agentState in agentStates: + copiedStates.append( agentState.copy() ) + return copiedStates + + def __eq__( self, other ): + """ + Allows two states to be compared. + """ + 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 + return True + + def __hash__( self ): + """ + Allows states to be keys of dictionaries. + """ + for i, state in enumerate( self.agentStates ): + try: + int(hash(state)) + except TypeError, 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 ) + + def __str__( self ): + width, height = self.layout.width, self.layout.height + map = Grid(width, height) + if type(self.food) == type((1,2)): + self.food = reconstituteGrid(self.food) + for x in range(width): + for y in range(height): + food, walls = self.food, self.layout.walls + 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 )] + agent_dir = agentState.configuration.direction + if agentState.isPacman: + map[x][y] = self._pacStr( agent_dir ) + else: + 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 ): + if hasFood: + return '.' + elif hasWall: + return '%' + else: + return ' ' + + def _pacStr( self, dir ): + if dir == Directions.NORTH: + return 'v' + if dir == Directions.SOUTH: + return '^' + if dir == Directions.WEST: + return '>' + return '<' + + def _ghostStr( self, dir ): + return 'G' + if dir == Directions.NORTH: + return 'M' + if dir == Directions.SOUTH: + return 'W' + if dir == Directions.WEST: + return '3' + return 'E' + + def initialize( self, layout, numGhostAgents ): + """ + Creates an initial game state from a layout array (see layout.py). + """ + self.food = layout.food.copy() + #self.capsules = [] + self.capsules = layout.capsules[:] + self.layout = layout + self.score = 0 + self.scoreChange = 0 + + self.agentStates = [] + 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) ) + 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 ): + self.agentCrashed = False + self.agents = agents + self.display = display + self.rules = rules + self.startingIndex = startingIndex + self.gameOver = False + self.muteAgents = muteAgents + self.catchExceptions = catchExceptions + self.moveHistory = [] + self.totalAgentTimes = [0 for agent in agents] + self.totalAgentTimeWarnings = [0 for agent in agents] + self.agentTimeout = False + import cStringIO + self.agentOutput = [cStringIO.StringIO() for agent in agents] + + def getProgress(self): + if self.gameOver: + return 1.0 + else: + return self.rules.getProgress(self) + + def _agentCrash( self, agentIndex, quiet=False): + "Helper method for handling agent crashes" + if not quiet: traceback.print_exc() + self.gameOver = True + self.agentCrashed = True + self.rules.agentCrash(self, agentIndex) + + OLD_STDOUT = None + OLD_STDERR = None + + def mute(self, agentIndex): + if not self.muteAgents: return + global OLD_STDOUT, OLD_STDERR + import cStringIO + OLD_STDOUT = sys.stdout + OLD_STDERR = sys.stderr + sys.stdout = self.agentOutput[agentIndex] + sys.stderr = self.agentOutput[agentIndex] + + def unmute(self): + 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 ): + """ + Main control loop for game play. + """ + self.display.initialize(self.state.data) + self.numMoves = 0 + + ###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] + if not agent: + self.mute(i) + # this is a null agent, meaning it failed to load + # the other team wins + print >>sys.stderr, "Agent %d failed to load" % i + self.unmute() + self._agentCrash(i, quiet=True) + return + if ("registerInitialState" in dir(agent)): + self.mute(i) + if self.catchExceptions: + try: + 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 >>sys.stderr, "Agent %d ran out of time on startup!" % i + self.unmute() + self.agentTimeout = True + self._agentCrash(i, quiet=True) + return + except Exception,data: + self._agentCrash(i, quiet=False) + self.unmute() + return + else: + agent.registerInitialState(self.state.deepCopy()) + ## TODO: could this exceed the total time + self.unmute() + + agentIndex = self.startingIndex + numAgents = len( self.agents ) + + while not self.gameOver: + # Fetch the next agent + agent = self.agents[agentIndex] + move_time = 0 + skip_action = False + # Generate an observation of the state + if 'observationFunction' in dir( agent ): + self.mute(agentIndex) + if self.catchExceptions: + try: + timed_func = TimeoutFunction(agent.observationFunction, int(self.rules.getMoveTimeout(agentIndex))) + try: + start_time = time.time() + observation = timed_func(self.state.deepCopy()) + except TimeoutFunctionException: + skip_action = True + move_time += time.time() - start_time + self.unmute() + except Exception,data: + self._agentCrash(agentIndex, quiet=False) + self.unmute() + return + else: + observation = agent.observationFunction(self.state.deepCopy()) + self.unmute() + else: + observation = self.state.deepCopy() + + # Solicit an action + action = None + self.mute(agentIndex) + if self.catchExceptions: + try: + 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 ) + except TimeoutFunctionException: + print >>sys.stderr, "Agent %d timed out on a single move!" % agentIndex + self.agentTimeout = True + self._agentCrash(agentIndex, quiet=True) + self.unmute() + return + + move_time += time.time() - start_time + + if move_time > self.rules.getMoveWarningTime(agentIndex): + self.totalAgentTimeWarnings[agentIndex] += 1 + print >>sys.stderr, "Agent %d took too long to make a move! This is warning %d" % (agentIndex, self.totalAgentTimeWarnings[agentIndex]) + if self.totalAgentTimeWarnings[agentIndex] > self.rules.getMaxTimeWarnings(agentIndex): + print >>sys.stderr, "Agent %d exceeded the maximum number of warnings: %d" % (agentIndex, self.totalAgentTimeWarnings[agentIndex]) + 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]) + if self.totalAgentTimes[agentIndex] > self.rules.getMaxTotalTime(agentIndex): + print >>sys.stderr, "Agent %d ran out of time! (time: %1.2f)" % (agentIndex, self.totalAgentTimes[agentIndex]) + self.agentTimeout = True + self._agentCrash(agentIndex, quiet=True) + self.unmute() + return + self.unmute() + except Exception,data: + self._agentCrash(agentIndex) + self.unmute() + return + else: + action = agent.getAction(observation) + self.unmute() + + # Execute the action + self.moveHistory.append( (agentIndex, action) ) + if self.catchExceptions: + try: + self.state = self.state.generateSuccessor( agentIndex, action ) + except Exception,data: + self.mute(agentIndex) + self._agentCrash(agentIndex) + self.unmute() + return + else: + self.state = self.state.generateSuccessor( agentIndex, action ) + + # Change the display + 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 + # Next agent + 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 ) : + try: + self.mute(agentIndex) + agent.final( self.state ) + self.unmute() + except Exception,data: + if not self.catchExceptions: raise + self._agentCrash(agentIndex) + self.unmute() + return + self.display.finish() diff --git a/search/game.pyc b/search/game.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65e17d8812aabddbb570fad807b593eded146353 GIT binary patch literal 23225 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 LNo^His#5qrz=s`p literal 0 HcmV?d00001 diff --git a/search/ghostAgents.py b/search/ghostAgents.py new file mode 100644 index 0000000..c3afe1f --- /dev/null +++ b/search/ghostAgents.py @@ -0,0 +1,81 @@ +# ghostAgents.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 game import Agent +from game import Actions +from game import Directions +import random +from util import manhattanDistance +import util + +class GhostAgent( Agent ): + def __init__( self, index ): + self.index = index + + def getAction( self, state ): + dist = self.getDistribution(state) + if len(dist) == 0: + return Directions.STOP + else: + 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 ): + "A ghost that chooses a legal action uniformly at random." + def getDistribution( self, state ): + dist = util.Counter() + for a in state.getLegalActions( self.index ): dist[a] = 1.0 + dist.normalize() + return dist + +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 ): + self.index = index + self.prob_attack = prob_attack + self.prob_scaredFlee = prob_scaredFlee + + def getDistribution( self, state ): + # Read variables from state + 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 + + 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] + if isScared: + bestScore = max( distancesToPacman ) + bestProb = self.prob_scaredFlee + else: + bestScore = min( distancesToPacman ) + bestProb = self.prob_attack + 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) + dist.normalize() + return dist diff --git a/search/ghostAgents.pyc b/search/ghostAgents.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c46287ff7785de7b285052a0260cb16bd87273cf GIT binary patch literal 3341 zcmbtW-EJF26h5=-pEz;iB#^c#5-g>qR#gHQl?qivNgEX*p)^`YL|CEL#yfV_wRe-9 zNt;&oRS@q07d!{tam!n9%N-IA0N**|pO(9nO=diEX6DTK`OZ1x|GhYW@0Z{9+cf@s z{C*xkuD3hGNsN@JU^i>OsN%$3)HArA!70mzPiH57SU~Wb!y$T z%+t0_veY=jJP6xKt{rX15m!JQMCnmvZIo^&27Oyw-umTHW~}g=8i%iWfMz~Gr-^L> zlRyI)1BT*(&lciAfxNqfzeUkKAQY=r_!5^;}>=g+gq(9O>C=m8DqoDNr`MM zBu_=Q&oF>sJ(2KS(a0kUQ9Z&KDn9inuaott=Tig1^@`)QMojPsv)M_|QN4uD*3fme zWxM9d;VC=A@^yWkhEw$#dyjWTPptRtB`mj(vdrj5c{X_Uq*yZ)zHAJ*%4#_mgZ-PE zrs8CDP`S#C*;u4%YE_lJsrT6TVxc7rEG(oLw+c3KYMaNPhuWUzsR^RsVRo8Yod-H? zXK|8tL1Hl{RtU0ZSd1JLgAOze?2!(R^Xyp?>o^eQHg?3I;R4^trp%+n=$*`N>rRsD z*sZcbLWa~En;>L`-$!$(@ak;dF=Wzcpj#~oh*oQm#ixBtLyoPGC6c4Fi)C~{Y=#VR z_PSwBN~+>l%9d3QqcqM25{7L|<(ozzgIG@@@YV1`)G@Nmr|7l<2?LlmvVj8?`=+nE zQGaaw;51D-Sw85$2(TxYD>uaHEEczi%xw$Z)ai(cv+EqeJx^lA=iu1>Zka}iehHSL zPn#$2(LUm)R}h?FG!Bn0SmFEYzL?oLm+d)5%p_*MW+BJ4rP*aE+^^=#n&Z0>$ zi0?x|C0i$&dE=svU>Mv)Go1cNRn~sH95DE@LoF)KUL+1o&8dz}r7W_a6kn_?&%FoZtw5mWG+L;mr0LAdYk0(YXn1 z7UZYqDA=7L~5n@k)3jx5+MWR3>6nT$EB^nkf zZ?ZEmPEicN)<>*dp;4JDb`LwsG%V4%M^8LDiD)z@o93|T7H=8~%XRDm=k?1x^+=}p zx!iHbexOlBBr0>Tjpl_#1uWKBFr+dZ8_rKI`JF}!BABNTRKo?4zbc_TPoqUj*9Zyd zHF}ll5Z*3|XK};>_jl<4N-oi;Mnn8pr99qL!zIz>rW!4iU7}u1gj%7qYcyQOv8$rj zA_3@_!+2}M6*j}>$rH7IcH3F#x@;0UoU{(5hl_NDk4U;%yX$YBoU47D?5!|=g;7I5 z;|g%Xn1jUp{c*o8k;_#An2Gmc$Ue_Bs9lb$064XI1l+zYOWL72%A(tpU7+AE<~mz zf(dP`FDf!#hGs8w8cH@k)W$a2S+3<)p6w#2E!Q!3jnKL7%d3*D$(trwo$q?{Xl6z4 zpqWq5k++KH%Bre)$e>j5Zm7Ge>R&@Pt*WY5MWo;Hs|o-@yT&_KPhgZPDRdr@N z6G}!G%`@v@@e$g%pqEswSm%-=kF_oy6d@)gU~;cOHkd2D4hf7Jc@~6R975*z|3nf$ ZY`W*m=lpIlTw|6M|5dqpmui>h{sk>5r)&TK literal 0 HcmV?d00001 diff --git a/search/grading.py b/search/grading.py new file mode 100644 index 0000000..b63c877 --- /dev/null +++ b/search/grading.py @@ -0,0 +1,323 @@ +# grading.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). + + +"Common code for autograders" + +import cgi +import time +import sys +import json +import traceback +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) + + #print 'Autograder transcript for %s' % self.project + print 'Starting on %d-%d at %d:%02d:%02d' % self.start + + def addPrereq(self, question, prereq): + self.prereqs[question].add(prereq) + + def grade(self, gradingModule, exceptionMap = {}, bonusPic = False): + """ + Grades each question + gradingModule: the module with all the grading functions (pass in with sys.modules[__name__]) + """ + + 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 + + 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, 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) + + 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==================" + + 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. + + --- ---- --- + | \ / + \ / | + | + \--/ \--/ + | + | + + | + | + + + | + @@@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + \ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + \ / @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + V \ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ + \ / @@@@@@@@@@@@@@@@@@@@@@@@@@ + V @@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@ + /\ @@@@@@@@@@@@@@@@@@@@@@ + / \ @@@@@@@@@@@@@@@@@@@@@@@@@ + /\ / @@@@@@@@@@@@@@@@@@@@@@@@@@@ + / \ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + / @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@ + +""" + 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() + + 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 = ''
+
+    # 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 ''
+
+    for line in errorHint.split('\n'):
+      self.addMessage(line)
+
+  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)
+
+    # 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
+
+  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 = """ +

+ Total score ({total_score} / {total_possible}) +

+ """.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 = """ +
+
+
+ Question {q} ({points}/{max}) {checkOrX} +
+
+ {messages} +
+
+
+ """.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 assignZeroCredit(self): + self.points[self.currentQuestion] = 0 + + 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) + + + + + +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. + """ + return sum(self.values()) + diff --git a/search/graphicsDisplay.py b/search/graphicsDisplay.py new file mode 100644 index 0000000..1bfe1b3 --- /dev/null +++ b/search/graphicsDisplay.py @@ -0,0 +1,679 @@ +# graphicsDisplay.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 graphicsUtils import * +import math, time +from game import Directions + +########################### +# GRAPHICS DISPLAY CODE # +########################### + +# Most code by Dan Klein and John Denero written or rewritten for cs188, UC Berkeley. +# Some code from a Pacman implementation by LiveWires, and used / modified with permission. + +DEFAULT_GRID_SIZE = 30.0 +INFO_PANE_HEIGHT = 35 +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) +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 + +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 ) + ] +GHOST_SIZE = 0.65 +SCARED_COLOR = formatColor(1,1,1) + +GHOST_VEC_COLORS = map(colorToVector, GHOST_COLORS) + +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_SIZE = 0.1 + +# Laser +LASER_COLOR = formatColor(1,0,0) +LASER_SIZE = 0.02 + +# Capsule graphics +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 + self.width = (layout.width) * gridSize + self.base = (layout.height + 1) * gridSize + self.height = INFO_PANE_HEIGHT + self.fontSize = 24 + self.textColor = PACMAN_COLOR + self.drawPane() + + def toScreen(self, pos, y = None): + """ + Translates a point relative from the bottom left of the info pane. + """ + if y == None: + x,y = pos + else: + x = pos + + x = self.gridSize + x # Margin + y = self.base + y + return x,y + + def drawPane(self): + self.scoreText = text( self.toScreen(0, 0 ), self.textColor, "SCORE: 0", "Times", self.fontSize, "bold") + + def initializeGhostDistances(self, distances): + self.ghostDistanceText = [] + + size = 20 + if self.width < 240: + size = 12 + if self.width < 160: + 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") + self.ghostDistanceText.append(t) + + def updateScore(self, score): + changeText(self.scoreText, "SCORE: % 4d" % score) + + 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") + + def updateGhostDistances(self, 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) + + def drawGhost(self): + pass + + def drawPacman(self): + pass + + def drawWarning(self): + pass + + def clearIcon(self): + pass + + def updateMessage(self, message): + pass + + def clearMessage(self): + pass + + +class PacmanGraphics: + def __init__(self, zoom=1.0, frameTime=0.0, capture=False): + self.have_window = 0 + self.currentGhostImages = {} + self.pacmanImage = None + self.zoom = zoom + self.gridSize = DEFAULT_GRID_SIZE * zoom + self.capture = capture + self.frameTime = frameTime + + def checkNullDisplay(self): + return False + + def initialize(self, state, isBlue = False): + self.isBlue = isBlue + self.startGraphics(state) + + # self.drawDistributions(state) + self.distributionImages = None # Initialized lazily + self.drawStaticObjects(state) + self.drawAgentObjects(state) + + # Information + self.previousState = state + + def startGraphics(self, state): + self.layout = state.layout + layout = self.layout + self.width = layout.width + self.height = layout.height + self.make_window(self.width, self.height) + self.infoPane = InfoPane(layout, self.gridSize) + self.currentState = layout + + def drawDistributions(self, state): + walls = state.layout.walls + dist = [] + for x in range(walls.width): + 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) + distx.append(block) + self.distributionImages = dist + + def drawStaticObjects(self, state): + layout = self.layout + self.drawWalls(layout.walls) + self.food = self.drawFood(layout.food) + self.capsules = self.drawCapsules(layout.capsules) + refresh() + + def drawAgentObjects(self, state): + self.agentImages = [] # (agentState, image) + for index, agent in enumerate(state.agentStates): + if agent.isPacman: + image = self.drawPacman(agent, index) + self.agentImages.append( (agent, image) ) + else: + image = self.drawGhost(agent, index) + self.agentImages.append( (agent, image) ) + refresh() + + def swapImages(self, agentIndex, newState): + """ + 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) + if newState.isPacman: + image = self.drawPacman(newState, agentIndex) + self.agentImages[agentIndex] = (newState, image ) + else: + image = self.drawGhost(newState, agentIndex) + 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) + prevState, prevImage = self.agentImages[agentIndex] + if agentState.isPacman: + self.animatePacman(agentState, prevState, prevImage) + else: + self.moveGhost(agentState, agentIndex, prevState, prevImage) + self.agentImages[agentIndex] = (agentState, prevImage) + + if newState._foodEaten != None: + self.removeFood(newState._foodEaten, self.food) + if newState._capsuleEaten != None: + self.removeCapsule(newState._capsuleEaten, self.capsules) + self.infoPane.updateScore(newState.score) + if 'ghostDistances' in dir(newState): + self.infoPane.updateGhostDistances(newState.ghostDistances) + + def make_window(self, width, height): + grid_width = (width-1) * self.gridSize + grid_height = (height-1) * self.gridSize + screen_width = 2*self.gridSize + grid_width + screen_height = 2*self.gridSize + grid_height + INFO_PANE_HEIGHT + + begin_graphics(screen_width, + screen_height, + BACKGROUND_COLOR, + "CS188 Pacman") + + def drawPacman(self, pacman, index): + position = self.getPosition(pacman) + screen_point = self.to_screen(position) + endpoints = self.getEndpoints(self.getDirection(pacman)) + + width = PACMAN_OUTLINE_WIDTH + outlineColor = PACMAN_COLOR + fillColor = PACMAN_COLOR + + if self.capture: + outlineColor = TEAM_COLORS[index % 2] + fillColor = GHOST_COLORS[index] + width = PACMAN_CAPTURE_OUTLINE_WIDTH + + return [circle(screen_point, PACMAN_SCALE * self.gridSize, + fillColor = fillColor, outlineColor = outlineColor, + endpoints = endpoints, + width = width)] + + 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) + + delta = width / 2 + if (direction == 'West'): + endpoints = (180+delta, 180-delta) + elif (direction == 'North'): + endpoints = (90+delta, 90-delta) + elif (direction == 'South'): + endpoints = (270+delta, 270-delta) + else: + endpoints = (0+delta, 0-delta) + return endpoints + + def movePacman(self, position, direction, image): + screenPosition = self.to_screen(position) + endpoints = self.getEndpoints( direction, position ) + r = PACMAN_SCALE * self.gridSize + moveCircle(image[0], screenPosition, r, endpoints) + refresh() + + def animatePacman(self, pacman, prevPacman, image): + if self.frameTime < 0: + print 'Press any key to step forward, "q" to play' + keys = wait_for_keys() + if 'q' in keys: + self.frameTime = 0.1 + if self.frameTime > 0.01 or self.frameTime < 0: + start = time.time() + 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 + self.movePacman(pos, self.getDirection(pacman), image) + refresh() + sleep(abs(self.frameTime) / frames) + else: + self.movePacman(self.getPosition(pacman), self.getDirection(pacman), image) + refresh() + + def getGhostColor(self, ghost, ghostIndex): + if ghost.scaredTimer > 0: + return SCARED_COLOR + else: + return GHOST_COLORS[ghostIndex] + + def drawGhost(self, ghost, agentIndex): + pos = self.getPosition(ghost) + dir = self.getDirection(ghost) + (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)) + + colour = self.getGhostColor(ghost, agentIndex) + body = polygon(coords, colour, filled = 1) + WHITE = formatColor(1.0, 1.0, 1.0) + BLACK = formatColor(0.0, 0.0, 0.0) + + dx = 0 + dy = 0 + if dir == 'North': + dy = -0.2 + if dir == 'South': + dy = 0.2 + if dir == 'East': + 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) + ghostImageParts = [] + ghostImageParts.append(body) + ghostImageParts.append(leftEye) + ghostImageParts.append(rightEye) + ghostImageParts.append(leftPupil) + ghostImageParts.append(rightPupil) + + return ghostImageParts + + def moveEyes(self, pos, dir, eyes): + (screen_x, screen_y) = (self.to_screen(pos) ) + dx = 0 + dy = 0 + if dir == 'North': + dy = -0.2 + if dir == 'South': + dy = 0.2 + if dir == 'East': + 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) + + def moveGhost(self, ghost, ghostIndex, prevGhost, ghostImageParts): + old_x, old_y = self.to_screen(self.getPosition(prevGhost)) + new_x, new_y = self.to_screen(self.getPosition(ghost)) + delta = new_x - old_x, new_y - old_y + + for ghostImagePart in ghostImageParts: + move_by(ghostImagePart, delta) + refresh() + + if ghost.scaredTimer > 0: + color = SCARED_COLOR + else: + color = GHOST_COLORS[ghostIndex] + edit(ghostImageParts[0], ('fill', color), ('outline', color)) + self.moveEyes(self.getPosition(ghost), self.getDirection(ghost), ghostImageParts[-4:]) + refresh() + + def getPosition(self, agentState): + if agentState.configuration == None: return (-1000, -1000) + return agentState.getPosition() + + def getDirection(self, agentState): + if agentState.configuration == None: return Directions.STOP + return agentState.configuration.getDirection() + + def finish(self): + end_graphics() + + def to_screen(self, point): + ( x, y ) = point + #y = self.height - y + x = (x + 1)*self.gridSize + 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 + #y = self.height - y + x = (x + 1)*self.gridSize + 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] + + for yNum, cell in enumerate(x): + if cell: # There's a wall here + pos = (xNum, yNum) + screen = self.to_screen(pos) + screen2 = self.to_screen2(pos) + + # draw each quadrant of the square based on adjacent walls + wIsWall = self.isWall(xNum-1, yNum, wallMatrix) + eIsWall = self.isWall(xNum+1, yNum, wallMatrix) + nIsWall = self.isWall(xNum, yNum+1, wallMatrix) + sIsWall = self.isWall(xNum, yNum-1, wallMatrix) + nwIsWall = self.isWall(xNum-1, yNum+1, wallMatrix) + swIsWall = self.isWall(xNum-1, yNum-1, wallMatrix) + neIsWall = self.isWall(xNum+1, yNum+1, wallMatrix) + seIsWall = self.isWall(xNum+1, yNum-1, wallMatrix) + + # NE quadrant + if (not nIsWall) and (not eIsWall): + # inner circle + 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) + 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) + 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) + + # NW quadrant + if (not nIsWall) and (not wIsWall): + # inner circle + 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) + 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) + 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) + + # SE quadrant + if (not sIsWall) and (not eIsWall): + # inner circle + 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) + 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) + 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) + + # SW quadrant + if (not sIsWall) and (not wIsWall): + # inner circle + 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) + 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) + 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) + + def isWall(self, x, y, walls): + if x < 0 or y < 0: + return False + if x >= walls.width or y >= walls.height: + return False + return walls[x][y] + + 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] + 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) + imageRow.append(dot) + else: + imageRow.append(None) + return foodImages + + 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) + capsuleImages[capsule] = dot + return capsuleImages + + def removeFood(self, cell, foodImages ): + x, y = cell + remove_from_screen(foodImages[x][y]) + + def removeCapsule(self, cell, capsuleImages ): + x, y = cell + remove_from_screen(capsuleImages[(x, y)]) + + def drawExpandedCells(self, cells): + """ + Draws an overlay of expanded grid positions for search agents + """ + n = float(len(cells)) + baseColor = [1.0, 0.0, 0.0] + 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]) + block = square(screenPos, + 0.5 * self.gridSize, + color = cellColor, + filled = 1, behind=2) + self.expandedCells.append(block) + if self.frameTime < 0: + refresh() + + def clearExpandedCells(self): + if 'expandedCells' in dir(self) and len(self.expandedCells) > 0: + 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) + 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] + + 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 + for weight, gcolor in zip(weights, colors): + 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): + PacmanGraphics.__init__(self, zoom, frameTime=frameTime) + self.showGhosts = showGhosts + self.capture = capture + + def initialize(self, state, isBlue = False): + + self.isBlue = isBlue + PacmanGraphics.startGraphics(self, state) + # Initialize distribution images + walls = state.layout.walls + dist = [] + self.layout = state.layout + + # Draw the rest + self.distributionImages = None # initialize lazily + self.drawStaticObjects(state) + self.drawAgentObjects(state) + + # Information + self.previousState = state + + def lookAhead(self, config, state): + if config.getDirection() == 'Stop': + return + else: + pass + # Draw relevant ghosts + allGhosts = state.getGhostStates() + visibleGhosts = state.getVisibleGhosts() + for i, ghost in enumerate(allGhosts): + if ghost in visibleGhosts: + self.drawGhost(ghost, i) + else: + self.currentGhostImages[i] = None + + def getGhostColor(self, ghost, ghostIndex): + return GHOST_COLORS[ghostIndex] + + def getPosition(self, ghostState): + if not self.showGhosts and not ghostState.isPacman and ghostState.getPosition()[1] > 1: + return (-1000, -1000) + else: + return PacmanGraphics.getPosition(self, ghostState) + +def add(x, y): + return (x[0] + y[0], x[1] + y[1]) + + +# Saving graphical output +# ----------------------- +# Note: to make an animated gif from this postscript output, try the command: +# convert -delay 7 -loop 1 -compress lzw -layers optimize frame* out.gif +# convert is part of imagemagick (freeware) + +SAVE_POSTSCRIPT = False +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) + name = os.path.join(POSTSCRIPT_OUTPUT_DIR, 'frame_%08d.ps' % FRAME_NUMBER) + FRAME_NUMBER += 1 + writePostscript(name) # writes the current canvas diff --git a/search/graphicsDisplay.pyc b/search/graphicsDisplay.pyc new file mode 100644 index 0000000000000000000000000000000000000000..403b55df0d43d71e80d93d4223e7b4f8c316c20f GIT binary patch literal 24599 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%0DD@%VACnHrxh}=#P@rToMneYZ6pI1h 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 NF5ROSWD)K5e*mGK?`Z%4 literal 0 HcmV?d00001 diff --git a/search/graphicsUtils.py b/search/graphicsUtils.py new file mode 100644 index 0000000..b80d3d2 --- /dev/null +++ b/search/graphicsUtils.py @@ -0,0 +1,402 @@ +# graphicsUtils.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 math +import random +import string +import time +import types +import Tkinter +import os.path + +_Windows = sys.platform == 'win32' # True if on Win95/98/NT + +_root_window = None # The root window for graphics output +_canvas = None # The canvas which holds graphics +_canvas_xs = None # Size of canvas object +_canvas_ys = None +_canvas_x = None # Current position on canvas +_canvas_y = None +_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 map(lambda x: int(x, 16) / 256.0, [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 + +def sleep(secs): + global _root_window + if _root_window == None: + time.sleep(secs) + else: + _root_window.update_idletasks() + _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 + + # Check for duplicate call + if _root_window is not None: + # Lose the window. + _root_window.destroy() + + # Save the canvas size parameters + _canvas_xs, _canvas_ys = width - 1, height - 1 + _canvas_x, _canvas_y = 0, _canvas_ys + _bg_color = color + + # Create the root window + _root_window = Tkinter.Tk() + _root_window.protocol('WM_DELETE_WINDOW', _destroy_window) + _root_window.title(title or 'Graphics Window') + _root_window.resizable(0, 0) + + # Create the canvas object + try: + _canvas = Tkinter.Canvas(_root_window, width=width, height=height) + _canvas.pack() + draw_background() + _canvas.update() + except: + _root_window = 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) + _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 + global _rightclick_loc + global _ctrl_leftclick_loc + if _leftclick_loc != None: + val = _leftclick_loc + _leftclick_loc = None + return val, 'left' + if _rightclick_loc != None: + val = _rightclick_loc + _rightclick_loc = None + return val, 'right' + if _ctrl_leftclick_loc != None: + val = _ctrl_leftclick_loc + _ctrl_leftclick_loc = None + 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) + +def _destroy_window(event=None): + sys.exit(0) +# global _root_window +# _root_window.destroy() +# _root_window = None + #print "DESTROY" + +def end_graphics(): + global _root_window, _canvas, _mouse_enabled + try: + try: + sleep(1) + if _root_window != None: + _root_window.destroy() + except SystemExit, e: + print 'Ending graphics raised an exception:', e + finally: + _root_window = None + _canvas = None + _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 behind > 0: + _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, endpoints=None, style='pieslice', width=2): + x, y = pos + x0, x1 = x - r - 1, x + r + y0, y1 = y - r - 1, y + r + if endpoints == None: + e = [0, 359] + else: + e = list(endpoints) + while e[0] > e[1]: e[1] = e[1] + 360 + + 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) + + +def refresh(): + _canvas.update_idletasks() + +def moveCircle(id, pos, r, endpoints=None): + global _canvas_x, _canvas_y + + x, y = pos +# x0, x1 = x - r, x + r + 1 +# y0, y1 = y - r, y + r + 1 + x0, x1 = x - r - 1, x + r + y0, y1 = y - r - 1, y + r + if endpoints == None: + e = [0, 359] + else: + e = list(endpoints) + while e[0] > e[1]: e[1] = e[1] + 360 + + if os.path.isfile('flag'): + edit(id, ('extent', e[1] - e[0])) + else: + 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] + return _canvas.create_line(x0, y0, x1, y1, fill=color, width=width) + +############################################################################## +### Keypress handling ######################################################## +############################################################################## + +# 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) + _keysdown[event.keysym] = 1 + _keyswaiting[event.keysym] = 1 +# print event.char, event.keycode + _got_release = None + +def _keyrelease(event): + global _got_release + #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) + event.char = 'a' + if event.keycode in [38, 99]: # UP ARROW + event.char = 'w' + if event.keycode in [39, 102]: # RIGHT ARROW + event.char = 'd' + 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=Tkinter.tkinter.dooneevent, + d_w=Tkinter.tkinter.DONT_WAIT): + d_o_e(d_w) + if _got_release: + d_o_e(d_w) + return _keysdown.keys() + +def keys_waiting(): + global _keyswaiting + keys = _keyswaiting.keys() + _keyswaiting = {} + return keys + +# Block for a list of keys... + +def wait_for_keys(): + keys = [] + while keys == []: + keys = keys_pressed() + sleep(0.05) + return keys + +def remove_from_screen(x, + d_o_e=Tkinter.tkinter.dooneevent, + 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=Tkinter.tkinter.dooneevent, + d_w=Tkinter.tkinter.DONT_WAIT): + if y is None: + try: x, y = x + except: raise 'incomprehensible coordinates' + + horiz = True + newCoords = [] + current_x, current_y = _canvas.coords(object)[0:2] # first point + for coord in _canvas.coords(object): + if horiz: + inc = x - current_x + else: + inc = y - current_y + horiz = not horiz + + newCoords.append(coord + inc) + + _canvas.coords(object, *newCoords) + d_o_e(d_w) + +def move_by(object, x, y=None, + d_o_e=Tkinter.tkinter.dooneevent, + d_w=Tkinter.tkinter.DONT_WAIT, lift=False): + if y is None: + try: x, y = x + except: raise Exception, 'incomprehensible coordinates' + + horiz = True + newCoords = [] + for coord in _canvas.coords(object): + if horiz: + inc = x + else: + inc = y + horiz = not horiz + + newCoords.append(coord + inc) + + _canvas.coords(object, *newCoords) + d_o_e(d_w) + if lift: + _canvas.tag_raise(object) + +def writePostscript(filename): + "Writes the current canvas to a postscript file." + psfile = file(filename, 'w') + psfile.write(_canvas.postscript(pageanchor='sw', + y='0.c', + x='0.c')) + psfile.close() + +ghost_shape = [ + (0, - 0.5), + (0.25, - 0.75), + (0.5, - 0.5), + (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.5), + (- 0.25, - 0.75) + ] + +if __name__ == '__main__': + begin_graphics() + clear_screen() + ghost_shape = [(x * 10 + 20, y * 10 + 20) for x, y in ghost_shape] + g = polygon(ghost_shape, formatColor(1, 1, 1)) + move_to(g, (50, 50)) + circle((150, 150), 20, formatColor(0.7, 0.3, 0.0), endpoints=[15, - 15]) + sleep(2) diff --git a/search/graphicsUtils.pyc b/search/graphicsUtils.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8cdd0a86e86758a4fa05d7a98dcd806e73b000fe GIT binary patch literal 13218 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 Dc}u;j literal 0 HcmV?d00001 diff --git a/search/keyboardAgents.py b/search/keyboardAgents.py new file mode 100644 index 0000000..c7d9fcf --- /dev/null +++ b/search/keyboardAgents.py @@ -0,0 +1,84 @@ +# keyboardAgents.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 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' + NORTH_KEY = 'w' + SOUTH_KEY = 's' + STOP_KEY = 'q' + + def __init__( self, index = 0 ): + + self.lastMove = Directions.STOP + self.index = index + self.keys = [] + + def getAction( self, state): + from graphicsUtils import keys_waiting + from graphicsUtils import keys_pressed + keys = keys_waiting() + keys_pressed() + if keys != []: + self.keys = keys + + legal = state.getLegalActions(self.index) + move = self.getMove(legal) + + if move == Directions.STOP: + # Try to move in the same direction as before + if self.lastMove in legal: + move = self.lastMove + + if (self.STOP_KEY in self.keys) and Directions.STOP in legal: move = Directions.STOP + + if move not in legal: + move = random.choice(legal) + + self.lastMove = move + return move + + 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 + return move + +class KeyboardAgent2(KeyboardAgent): + """ + A second agent controlled by the keyboard. + """ + # NOTE: Arrow keys also work. + 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 + return move diff --git a/search/keyboardAgents.pyc b/search/keyboardAgents.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9129cea5d061ecbff4c01cdab45f27aa1a456f28 GIT binary patch literal 2784 zcmcIl-EJF26h6D_tnJjLC?Eni;FiAyiKs%rML~$PiBw2&(K=C8E7HpGZk)9pJKdQO zA~_eReE_cd06YaZNFd$=i5K98D=rXx-&wEMLFz>mSZ7YoH*?OMGc(_r@&35FeCvmw z9`t1PdHDYsn%RYj@#n}$`Mg>{KN7 zC8=m{b>6!qu_x`Ih5+f`_yPx-U4mHeCu5t#Wx$OzOL{h)j7`g41>QJrygS(dOJFaxs& zvE0PBK5llIU9&eC+iWr#C2@1_v}q5L=5UtQni^WJrmHemd7{#&e3W8PdQ7=!cc7aa z5LRU1$W$b9WtuCV^hJBH0Kt}V>Q=y=3U$va(AwMgzp~uRQP!0tokM{=H@m-U2v))1RuUMaMyIDIr)o@Xij#C>& zufp5-oXu@Gbw}4$B|_7+{SF03F(Zy6XCw|Vhy!A|a^{IMbxD}1N4a`dk!gi1A9|AA zrOr+9WDE;O1_}pD@)%PsacJPnG>1@pu~iw=WavuvR7dL^9r`6a^X1V~oejRrYU8QF zFEihneF0(5&>Ce}mFzdMS7gvAgU&{gBx3nEC+>S|f!hsWoH{v=Mv) z5+&N&d}w)CS$7;y4pr?POwwKw&^u&G${%C9Hu-mC5^uz?N~J@@xfF|-85WYS;SB)O zgb?R>{WYA1yW(7P@q@fB4bW@Foe|7~-JD>50p!I4YLO4Q)H5~jl6&mTk9bopK_N#^ zynt}zA;K(YRPMV^(w4s8sxN4e`xdbDt(L~-dlJ0#{ZV~ug>L~%UofXg()`McY7VnM z)fYs~;}&q{>w<4Qn3f*Oy=33&0fuS+z*_Fn&XJC6OisoD2~=`JY4KpQy-ix=0DDp}?}d{N@!^z=ev+U)uBKlG8=|Uc(}D;#{Yu?0KD= 0: + curdir = os.path.abspath('.') + os.chdir('..') + layout = getLayout(name, back -1) + os.chdir(curdir) + return layout + +def tryToLoad(fullname): + if(not os.path.exists(fullname)): return None + f = open(fullname) + try: return Layout([line.strip() for line in f]) + finally: f.close() diff --git a/search/layout.pyc b/search/layout.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5276e80d331e8247983126da44be397990091836 GIT binary patch literal 6269 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