When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
36 messages ยท Page 1 of 1 (latest)
When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
just organise your game logic such that any state (that satisfies some invariant, if any) can be a starting state
save the money and positons of properties to a file like p1 500 pos1 pos2... then store each on a new line then you can use a shell command to get how many lines are in the file to know how many people are participating then you can simply read the data from eachline use atoi to convert it etc
A very naive but rather simple solution would be to just log everything that happens. If a player rolls a dice you log that, if a player buys a property you log that, if a player does any action you log that (logging could mean just appending to a file).
Then when you want to load a game you read the respective log file and replay all the actions that happened.
Voilร , you're at the old gamestate.
Why is it naive? Because it's rather slow and memory inefficient.
It has however the advantage of being able to always restore your game should it crash and that you can save some inputs for future testing this way.
What would be faster and more memory efficient? Think about what information do you even need to construct the game state.
You need to know how many players there are, what the dice roll order is, who's turn it is, where everyone is, how much money they have, which properties they own and which are flipped around, how much money is on free park, jail counters, etc., etc.
You can either save the data every turn or upon explicitly saving (e.g. via the click of a "Save" button).
Then when you want to load the game you can just read the file, construct the board and continue.
If you don't want to use a third party library then using xml, json or csv won't be easier than just using some custom .txt files btw
the crucial point in all those approaches (except the event-log based one described by Monke in the first paragraph) being: allow the game to restart from any state. the rest is indeed just about (de)serialising
the event-log is a very interesting approach, and one often considers it slower than what it could be. for instance, I've made a small app whose backend is entirely event-log based. it's the fourth year it's running into production, and it just works flawlessly. I suspect for a monopoly game, you wouldn't get a lot of issue. it's less efficient, but that doesn't mean it's inefficient ๐ it usually has a good ratio [maintainance/iteration]/[perf]
doesn't really matter how long efficient or slower the implementation is
what would be the easiest to implement?
it depends a bit on you I guess; I personally find event-log based systems easier to reason about and iterate on. basically the file would look like:
player order is Katya Marc John
dices gave 6
dices gave 11
dices gave 3
dealer of lucky cards distributes "go to jail"
dices gave 9
dices gave 2
dices gave 12
and so on. very easy to follow
(obviously you don't have to make it that verbose)
the event-log should ideally closely follow the code design. (likely you should organise the game to have a kind of "God" object that emits events of the kind "dices gave", "dealer of lucky cards distributes", ... and so on, to encode randomness (when you play live, it's backed by a random generator thing; when you're recovering state from a file, you just follow the instructions in the file)
and for each event, the game state updates itself (the correct player is moved on the board and so on)
the God can keep its state in-memory until SAVE is pressed, or log in the file as the game goes on (or a mix of both, with an auto-save once every N moves). a format like json/xml could be annoying to maintain, because they would always require you to deal with the closing markup. but that's up to you I guess
I've implemented a basic dicelog function but after the first round the player names somehow get corrupted
aside from this issue: you don't really have to log which players rolls what
the log includes the ordering (first line); basically your events only store what happens and cann't be recovered. asymptotically, you could even just store a seed and the number of times dices have been rolled: that would be sufficient to entirely recover a game state
do you have any guide for that?
absolutely not
but basically in this approach:
player order is Katya Marc John
dices gave 6
dices gave 11
dices gave 3
dealer of lucky cards distributes "go to jail or back from 5 steps"
user chooses "go to jail"
dices gave 9
dices gave 2
dices gave 12
you should see that you can capture the entire game history, since you know what happened every time something was hazardous and/or the user made a choice
but it is much harder to implement it if your game hasn't been thought off like this from the start. imo you should really have a kind of:
struct Choice decides_next_choice(struct GameState *state);
that returns the next "random" or "user" choice based on the game state
then a
void update(struct GameState *state, struct Choice *choice);
that updates a state after a choice is made
next you could have a
struct GameState init(void);
to get the initial blank game state, and two helpers
struct Choice read_next_choice(struct FileCursor *cursor);
void write_choice(struct FileCursor *cursor, struct Choice *choice);
something like that, in order to read and write choices from a file
once you have those utilities, I think arranging them would do the job
philosophically, you should change your mindset:
when a user throws a dice, it does not control a dice object to generate a number
rather, it turns into "waiting state" and waits for a "dice has rolled" event. I think that's the key. you should think your game as a machine that reacts to external events (dices have finished a roll, dealer has distributed a card to a player, player has made a choice, ...); rather than a scene where components control each others
once that is done, might the events be decided on the fly by a random generator (or a user answering through CLI), or might they come from a file, it doesn't matter much for the game
What Judekeyser means is that you need to separate your game logic from your input action logic.
This means that you never want to have a function for e.g. moving a figure that internally does anything else but moving a figure, i.e. inside that move function you can't ask for user input. Getting and parsing user input should be split from the game and only fed to the game whenever something happened.
If you have your code structured like that it also makes it much easier to implement such a log-based save.
And yeah, if you just play all the inputs from the file, even if the game has a few thousand actions, it should still happen basically instantly. Computers are fast.
I'd personally do it by having a struct that holds all of the game's state:
struct state {
int player_count;
// Add whatever stuff your program needs to keep track of here
};
int main() {
// Making it static initializes all values to 0,
// and means you can't get a stack overflow, no matter how huge your struct is
static struct state state;
init(&state);
while (true) {
update(&state);
}
return EXIT_SUCCESS;
}
and then writing a save() function that take a pointer to the state variable and the path to save the file to, and writes the struct to the file in JSON format.
The reason being that 1. JSON is one of the easiest formats to find libraries for no matter the language, or to write your own tokenizer and parser for, 2. it makes it easy to manually edit the state of the game by editing the file, 3. it doesn't get larger over time, unlike the logging approach, 4. it makes it easy to implement multiplayer, as the save format won't be machine dependent by being a binary blob
Then you just write a load() function that iterates over the loaded JSON object, and turns it back into your game's state struct. ๐
would I not need to change bunch of other functions to allow them to be set using load?
Wdym? Can you give an example?
yea and considered using one but there wasn't any default library for it
I'd put writing your own tokenizer and parser for something as one of the most educative things one can do as a programmer, after learning how to use a debugger
have you actually taken a look at the zip file that I sent?
I have now, it seems like you know your way around the language pretty well, if you wrote all of that yourself ๐
What you may have wanted to know was how the save() and load() functions would be used in practice:
void update(struct state *state) {
printf("update()\n");
if (user_pressed_save_key()) {
save(state, "save.json");
} else if (user_pressed_load_key()) {
state = load("save.json");
}
}
<@undefined>
Please don't delete forum posts. They can be helpful to refer to later and other members can learn from them. In the future you can use !solved to close a post and mark a post as solved.
@tall salmon Did you figure out how you want to approach it?