lundi 25 novembre 2019

Design patterns in c++ for a simple Battleship game (linux terminal only)

It almost kind of seems like C++ really wants to make things extra hard for design patterns because I really don't want to change my design, just to accommodate such strict static typing.

So, I have an assignment in my c++ class where we make the simple game of Battleship. The constraints are we can't use anything from the STL (so I had to make my own custom vector with templates which works very well, nearly identical to the c++ vector).

So here's the thing, originally I started very simply with a PlayerBase class that PlayerHuman and PlayerComputer were derived from. Being new to polymorphism, I thought it'd be cool to put pure virtual functions getReady() and getShot() in PlayerBase to force PlayerHuman and PlayerComputer to implement them. So far that seemed like a great idea.

Well, I ran into a little problem. (I'm really picky about trying to get a proper design down) I noticed how my design for getting player input was entirely dependent on the terminal. What if I wanted to easily switch out a terminal interface for a web interface? So, I should separate my user interface from my Player classes.

So now I had another choice. Should I have a separate HumanTerminalInterface object that is stored inside PlayerHuman (using aggregation) so I can easily swap that out with something else that matches that interface? OR... should I turn the class PlayerHuman into a public data structure that is passed to a function that changes it?

Ex:

PlayerHuman
   GenericInterface UI = HumanInterface
   PointData getShot()
      return UI.getFiringSolution()

Or:

PlayerHuman Sean;
PointData = callHumanUI(Sean&)

I opted for the second option along with instead of callHumanUI I got more fancy:

fake_vector<PlayerBase> players
callUI(PlayerHuman)
callUI(PlayerComputer)

So, I'm feeling pretty good about myself by separating the interface from the logic and storing entirely different objects in the same vector under 1 base type! WAIT A SEC!!! callUI only recognizes the derived classes...

I can't put my objects that are stored in the Base class array in there and expect them to work. Well, I could not put them in an array? WRONG! I need to swap the players every turn. So swap(player1, player2).

This is all because I can't get c++ to recognize these data structures have different types even though they are in a generic base class array. I know that means my design is wrong if I'm trying to do it this way.

The whole point of polymorphism is to make it so types don't matter. So,this was my solution, and it was ugly. Inside the PlayerData structure, I added a string "playerType" that is either "human" or "computer" then inside the callUI functions I have an if statement that calls other functions based on if the structure is Human or Computer. Yes, it works, but that DEFEATS the whole point of overriding functions like this. We do that so we don't have to use IF statements.

Is there a better way to do this? I know there isn't any code in here, this is purely design concept with the limits of c++. If you really want to look through my 1300 lines of code, go ahead. https://pastebin.com/f0MZ2rvJ

Aucun commentaire:

Enregistrer un commentaire