Stefan Evans wrote:
I would think it would be simple with an
"advanceBases" method which advances all the base positions by one. And to advance for a double, you call this method twice. etc etc
Your calculation on runs suffers from the same thing. You analyse who is on the bases, and how hard the batter hit the ball to work out if anybody got home to score. And that may be 1, 2 or 3
As an alternative, why not run the scoring out of "advanceBases" so that any time somebody moves from 3rd base to home, you add a run.
Just my $.02.
Carey Brown wrote:Not sure why you need a copy constructor.
Carey Brown wrote:I'm still looking. Your enum Bases doesn't need the int as this is already provided by enum's as an ordinal.
Kendall Ponder wrote:
Carey Brown wrote:I'm still looking. Your enum Bases doesn't need the int as this is already provided by enum's as an ordinal.
Could you show me how I would change the code to use that? Thanks!
Carey Brown wrote:You've put a lot of stuff into Team that doesn't seem specific to a "Team" object. Some of the fields should be moved off to a Game class: bases, playersCanSteal, outs, runs, etc.. A Game would essentially keep track of the state of a game. A Game would have some method that takes an event, which might be the type of hit the batter made or it might include other things as well. The Game's state would change based on the event received. You might also want a Statistics class.
Carey Brown wrote:
Kendall Ponder wrote:
Carey Brown wrote:I'm still looking. Your enum Bases doesn't need the int as this is already provided by enum's as an ordinal.
Could you show me how I would change the code to use that? Thanks!
Junilu Lacar wrote:Smells:
1. The advanceRunnersForXXX methods smack of duplication.
2. Can't really find a coherent "story" to follow here. Good designs/code should read like prose: there is a beginning and end and a natural flow between those two points.
3. Responsibility assignments seem strange. Why does a Player have batterResult? And look at Team, most of the methods do not seem to be responsibilities of a "Team"
4. No tests
Try this: relate what you want the program to do as a story. For example:
I want to simulate a baseball game. I want to set up two teams. Play will be simulated randomly. Sample output:
Simulation:
Inning: 1
Team 1 at bat
Player 1 hits a SINGLE
Player(s) on FIRST
Player 2 hits a DOUBLE
Player(s) on SECOND, THIRD
Player 3 walks
Bases are loaded
Player 4 hits a SINGLE
Player 1 scores
Player 5 strikes out
and so on...
Ron McLeod wrote:
Carey Brown wrote:
Kendall Ponder wrote:
Carey Brown wrote:I'm still looking. Your enum Bases doesn't need the int as this is already provided by enum's as an ordinal.
Could you show me how I would change the code to use that? Thanks!
Another approach would be to use a Map to keep track of who is on each base;
Ron McLeod wrote:
Another approach would be to use a Map to keep track of who is on each base;
Junilu Lacar wrote:One common pitfall is trying to model the program too closely to the real world. While it helps when you can draw parallels between the abstract software object relationships and real-world relationships, sometimes it makes more sense to have objects that are simply abstractions. For example, you have the concept of an AtBatResult. It seems to me that it would make more sense to have a class named TurnAtBat be responsible for generating the AtBatResult. You could have code like this:
This seems like plausible code and it actually tells a small story. When I design, I try to write the code that I'd like to see first. Then I start writing tests to drive my design thinking down that road and see where it leads me and what kind of concepts present themselves. When the "story" starts becoming confused, that's when I start looking for smells and opportunities to refactor for clarity.
Note that the above may not be the code I end up with when I'm done but it's a starting point for exploring different ways of telling a story. I actually spend more time reading and re-reading my code than I do writing it. Also, I don't try to tell the whole story all at once. I start from a core idea, then work my way outward, adding more details, reading and re-reading to make sure what I have so far still hangs together cohesively and coherently.
Junilu Lacar wrote:Seems to me that a more natural data structure to represent the bases would be a queue (FIFO). If you see the bases, include home, as spots in a 4-item queue, it seems it's easier to just advance each item (a Player) along in that queue as a result of whatever play is simulated. If a Player gets to the end of the queue without getting tagged out, he scores. If a Player is tagged out at one of the bases, then he gets removed from the queue. You also need to track the players who are back in the batting lineup, which I suppose would have to be some kind of revolving queue. The player who is at the head of the queue goes up to bat and is either put into the bases queue or cycled back to the end of the batting lineup queue. When a Player scores and gets out of the bases queue, he will need to be reinserted in his proper spot in the batting lineup queue.
This might also help simplify the logic for simulating bases being stolen, double plays, triple plays, grand slams, etc.
Kendall Ponder wrote:4. I don't understand what you mean by no tests. Are you talking about debugging?
Kendall Ponder wrote:Where is the data being passed to the methods in this code? You have to pass the team information somewhere or am I missing something?
The atBatResult method has to operate on a player who has to come from a team.
Junilu Lacar wrote:
Kendall Ponder wrote:4. I don't understand what you mean by no tests. Are you talking about debugging?
Besides looking at programs as "stories", I also see them as "theories" of how the computer should do things. To validate these theories, I write tests. The tests will tell me if my theory is flawed or not. For example, one "theory" in this program might be stated as:
1. If the bases are loaded and the player at bat hits a single and the player on third doesn't get tagged out at home, then the team at bat should get another point.
By writing a test, I can start laying out the code that I'd like to write and start to see some of the relationships and collaborations that need to be in place for this story to get played out in the program and my theory of how it should work can be checked.
This approach is called Test-Driven Development and it seems like a "bass ackwards" approach when you first try it but I have found that it really helps clarify and organize my designs.
Take your story, for example:
Line 1 itself is very procedural code. Where does outsInTheInning reside? What class is responsible for tracking this? Where did the number 3 come from? What if the reader doesn't know how many outs there are in an inning? How can this be made more OO? What "theory" is involved here?
Well, the "theory" might be this: "A team will be at bat until it has 3 outs against it" -- Then I would think, "Ok, what classes are involved in telling this in the program and what would the code look like? How do I know that the code is working the way I expect it to work?" Well, I might try this test:
A number of questions will come to mind just by reading this code and it would lead to more design decisions. Refining and clarifying the "story" and "theories" using tests allows me to develop incrementally and iteratively and it helps me to get parts of the program working right away. By seeing working code, I learn more about the problem and how the design fits and whether it's something that can be extended and expanded.
Tell me, with all the code that you've written so far, how many times have you actually run your program? When I'm doing TDD and I have as much code as you have there, I would have executed the tests and the code dozens of times already.
Junilu Lacar wrote:
Kendall Ponder wrote:Where is the data being passed to the methods in this code? You have to pass the team information somewhere or am I missing something?
Certainly valid questions. This is precisely the point of writing code like this: to elicit these kinds of questions and drive your design thinking. It's about figuring out who's responsible for what and who needs to collaborate with whom. It's about seeing code that will compel you to make decisions that will enable you to answer these questions or write/modify code so that the questions change altogether.
The atBatResult method has to operate on a player who has to come from a team.
Why? The result is just a simulation that's randomly generated, right? Why does a "Player" need to be involved? This is the pitfall I mentioned earlier: you're trying to model the real-world too closely. The questions I would ask instead are:
1. Who needs to know about the play? The Player? The Game? The Inning? The TurnAtBat? Why?
2. How does knowledge of the play affect the state of the object(s) that is/are informed about it?
3. What exactly are these state changes?
4. How do I test that these state changes have occurred?
Junilu Lacar wrote:That test with a TurnAtBat and recording three outs would lead me to write some code that simulates a small scenario: You set up a game, first team goes to bat, and they get three strikes in a row. You can simulate a whole game with just this functionality. The game wouldn't be very much fun to watch because each team will not score at all and the game would come to nine innings with a score of 0-0. But then you learn a lot from this simple simulation. You can then extend it by introducing a result besides OUT, maybe a SINGLE run in the first inning. Then all outs to the end of the game.
You don't have to get everything right all at once. If you try to do that, you will likely fail. It's just way too much to process all at once. You have to step small things in one at a time, always keeping your code base clean and well factored every step of the way. When you extend your story, you re-read the parts that you changed and make sure everything around it still hangs together nice and tight. This is the best way I know to achieve clean code and designs.
Kendall Ponder wrote:
Junilu Lacar wrote:Seems to me that a more natural data structure to represent the bases would be a queue (FIFO). If you see the bases, include home, as spots in a 4-item queue, it seems it's easier to just advance each item (a Player) along in that queue as a result of whatever play is simulated. If a Player gets to the end of the queue without getting tagged out, he scores. If a Player is tagged out at one of the bases, then he gets removed from the queue. You also need to track the players who are back in the batting lineup, which I suppose would have to be some kind of revolving queue. The player who is at the head of the queue goes up to bat and is either put into the bases queue or cycled back to the end of the batting lineup queue. When a Player scores and gets out of the bases queue, he will need to be reinserted in his proper spot in the batting lineup queue.
This might also help simplify the logic for simulating bases being stolen, double plays, triple plays, grand slams, etc.
I didn't think of using a queue because I didn't even know Java had a queue structure when I first wrote this and I didn't think of changing it. I will look at the queue. Thanks! The disadvantage of my last professional coding being in 1986 is when I hear of a FIFO I think of doing it in assembly language which doesn't seem simple at all!
Kendall Ponder wrote:
I did all of this. Why do you think I didn't? Robert Martin in his Clean Code book says refactoring is a continual process and his first attempt is never well factored. Mine definetly was not well factored since I had never heard of the clean code idea. I am trying to clean it up now.
Junilu Lacar wrote:It's hard to discern emotions in a medium like this and I've tried my best to be as clinical and impersonal with the critiques I have given. Please don't take any of what I say personally because it is never my intent to do anything other than help. It's always about the code, never about the coder.
This is my favorite tiny ad:
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com
|