In my original post, I expressed some concerns about the design of StrategyMinimax that my partner and I implemented for the project. In the post, I said that we had used "a recursive helper function, get_score, to find the score for every possible move at the current game state, and then use the Strategy class method suggest_move to (randomly) pick one of the moves that had the highest score" (if this isn't very clear, you could revisit Post #6 for a more thorough explanation). When I wrote that post, I wasn't sure if we had made the right decision about minimax, as our profs had described the recursive part of minimax as being able to store both the move and the score of the move, as a tuple. Even though we had tested it quite a bit, I didn't know if our implementation was correct or not.
Although we still haven't received the mark for Assignment 2 (because of the TA strike), last week I went to talk about it with Diane. She showed me the model code for the the minimax function, and it was as I had expected: the recursive helper function kept track of both the score and the move. Diane suggested that I test out our minimax function with the unittest that Danny created for the assignment. The unittest basically had a bunch of different scena//*rios that tested minimax's ability to return a correct move. Because there were so many cases, it was highly unlikely that an incorrect strategy (for example, the random move strategy) would pass. Our minimax function passed all parts of the test except for one section that involved setting up a game board. The reason our code failed here was because we had designed a different method of setting up a TippyGameState, and once I changed the unittest to be compatible with our setup, our minimax code passed all cases.
After this, I was quite confident that our minimax function was working properly. However, for Assignment 3 we decided to change our code to be more like the model version of minimax, since there was a major advantage to the way it was structured: it would be easier to implement certain features, like memoization, in a minimax strategy that kept track of both the move and the move's score within the recursive part of the code.
When I wrote Post #6, I thought that our minimax strategy implementation was inferior to the model version. However, I now believe that this is not the case: our minimax strategy was just as effective the model strategy. Furthermore, I believe that our strategy is easier to test. During development, we modified our code for the suggest_move method so that it returned a list of scores for each of the possible moves (as opposed to just returning the best move). The reason that we could do this was because, in our design, suggest_move creates two lists, a list of possible moves and a list of corresponding scores for those moves (obtained by get_score, the recursive helper function) (see more complete description in Post #6). This solves the major problem that the model minimax code has in testing: there is a chance that it will choose the correct move purely out of luck. Our program was better in a sense because it could show you a list of all the scores, making it easier to verify correctness.
This experience with Assignment 2 has allowed me to come to an important realization. At the beginning of the course, I always assumed that there was one "correct" way of doing things. In CSC108, we weren't given too much wiggle room on projects, and I think this may have given me the impression that every problem has one solution that is "better" than all of the others. When I look back at the minimax design in Assignment 2, and at the GameState class design in Assignment 1, I recognize there were many possible ways of approaching each problem, each with its own advantages and disadvantages. For every program, there isn't necessarily a design the is objectively better in all cases. One must weigh the costs and benefits of each design to determine which is the best for the specific situation. I'm confident that this knowledge will be useful to me in the future, as it will encourage me to pursue strange and creative solutions to the problems that I face.
When I wrote Post #6, I thought that our minimax strategy implementation was inferior to the model version. However, I now believe that this is not the case: our minimax strategy was just as effective the model strategy. Furthermore, I believe that our strategy is easier to test. During development, we modified our code for the suggest_move method so that it returned a list of scores for each of the possible moves (as opposed to just returning the best move). The reason that we could do this was because, in our design, suggest_move creates two lists, a list of possible moves and a list of corresponding scores for those moves (obtained by get_score, the recursive helper function) (see more complete description in Post #6). This solves the major problem that the model minimax code has in testing: there is a chance that it will choose the correct move purely out of luck. Our program was better in a sense because it could show you a list of all the scores, making it easier to verify correctness.
This experience with Assignment 2 has allowed me to come to an important realization. At the beginning of the course, I always assumed that there was one "correct" way of doing things. In CSC108, we weren't given too much wiggle room on projects, and I think this may have given me the impression that every problem has one solution that is "better" than all of the others. When I look back at the minimax design in Assignment 2, and at the GameState class design in Assignment 1, I recognize there were many possible ways of approaching each problem, each with its own advantages and disadvantages. For every program, there isn't necessarily a design the is objectively better in all cases. One must weigh the costs and benefits of each design to determine which is the best for the specific situation. I'm confident that this knowledge will be useful to me in the future, as it will encourage me to pursue strange and creative solutions to the problems that I face.



