-
Notifications
You must be signed in to change notification settings - Fork 8
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
PGN Export #19
Comments
Hi, I'm not exactly sure how pgn worked, but I think it was like recording which piece moved where (kinda like a diff). This should be pretty to find out when comparing 2 states of a board or just taking the move action. I'm currently pretty busy as well so I might or might not have time to do this over the coming days. Here are some pointers:
You can probably hook the Otherwise you should be able to get a FEN of the board pretty much everywhere. You can use it to create a @rmadhwal Did the pgn viewer and can probably help better regarding the format or whether the lib can also be used to encode a game as a pgn. Edit: Fixed wrong file linked in pointers |
The game also logs the fen of each board change by default. So if you wish to make a first hacky attempt at generating a pgn based on individual FENs, you can extract them from the logs of your launcher (e.g. Maybe there are already same "Fen to Pgn converters" that could make this automatically. |
FEN only gives you state of the current board while PGN is a historic overview of how you got to that state. So a FEN is essentially a subset of a PGN and you've lost some information if you only have the former. For example, there could be multiple ways to get to the same FEN and all those PGNs would represent different games which might not be too helpful.
Currently we allow the pleco board to be created via a FEN, so this change might not be sufficient unless we also store PGN and recreate the board with both FEN and PGN, but in that case we might as well only use the PGN. Hence, I think we should extend pleco's board to be PGN based along with FEN based and only used the PGN based version for our code. That way when the game is over we can just generate the PGN from the board itself, it also seems more intuitive to me that the underlying board remembers the history of moves. This change will probably be non-trivial though. Storing a state of moves internally like @LinusCDE suggested would probably be easier and involve less tinkering. (We could change save state to include the PGN and load that into the internal representation in game.rs and continue with the FEN based representation in Pleco, it just seems sorta hacky to me) Also they currently have an open issue with help wanted for something similar pleco-rs/Pleco#71 but this probably doesn't include changing internal implementation. |
I figured out most of it; went with storing the state of moves. Quick question: why does At the moment, the issue I'm running into is that
Any thoughts would be greatly appreciated. Thanks! Edit: You can see my changes here: https://github.com/addcninblue/chessmarkable/tree/feature/implement-pgn |
I didn't write this code, so I'm not entirely sure why it is this way, but I don't think you should think of them as a server-client, they just seem to have a different set of responsibilities and in this case, since both of them contained a board (which theoretically should be able to tell us what state the game is at), the responsibility of saving the game seems to have been delegated to the Doing it the other way I suggested would have circumented this problem since the board would be aware of the current PGN.
Why would you need to send the entire PGN on every move ? Wouldn't just the current move's notation be enough ? |
On second thought you can diff the FEN between moves so you don't even need to send a PGN |
Originally, everything was in the game_scene: drawing, game logic, saving, ... I split this at some point to separate the responsibilities and make game_scene more readable. At that time, I also wanted to add multiplayer, this is why communication is done with messages. The fen is used as a means to serialize the board and send it to clients. The fact that the game_scene (basically a client and the ui) is receiving the fen twice I because it is playing both white and black (at least in PvP). In true multiplayer, messages would get (de)-serialized and white and black could be different clients. For the same reason I also implemented the savestate in game_scene and not the server, since I wanted to keep the lib portable to make integration in a server as easy and single-responsibility as possible (had actix-web with websockets in mind back then). @rmadhwal already elaborated on most. Thinks I can probably add:
I'm not sure what to specifically watch out for when sending moves (like how e.g. castling is communicated), but if that works well, we could probably use "full updates" (fen) and "partial updates" (pgn part/move) from the server. Maybe that would also make a pgn impl easier. |
I thought about this when the change was suggested, but I don't think this would be possible. Not because I looked into the code, but because a pleco board can be created purely with FEN (for example, when loading from a saved state). Given this, I doubt that it stores a history of moves (or even if it does, it's possible this is not an authoritative copy). Unless you're suggesting extending the pleco board to do so. |
You're correct about that problem. When starting a game from scratch the "server" will have the complete board with the history, but the "client" (game_scene) usually just re-creates the board on each change from the new fen (thus never having any history). If the game is continued from a fen, the server will also not have any history prior to game start. This is easy to notice when undo's don't work. Not sure if the history can be queries or is pub, but that may make it possible to check if the board is authoritative. We could solve that by simply also allowing a savestate as pgn and defaulting to that on newer version. But for that we must be able to import/export a pleco board from pgn reliably. For people loading a fen, we could then just detect the "non authoritative board" and forbid saving a pgn as it would be broken/incomplete. |
Got it, thanks all. I'm leaning towards replacing savestate with just PGN. I'm curious about the usecase for FENs, since it seems like that's only good for analyzing next moves (typically with puzzles, etc). |
I would be also for it. That way we also keep the history in addition to the state. We could probably just use a pgn where we save a fen now. When loading we can fall back to fen for older save states but in time people would automatically migrate to pgn savestates for new games. |
While implementing this, I realized that it seems that the UI is handling events twice during PVP: once for white and once for black. Can we just drop all events for e.g. black and handle them once with white? snipe edit: ah, it appears that some messages wouldn't work (eg. possiblemoves). nvm. |
I think I mentioned that above already a bit. That is because of the intention of a server-client-model. game_scene is probably more client, client, ui in this case. I'm generally for it, but am not sure if this would cause problems with the bot mode (the bot is more like a remote player for the UI) and have a kinda broken server. Maybe adding this to the protocol would make sense, like the server not sending some info or the client just ignoring most for one player? As you can see I'm not sure either. |
On implementation, I noticed that communication is done through sending Squares instead of BitMoves. I assume this is to allow for future portability? Conversion to bitmoves lets us reduce on a lot of logic (like iterating through all possible moves to figure out which was the intended move every time, etc). It also makes the PGN logic much simpler, as it would just be a list of bitmoves (which can be converted into pgn trivially). I tried converting everything to bitmoves to see where that got me, but I haven't finished yet. You can see below where I'm at below. I wanted to get some thoughts on this before I go further into this approach. It seems that, in retrospect, it would be possible to get the pgn converted from a list of historical board moves, but I think this approach seems marginally cleaner (at the expense of portability with other languages). |
I think it's a good idea and while I have some concerns about the implementations (most notably in getting rid of Though I think it's useful to note that in |
Tbh, I wrote it 2 years ago, so I'm not really an expert on it anymore as well. Since I never got to actually do multiplayer, the protocol layer is just unneccesary complexity for no reason tbh. I'm not sure if ditching the message queues could cause problems with waiting on bots without blocking (especially on hard, a bot can take about a minute), but there are certainly redundant types that could be removed as serialization would not need to be taken into account. @rmadhwal Regarding In general, removing the protocol layer would probably be a good thing to reduce overall complexity. I still believe that having some separation between UI and game logic would be benifitial, but this could be exercised more directly when the UI e.g. has a instance of I'm currently pretty deep into sorting out what exact topics to do for my bachelor, so I'll most likely not find the time doing a bih refactor. Btw @rmadhwal , would you mind if I promote you to being collaborator on this project? I haven't really done any meaningful things over the last years, and chess was not ever really a hobby of mine tbh. You seem to be for deeper into chess than me and me having to okay things would only slow things down imo. |
From what I understand I don't think it's a bad idea to replace it, I think more consideration might be required to see how to do that exactly. I think having a communication layer is a good idea, because eventually it should indeed support multiple devices, having said that I don't think @addcninblue's change would affect portability since all existing information is preserved. I also am not 100% about making
Sure, that would be fine with me! |
Edit: Btw, this message was out of order again. Didn't the the above response then writing this. Sorry I didn't noticed your reply before @addcninblue (my phone only showed me the last one but I noticed this when going through my K-9 Mail client).
One reason was probably the easy to serialize it. But I think I never really understood/looked into the BitMove, so I probably just wanted to let pleco deal with things like castling in case I would overlook any similar special cases.
Seems reasonable. The code seems nice imo. I didn't get to test it yet, but as long as the game works in the end, I'm for it as well. When disregarding serializability, it would hopefully also make things easier as custom types are not a requirement anymore then. |
Yeah, I believe my approach was to always send the absolute state. This makes remote communication and picking up a paused game a lot easier. I also didn't know about PGN back then. Having the proto only has the advantage of having easy integration possibilities with multiplayer. Technically that should already work if the senders were to just serialize to/from json with I'm personally up to anything. I started the refactor with the
Done. Welcome to the project as a collaborator! 👏 I'm still confused how people put up with this messy code base. I'm truly humbled. |
Thanks! Also the code base is pretty decent :)
I would prefer to not add too much extra complexity (especially as we don't have sturdy tests). @addcninblue unless you have a better suggestion to resolve the ordering conflict mentioned above, would it be okay if we kept both the FEN (along with the |
Regarding the tests, I'm on that rn. For now I guess just basic If I find the time, having automated ipkg packaging as in oxide would be nice as well. Will see if I get to that today as well. A simple binary should be enough for now. |
Should be done. Apologies for commit spam on the master. Wanted to get this done fast and not drag along for a while. Also a bit rusty on GH Actions and had to test a bit. While updating, I also updated some dependencies. I hope the changes are minimal, but there might be some small merge conflicts due to that. |
@rmadhwal I'm not entirely sure there would be an ordering conflict? If the protos are delivered via something like TCP, this would never occur, right? Nevertheless, the states can get desynced if they disconnect. The idea I had in mind to resolve any conflicts is for the client to
I think under this scheme, sending the FEN each time won't be necessary. |
Asynchronous message passing in general makes no guarantees about the order of message delivery, they (sometimes) guarantee that messages will be delivered not necessarily in what order. To guarantee order you'd have to use either a synchronous system or some sort of synchronizer like an acknowledgement based method. TCP only preserves orders of packets in a single connection, there are no guarantees across multiple connections (which may happen with parallelised connections). Though I agree that it's highly unlikely for this to occur in practice with most modern TCP libraries, I still think it would be better to stick with caution and not having hidden dependencies between updates intuitively seems like good practice to me.
That's reasonable. Though how would you check for consistency in the |
As far as the bot concerned, that only cares that it has the current board state and knows which player it is moving. I think so far we only need to worry about "Continuation". Meaning either a potential client (re)connect or starting from a past partial game. When we then just bulk send the partial pgn/total moves a client should be up to date. I think we can assume that any protocol during the game would have all messages arriving guaranteed and in order. Otherwise the channel/connection would fail and the reconnect would do the rest. Async in rusts context only means "async execution". The channels are not handling messages in async order or akin to udp because of that. |
Hmm I see okay, since the communication logic hadn’t been implemented I was just assuming a normal distributed network with async communication. If the order is guaranteed then that’s cool and I have no reservations against this approach. |
Hi!
Thanks for the wonderful chess program.
I was wondering how much work it would be to be able to export games to PGN after they're done (or perhaps continuously during the game)? Perhaps this can be implemented in savestates.yml, with a new line like
slot_1_pgn
or something. If it's not too much work but is nontrivial, I'll have time over the summer to see if I can try implementing it. Pointers would be appreciated!Thanks again!
The text was updated successfully, but these errors were encountered: