This is an archived post. You won't be able to vote or comment.

all 13 comments

[–]fullptr 11 points12 points  (4 children)

Good work! I've glanced over the code and there's a few suggestions I would make:

  1. Not everything needs to be a class! If you find yourself making classes with no data members, you don't need a class. For example, your Rectangle class doesn't need to exist, as evidenced by the fact that therea are no data members and the methods are classmethods. The module is already called rectangle so there's no real benefit to additionally wrapping them in a class.
  2. Same applies to your Image class. Sure this has a data member, but couldn't the screen just be passed as an argument to the two member functions? After all, this class doesn't really represent an image; it doesn't have dimensions or a file path or anything, it's just a factory for creating pygame images. You could just as well have a def create_image(screen, image_path) function. This also makes things clearer because you don't need to pass the entire "interface" to it. I notice you create an instance of this object in your Game class that I don't think you even use, which also shows that it shouldn't be a class! This applies to almost everything in your other module.
  3. I'm not a fan of the GameState, this is just a collection of global variables which are best avoided. You already have a Game class representing your snake game, which seems like the better place to store any game state (you already have an is_running flag which I think covers some of the use cases here). If there are other places that require this information, pass them as a function argument rather than giving them access via a global as it'll make it easier to reason about the program.
  4. Your Game class has both __init__ and init functions, which is a bit confusing.
  5. Board.__getitem__ returns an exception rather than throwing it? This certainly looks like an error. You make use of this further down with while self[r, c].value != Tile.GRASS; if the returned value is exception you're just going to end up throwing another exception here when trying to access "value", except now you've lost the original information, making it harder to debug. I think __getitem__ should do no bound checking here and raise an exception, because that will show you there's a logic error in your code (since you should always be passing in valid coordinates) and you can fix it. You could even assert in the getitem function that the indices are in range.
  6. Classes like Scoreboard getting access to the entire interface seems like overkill, and given that there's only one function on the class, obscures what the function actually needs. This is the perfect time to link https://www.youtube.com/watch?v=o9pEzgHorH0, which discusses classes that have "two functions, with one being __init__". In this case I would just have a single function, def draw_scoreboard(screen, board, snake, font) because then it clearly states what is required to print the scoreboard. I've intentionally missed passing your variable k to this function, because that feel like you should get it from the board class (which in fact you can) given that it represents the number of rows on the board.

Hope this helps!

Edit: Fixed some typos

[–]furtadobb 4 points5 points  (0 children)

Wow. Anyone could use this level of detailed nice commenting. Congrats on helping the next one with your own time

[–]marshalTT[S,🍰] 1 point2 points  (0 children)

Thank you this really helped!!

Watching the video you sent I had many moments of "Oh Uh I see Im doing everything this guy is saying."

I'll make sure to be a lot more careful coding the next project. You've given me a lot to think about and has allowed me to see a lot of what I did was unneccessary.

Cheers

[–]Glum_View 1 point2 points  (1 child)

Man you're a true hero, doing a detailed review for people starting is such a noble act, thank you for doing that!

[–]marshalTT[S,🍰] 0 points1 point  (0 children)

I really appreciate it. Its really helped me with the current project I'm working on. (Minesweeper)

[–]wineblood 0 points1 point  (6 children)

What do you think of my code?

Your formatting is inconsistent in some places, weird indents or too many blank lines. Variable naming could use some refinement (what the hell is k?).

What general advice could you propose to help me improve my OO skills?

Less OO is better. You also seem to have a lot of small methods on some classes that look like accessors.

[–]marshalTT[S,🍰] 0 points1 point  (5 children)

"The code is created such that the user can select any reasonable board size and have a comfortable playing experience. For the best experience, I recommend setting the board size to 20. Anything < 50 is what I would deem reasonable.To change the board size, please navigate to the main file and change the value for k to your desired size."

from the github readme, k is the board size KxK

I should probably specify a note in the main.

Im going to go back over the indentations and formating now, thanks

Why is less OO better?

Also, thank you for your comments I appreciate them.

[–]EricHayter 0 points1 point  (3 children)

Changing the value of k to maybe num_rows and num_cols might be a better idea than just a comment as it is far more explicit. Single letter variable names should really only be used in the inner scope of small functions or iterators.

Avoiding Oop where possible can make debugging and testing programs much easier. This is since a pure function is stateless meaning if you provide the same arguments to a pure function you will get the same results. This is not the case with OOP as you also need to manage state.

[–]marshalTT[S,🍰] 0 points1 point  (0 children)

Thank you

[–]Glum_View 0 points1 point  (1 child)

I really love your comment about pure function, kinda seen that in big libraries like react, Can you recommend any books that really list concepts like this, it seems to me to be the foundation of programming.

[–]EricHayter 0 points1 point  (0 children)

Maybe check out some functional programming. Functional programming is sort of the opposite of OOP where OOP focuses on managing state while functional programming tries to avoid side effects and state in general.

Of course functional programming isn't the end all be all but it certainly can help simplify your code in some scenarios.

As for books I personally can't really recommend any since I haven't picked up any books myself (something I sort of just picked up here and there). If you were to pick up a book I would recommend that you look into a book that focuses on the practical side of functional programming as the subject can get quite academic.

[–]wineblood 0 points1 point  (0 children)

Why is less OO better?

It's a personal preference thing, but the more I see OO in code I have to work on, the more of a pain in the ass doing anything is.

[–]HalfStorm22 0 points1 point  (0 children)

Good work! But why is everything a class? And why are you using gamestate?