-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Design and Flexibility #2
Comments
I like what you've started. The board, in my opinion, should be responsible for movement of pieces. The rationale behind that being it is more intuitive for the board, a central object, to keep track of where all of the pieces are placed. If the pieces were allowed to move themselves, it would create complications for things such as detecting whether or not another piece is already in the same coordinate and such. //naming can be changed in the future.
enum piece_type {
TYPE_PAWN = 0,
TYPE_KNIGHT,
TYPE_BISHOP,
TYPE_ROOK,
TYPE_QUEEN,
TYPE_KING
}
class Piece {
virtual bool move(short location) = 0; //Returns true on success, fail on failure..
virtual bool attack(short location) = 0;
std::string name;
Location location;
piece_type type;
sf::Sprite sprite; //I'll elaborate on this
}; I added an sf::Sprite instance to the parent class Piece because, as far as I can see, it will be necessary to have in all base classes as well. Firstly, I'll get out of the way some more global definitions for image locations. //in some header yet to be named
const std::string img_pawn_black("res/img/pawn_black.png");
const std::string img_pawn_white("res/img/pawn_white.png");
//... and so on. The resource manager (as a whole) will
I've split this into two different concepts. The first being an abstract base class, ResourceManager, which handles the storage/retrieval of a resource, and provides a virtual method for the loading of resources.
The following is a short example to help push the point. template<class T, class deleter_type = std::default_delete<T>>
class ResourceManager
{
protected:
virtual T *onLoadResource(const std::string &location) {} //pure virtual method; base class is responsible for implementing.
public:
std::shared_ptr<T> Load(const std::string &key) {
//pseudo code
if exists in memory
return shared_ptr to the resource
else
call OnLoadResource to load it
store the loaded resource in memory
return the resource
}
void Free(const std::string &key) {
//pseudo code
free the resource from ResourceManager memory (namely, delete the shared_ptr)
//resource will not actually deallocate unless the reference count is 0, which it should be before calling Free.
}
};
class TextureManager : public ResourceManager<sf::Texture>
{
public:
static TextureManager &getInstance() { //singleton class
static TextureManager instance;
return instance;
}
protected:
sf::Texture *onLoadResource(const std::string &location) {
sf::Texture *ret = new sf::Texture();
ret->loadFromFile(location);
return ret;
}
};
//usage:
TextureManager::getInstance().Load(img_pawn_black); //img_pawn_black defined earlier. So then every instance of a piece can call Load, and multiple allocations of the image will not occur. I'm working on the full code, which I'll push to the master either tonight or tomorrow afternoon. |
That's one thing I don't want though is hard coded pieces! There are thousands of variations of chess, some containing pieces that aren't what you're used to: http://en.wikipedia.org/wiki/Chess_variant Since this isn't a very heavy application of algorithms, I thought using "name" to identify piece types would suffice. |
It would be beneficial to keep the design of boards, pieces, moves and game logic free of things like sf::Texture and sf::Sprite. There's no reason those things should be coupled to the graphics library. |
computerquip, it would be impossible to code one game that fits every variant of chess. Which is why they're called variants. We could have XML setting files containing names of piece files, so they could be changed externally? cire, That makes way too much sense. Thanks, definitely keeping that in mind. |
I'm not so sure. It's like having different gametypes in one game. For instance, having Deathmatch, Capture the Flag, and Domination in Modern Warfare 2. Or having different gametypes of tetris. Just like any other console game really... I'm not saying make one that fits every variant but just enough to be able to implement most with minimal problems. |
Then, as mentioned earlier, we could have external configuration files that we can change in the future. Either way we need to have the paths to all of the pieces coded somewhere in the game, whether we use those pieces or not. |
I think this should be kept as the classic chess that everyone is used to. And yes we should also definitely keep the graphics components outside of the internal classes (piece, board, space, etc). That should be handled separately. What about having the Piece class have its own internal representation of the grid, with valid places that given piece can move to? |
Agree on that. Disagree on the second point. There are <= 32 pieces on the board at a given time. So up to 32 pieces have to have a representation of the grid, and every time the grid is altered up to 32 representations of it have to be altered as well. |
But each piece moves differently. Should the board be responsible for handling each piece's movement behavior, or should the piece be responsible for that? It makes more sense for the piece to, but like you said that leads to lots of recalculations. Granted, it would only need to recalculate when a piece moves. As far as the piece is concerned it just knows where it can move. The board can keep track of if that place is free or not (be it line of sight issue, or preoccupied by allied piece). |
Sorry, each piece would only have to recalculate when it moves. The other pieces don't care. I'm just saying each piece keeps basically the movement behavior of itself. The board can handle whether or not that movement leads to an attack, is impossible due to line of sight, or the space is occupied. |
Maybe a piece can hold a |
Okay, yeah I take back what I said about the board handling movement patterns. Unique pieces should know where it's allowed to move. Up two positions, over three up 2, diagonally, etc. The board should have member function 'isOpen" which the piece can use to see whether or not a specific movement spot is open. Yeah? |
Are we against having an abstract base class Piece, with derived classes for each type of piece? We could then store a I realize this won't be as flexible as adding a new type of piece will require recompilation, but it's a thought. |
I have an example I'll post up here in a few moments... I just need to finish basic game logic. |
That was the original idea (i think). Piece would be the base class, derived classes for pawn, rook, bishop, knight, etc would be specific to that piece type. I'll wait on your example, computerquip. In the mean time, I'm going to start a new issue on the topic of resource management. |
So, this turned out a lot more fucked up than I really (ever) wanted. It's pretty nasty.. but try and look at it from an overall picture than the implementation details... I've clearly been sitting too long in C and some other similar languages... I apologize if I messed up some syntax seriously somewhere: However, note that this isn't a working example. I don't have time for that right now, this is just a sample of the direction I was thinking of. Criticize the crap out of it but like I said, try and ignore the implementation details, more towards the use of the interface. Good night! |
Eh, I just noticed the namespace name "default" doesn't work because of keyword collision. Just ignore that. >.> |
I like how you separated the pawn piece into a separate namespace for white. I didn't think of it before, but black pawns will have a different movement method than white pawns because of the way the board is oriented. (white will move up, black will move down). |
And that's what the close button does.. lol |
Ooh good point. I knew the white and black should be distinguished, but I hadn't thought of the fact that their movements would be reversed. At least for pawns. The rest can move forward and backwards. |
BTW, I have an account on LucidChart. I can give some people access to a project. It's nice for collaboration and planning/design if you haven't used it before. |
Or, again with the enumeration enum piece_color {
black = 0,
white = 1;
}
class Piece
{
bool move(int x, int y) {
if(color = black) //do one thing
else if(color == white) //do the other
else //blow the computer up because what the hell.
piece_color color;
}; EDIT: I haven't heard of LucidChart before. What's it used for? |
http://www.lucidchart.com/invitations/accept/5125b5a1-9494-4c78-8338-21570a004d18 This will give you owner rights to the project page (I think). There's nothing there yet. EDIT: LucidChart is a pretty handy online diagramming tool. It has a bunch of stuff you can do with it (think Visio online, but easier) but I've only ever used it to diagram projects and throw together mock UIs. |
Thumper, that's kind of what I was thinking. I just threw a bool in my Piece class. An enum is a little cleaner though. |
I like enumerations, they do look clean. |
From reading through it, it looks good to me. I like the simplicity of it. Doesn't have anything it doesn't need. |
The only thing that would need to actually differ between white and black are the pawns. Outside of that, they would be the same on both sides. While it may be slightly redundant, its the only type of piece that will require the redundancy plus the logic of it isn't complex at all. So far, here's my todo list:
|
Wouldn't it be important to differentiate between white and black for every piece? Especially if you intend on calculating score. There has to be a way to tell one teams knight apart from the others. Otherwise, by that logic, you would be able to move the enemies pieces while it's your turn :P Speaking of networking, have you got any ideas how that should be structured? Like what exactly is going to be accomplished. Will there be a server application? Or will the one application be able to act as both a client and a server depending on whether it's starting the game or not? |
I was also thinking a server could maybe store a game state and if a client gets temporarily disconnected it could resume the game. But I do agree a central server model would be pretty complicated to really consider now but could be something to implement later. |
I'll draft up some higher level networking stuff over the next few days. Handling disconnections is very feasible. |
Looks as if LucidChart did not save some changes to the diagrams. I'll work on that tomorrow at some point. Luckily I saved a JPEG copy. And looks like Thumper got his saved here. |
Yeah, apparently LucidChart didn't save, despite my telling it to. Luckily, I downloaded a .pdf before I exited. |
I spent some time working on the logic of the game via console. I have used inheritance for the pieces. The direction of the pawn is calculated upon construction (if it's black it goes down). I would like to see the ability to have black on the bottom, especially if I was playing as black, but perhaps that would be in the future. Making black on bottom could possibly just be a difference in how the positions are interpreted. Valid moves is seeming a little tricky. Right now I'm making a "list" of valid moves, so if the move one picks is in the list, the move must be valid. I do think better than calculating on the fly. The tricky part seems like it is going to be checking whether the move would put the king in check. I'm thinking maybe a piece have a trajectory, the valid moves being a sub set. Maybe something like "that piece can't move because the king is in the white piece's trajectory, and it happens to be blocking it". Maybe I'm making it more complicated than it has to be. The other way I can think of would be "faking" the move, then checking every piece of the other color to see if it could hit the king. Should a piece know why it can't move? Should a piece know the pieces it's pinning? |
LowestOne, Have you posted your code anywhere? I've actually been working on the same, I'm curious what route you've taken with this. |
I haven't. I don't know how pleased I am right now with it. I had trouble saturday night getting sf::renderwindow to work. I know I've got it working on other projects, but I wont have time to try again until Wed. |
My fork now has the start of the game logic. You could actually play a game of chess. There is no check, checkmate, en-passe, or castling. You can take pieces though :) I've done some things to the SFML files, but I'm pretty sure they aren't the latest. I've obvisously changed the events and render functions. I've also changed the way the looping works. The game sleeps unless it gets a message, and sleeps between handling messages. I don't think noticeable as far as gameplay, but certainly for trying to do other things with your computer. |
Wow, you've done some work. |
Thanks. Just found this site, pretty neat stuff. |
Currently it seems that @Lowest0ne is performing massive refactoring. Comparing to his fork, you wouldn't even know they were the same codebase. @Lowest0ne: What was wrong with the current code base and why are you drastically changing it? Looking at some of your code it seems to be far more complex than the original working code and much less modular. Could you explain your design to us? EDIT: Also, it doesn't properly conform to the styleguide (but we weren't finished changing the existing code to conform either). |
The logic of the game is now completely different, yes. The way it interacts with the rest of the program is not that different, so I'll talk about that first. The logic of graphics has been taken out and placed in the appstategame.hpp. I feel the purpose of graphics is to draw things, not to know about the things that it is drawing. That's the most of it. Something I did that I am open to changing (or at least, feel I need to say I'm open about) is the fact that AppStateGame knows what piece is selected and is "current". I did this because I felt that these are things that are results of the user clicking the mouse and didn't belong in a logic based class. Maybe a bad feeling. About the major change in the logic. There is no more inheritance. I feel it makes it more complicated than it has to be, particularly when it comes to checking for moves that make check and blocking moves that might cause check. A piece is really a uint32_t with various masks for it's members, easily changeable if wanted. A piece's valid moves is no longer a list (so called), but a std:bitset<64>. The list implementation was noticeably slow when it came to dealing with check. We had something like this: -for_each( piece of other color ) And that doesn't even work with pawns. Now we have this, which still doesn't work with pawns: -for_each( piece of other color ) So that's the basics of what I changed |
Just a note before I respond to anything: I want to get styleguide conformance before I start refactoring the code.
There should be a Player class, which AIPlayer, NetworkPlayer, and HumanPlayer all extend - a player would maintain this and control pieces.
How so? I think that inheritance is a great path for modularity - we could easily add new and different pieces if we wanted (or if someone forking the project wanted) though for now I think we should get Vanilla Chess working before we go for modded chess.
The repo is called "ChessPlusPlus", not "cchess" - the goal of the project is to show the power and elegance of C++, not to show how to obfuscate code and use C ;)
That's no reason to obfuscate code and revert to C techniques. We could easily optimize the code in a way that is still very clear as to what the code is actually doing - the moment you touch bits you create obfuscated code that is non-modular and confusing to think about. Rule: design first, optimize later. At least, that's how everyone else seems to do it successfully :) My IdeasIn terms of logic, I think most logic should be done server-side, which means that when playing online and not via a local 'fake' server, you're limited by connection speed anyway. A couple heiarchies are needed:
The For full modularity, the Eventually, though not right now, a server should be able to send custom dependencies, meaning sounds, graphics, and a different Summary: the client is just a window into what the server wants you to see. |
@Thumperrr: We can discuss things here (it would be better as a concrete record compared to irc anyway). See my post above for my intentions and ideas. |
For design choices I agree, but I mean for some smaller things like, browsing over code and thinking "I have no idea what the hell that bit of syntax does.." I'd like to have an IM or something we can do quick back-and-forth's with. Would you have any objections to modifying operator[] on JsonParser to be able to do something like this Also, I know I was first against it, but I'm starting to like json-parser over boost::property_tree::json_parser. The thing you did with the board layout inside config.json blew my mind. I don't think boost::property_tree could handle that. Can you include other files within .json files? I think it would be beneficial to have config.json 'include' another json file that contains the board layout. |
I would object because it is possible that names could contain dots. For example: {
"files":
[
"a.txt",
"b.txt"
],
"file info":
{
"b.txt": <--valid
{
"blah": "meh"
}
}
}
That's because it is not legal in XML, however it is legal in JSON.
I think YAML supports that (YAML supports a lot of things and a valid JSON is a valid YAML), but as for JSON we would have to have a string with a filename. I think we could allow both inline board definition and external-file board definition with a simple type check - I'll work on it. |
Actually, thinking about it, we should actually have different config files for the board setup and its graphics - having the different config classes load the same config file doesn't make much sense to me.
You can go to the commit that added that line of code and ask about it on that line - that way everyone can see. |
Good point. I hadn't thought of that. I withdraw my suggestion.
I was about to touch on that. That seems like the most intuitive thing to do. {
"files":
[
"a.txt",
"b.txt"
],
} In the above snippet, when you go |
|
What would be the value of that string? There are two values in "files". Would it evaluate to |
Oh, sorry - I misread. The value of auto &arr = reader()["files"];
std::vector<std::string> files;
for(std::size_t i = 0; i < arr.length(); ++i)
{
files.push_back(arr[i]);
} There's actually some gaps in the JsonReader interface, one of which is |
Added missing capabilities in LB--@dfd7c17 and also abstracted the code where I had to use |
I'm still chugging away refactoring the code in my fork. The main thing I'm having a hard time on is Interactions, I've basically gotten nearly everything but that refactored. Then I'll just need to make the game playable and turn-based. After that's done I can send a PR and start working on separating client and server logic (which will lead into multiplayer). But before I can send the PR I need to wait for the CMake stuff to get finished and pulled in. So, this is just a status update for everyone. I'm still working on this :) |
So, I've been thinking of something to come up with in design. To begin, let's get some terminology out of the way:
Board:
A grid consisting of valid locations for a piece to move.
Piece:
An entity that contains logic on how to move and other entities like itself.
Game:
Generally consisting of a board and a set amount of pieces (although not always the case), it handles global logic such as when the game ends, when a piece changes (such as when a pawn reaches the end of the board in a default game), and so on.
Please note that these definitions may need to be extended later since it's difficult coming up with defined terminology to fit the humongous amount of chess variations.
Moving on, there are some things that we know for sure:
So using, this... we get pretty much nothing. 🎱
So, my idea so far consists of implementing the logic of the game using generic virtual types.
In example:
Obvious flaws are whether the piece should move or the board should move the piece or the game should move the piece. I like the idea of virtual interfaces but I'm not so sure about the interface I'm introducing... this is where I fall short most of the time anyways. Any ideas would be lovely.
Also, I'm starting to think there's no reason to seperate "Game" and "Board" since game needs to know the dimensions of the board anyways.
The text was updated successfully, but these errors were encountered: