I have a fairly simple board game i've been building in C++. Currently, players are assigned a player number (1, 2, 3...N) depending on the number of players in the game. Pretty standard. The players and their stats are kept in a file which include their name and their number. I then process turns via reading a directory with turn files. The turns are submitted by the players and contain only their player name and their task/turn. In the future, I plan to have player numbers change so to mix up the order of the game.
(if you're a board gamer, think Caylus or Agricola)
Players are read in at the start of the application. I then give a command and turns are processed. Basically, I simply read the directory of turns, 1 by 1, and match that turn to a player name. As it stands, there is no order in turn processing. Player 3 can go before player 2.
I figured this wasn't a great design so I came up with the following solution:
As I'm comparing which turn goes with which player, insert that turn into a std::map<int, Turn>, the key being the player number.
After I gather all the turns, search for player N, starting with 1, within the map and process his turn.
I'm iterating through the list of players again here because I need to match the player with the player number in order to process the turn.
Do this until I've processed all players.
Is there a better way to do this? This seems kludgey and a lot of overhead.
Thanks!
Note: My turn processing method takes in a Player class (which represents the player stats file) and a struct representing the turn read from the turn file.
So as I understand it, your problem is you have thee bits of linked data: Turns, PlayerIDs and PlayerTurnPositions (OK the latter 2 are ints but I'll assume you've typedef-ed them to something like that to avoid confusion). And you want to maintain a lookup from the PlayerID and PlayerTurnPosition values to the corresponding Turn, and also maintain a bidirectional relation between the Player info.
This is just screaming out to use a boost::bimap with some extra info attached to each pair relation; something like
boost::bimaps::bimap<
boost::bimaps::vector_of<PlayerID>,
boost::bimaps::vector_of<PlayerTurnPosition>,
boost::bimaps::with_info<boost::shared_ptr<Turn> >
>
should do the job nicely (although there are other options for the left/right view container types; set_of probably makes more sense given playerIDs and positions are presumably unique).
Example of this sort of with_info usage in the docs.
You might think of defining an Action class for a player acting in his turn, which is defined by a player number and a turn number, and define a comparison on this class. Read all Actions from the files, insert them into an ordered list, and then process these actions.
Related
i am trying to implement a minimax algorithm from scratch in java.
General point is known to all, through a tree i try to find the best possible move.
I dont have something crucial from code to show now, first i would like someone to give me a general approach so i can start the project and then update the post with my code.
In addition to that i am also going to implement a random heuristic for my game, that will in random choose the next move and pass it to the game, but this will be added later on.
I will be adding bounty on this question.
P.S.
This is not a duplicate, i dont want to copy someone else's code, i have to do the whole code on my own.
So the main thinking to follow is the following:
Calculate the best move with the given game field and the rating mechanism
field the input field where to calculate from ratingMechanisms the mechanism to rate the move and return the best move.
In a more in depth analysis:
The key to the Minimax algorithm is a back and forth between the two players, where the player whose "turn it is" desires to pick the move with the maximum score. In turn, the scores for each of the available moves are determined by the opposing player deciding which of its available moves has the minimum score. And the scores for the opposing players moves are again determined by the turn-taking player trying to maximize its score and so on all the way down the move tree to an end state.
A description for the algorithm, assuming X is the "turn taking player," would look something like:
-If the game is over, return the score from X's perspective.
-Otherwise get a list of new game states for every possible move
-Create a scores list
-For each of these states add the minimax result of that state to the scores list
-If it's X's turn, return the maximum score from the scores list
-If it's O's turn, return the minimum score from the scores list
-You'll notice that this algorithm is recursive, it flips back and forth between the players until a final score is found.
In the main part you should use a for in order to minimize or maximize each level (also you can try adding some debugging like this: //System.out.println("max/min level " + i);), then while getting the current level of the tree check if it is null so you get no exceptions, and for the that level add it in the max node, while parsing in the min node.
In order to use the max and min nodes you have create the functions for these.
The maximize part of the algorithms: The node will get the biggest rating of his children. WARNING: if no child exists, the rating will be the min.
For the minimize part of the algorithms. The node will get the lowest rating of his children. WARNING: if no child exists, the rating will be max.
First some background...
I'm currently working on a "practice project" to keep up and refine my programming skills. The project is a card game system (similar to MTG and other trading card games). I currently have the following concepts implemented:
There are Players that can be created/saved/loaded, which contain profile information, win/loss statistics, and a list of Decks. Each Deck contains a list of Cards (they are actually instantiations of the four different Card types, not the abstract Cards themselves), which have all the attributes needed for game-play.
The issue...
Saving Players, Decks, and Cards is unnecessarily redundant. If there are multiple Decks with the same Cards or multiple Players with similar Decks, then the program will be saving the same Cards over and over again. For Example: If Card A is very popular, then Players will put multiple copies into multiple Decks. So, the same card will be saved over and over again.
Conceptual solution...
The idea is that Players and Decks are unique, but Cards are from a common pool (a set or collection that everyone can use to build Decks). Therefore, I have created a directory for saving/loading Players and their Decks and a separate directory for storing individual Cards that are part of a set. I would like saving and loading of Players and Decks to utilize Card IDs, which will then reference the Card directory for loading and instantiating the actual objects. Additionally, the reverse needs to happen upon saving (not saving the Deck with Cards, but with Card IDs).
The question(s)...
Is there a design pattern I should be utilizing to help with the saving/loading based on IDs? Should I break up Decks into Decks for game-play and Deck lists for storage? Should I created and store PlayerProfiles with DeckLists and use those to save/load Players and Decks?
NOTE: If you would like to see the code, let me know. It's just too much to post right here.
What you are looking for is the flyweight design pattern. Instead of storing a full copy of whatever a card is, you're just storing something like 5C, 8D etc. Your application should be able to "decode" that into the full object.
I am in trouble choosing the most pertinent structure for my data, here are the explanations:
I am actually working on a game project for school, a Bomberman like game in c++.
I am designing the Map object, who contain Bombs, Boxes, Players and Walls.
The map is 2D, I have already 2 containers of type:
std::unordered_map<int, std::unordered_map<int, AEntity*> > *UMap;
One contain Walls, the other contain destructible objects (Bombs, Boxes).
I have already discussed this choice here -> Choice of unsorted_map.
It's mainly for fast access time and because there can only be one element per map's box.
Now as the title suggest I'am in trouble choosing a data container for my players, because there can be multiple players on a single map's box, unordered_maps can't be used.
In a first time I was going to use a std::list<AEntity*> sorted with std::sorted, AEntity containing the entity information (coords), but while coding my
playerOn(const int x, const int y);
function I found it was a poor choice. I can't retrieve fast enough which player(s) is on the given box using dichotomies, and if there is no player of this box it's a waste of time.
How should I store my (AEntity)Players in order to be able to retrieve them fast
(On of the itchy thing is that there can be more than 500 player at the single time, on big map, that's why I am looking for optimization)
I am running out of brain juice. Thanks for your future answers.
Edit about my probleme
It's mainly because I want to know if there is another solution to go trough my whole std::list of player to find if there is someone on box(x, y). Looks slow and not optimized, but i can't figure another way to do this.
(I can change container type if needed)
First of all, before trying any optimization, you should profile your code to detect where is the bottleneck. You will be surprised. Once that said :
1) Your unordered_maps seem like a lot of over-engineering. The answers provided in your previous post are true but I think it is useless in your case. You absolutely do not care of a O(log(n)) cost when n = 500. Just make a vector of Entities*. It is much enough.
2) You seem to be falling in the god object anti-design pattern. A bomberman game is an excellent project for studying OOP, as it teaches you to avoid the God Object design pattern. Make sure each class does its own business and no class handles all the logic (I suspect your class Map or Game has too much power).
a) Create a vector of players, a vector of bombs, a vector of walls, a vector of fires, etc.
b) Map should be a 2-dimensionnal array storing list of pointers to the entities that are present on each Map's box. (Each Map[i][j] holds pointers to all the elements that are on the box of index (i,j)).
c) Bombs should create fire elements.
d) Your central routine should be something like :
while(gameContinued)
{
for each entity in the game
{
entity.Update(map);
}
game.Render();
}
Bomb update consists in making the bomb's texture rendering dynamic and create fires if delay is over-due (and update the Map with the fires pointers accordingly).
Fire update consists in nothing except vanishing if delay is over-due (and update the Map).
Player update consists in moving through keyboard event handling (and updating their current internal x and y values ), creating bomb if needed, dying if for their position (x,y), there is a fire in the Map[i][j] list of entities.
3) In most of my students implementation of bomberman, the only issue they can get is with textures and deep copy of objects. Make sure you have a Texture Loader (using Singleton Pattern) to avoid loading multiple times the same textures, and you should be fine.
I'm working on an iOS music app (written in C++) and my model looks more or less like this:
--Song
----Track
----Track
------Pattern
------Pattern
--------Note
--------Note
--------Note
So basically a Song has multiple Tracks, a Track can have multiple Patterns and a Pattern has multiple Notes. Each one of those things is represented by a class and except for the Song object, they're all stored inside vectors.
Each Note has a "frame" parameter so that I can calculate when a note should be played. For example, if I have 44100 samples / second and the frame for a particular note is 132300 I know that I need that Note at the start of the third second.
My question is how I should represent those notes for best performance? Right now I'm thinking of storing the notes in a vector datamember of each pattern and than loop all the Tracks of the Song, than look the Patterns and than loop the Notes to see which one has a frame datamember that is greater than 132300 and smaller than 176400 (start of 4th second).
As you can tell, that's a lot of loops and a song could be as long as 10 minutes. So I'm wondering if this will be fast enough to calculate all the frames and send them to the buffer on time.
One thing you should remember is that to improve performance, normally memory consumption would have to increase. It is also relevant (and justified) in this case, because I believe you want to store the same data twice, in different ways.
First of all, you should have this basic structure for a song:
map<Track, vector<Pattern>> tracks;
It maps each Track to a vector of Patterns. Map is fine, because you don't care about the order of tracks.
Traversing through Tracks and Patterns should be fast, as their amounts will not be high (I assume). The main performance concern is to loop through thousands of notes. Here's how I suggest to solve it:
First of all, for each Pattern object you should have a vector<Note> as your main data storage. You will write all the changes on the Pattern's contents to this vector<Note> first.
vector<Note> notes;
And for performance considerations, you can have a second way of storing notes:
map<int, vector<Notes>> measures;
This one will map each measure (by its number) in a Pattern to the vector of Notes contained in this measure. Every time data changes in the main notes storage, you will apply the same changes to data in measures. You could also do it only once every time before the playback, or even while playback, in a separate thread.
Of course, you could only store notes in measures, without having to sync two sources of data. But it may be not so convenient to work with when you have to apply mass operations on bunches of notes.
During the playback, before the next measure starts, the following algorithm would happen (roughly):
In every track, find all patterns, for which pattern->startTime <= [current playback second] <= pattern->endTime.
For each pattern, calculate current measure number and get vector<Notes> for the corresponding measure from the measures map.
Now, until the next measure (second?) starts, you only have to loop through current measure's notes.
Just keep those vectors sorted.
During playback, you can just keep a pointer (index) into each vector for the last note player. To search for new notes, you check have to check the following note in each vector, no looping through notes required.
Keep your vectors sorted, and try things out - that is more important and any answer you can receive here.
For all of your questions you should seek to answer then with tests and prototypes, then you will know if you even have a problem. And also while trying it out you will see things that you wouldn't normally see with just the theory alone.
and my model looks more or less like this:
Several critically important concepts are missing from your model:
Tempo.
Dynamics.
Pedal
Instrument
Time signature.
(Optional) Tonality.
Effect (Reverberation/chorus, pitch wheel).
Stereo positioning.
Lyrics.
Chord maps.
Composer information/Title.
Each Note has a "frame" parameter so that I can calculate when a note should be played.
Several critically important concepts are missing from your model:
Articulation.
Aftertouch.
Note duration.
I'd advise to take a look at lilypond. It is typesetting software, but it is also one of the most precise way to represent music in human-readable text format.
My question is how I should represent those notes for best performance?
Put them all into std::map<Timestamp, Note> and find segment you want to playing using lower_bound/upper_bound. Alternatively you could binary search them in flat std::vector as long as data is sorted.
Unless you want to make a "beeper", making music application is much more difficult than you think. I'd strongly recommend to try another project.
I just learned about the i/o part of the STL, more specifically fstream. Although I can now save binary info and classes I've made to the hard drive, I am not sure how to define how the info should be read.
I saw the answer for making a file format from this post:
Typically you would define a lot of records/structures, such as
BITMAPINFOHEADER, and specify in what order they should come, how they
should be nestled, and you might need to write a lot of indices and
look-up tables. Such files consists of a number of records (maybe
nestled), look-up tables, magic words (indicating structure begin,
structures end, etc.) and strings in a custom-defined format.
What I want to know specifically is how to do this with the STL and C++...
Since the format is meant simply for the use of a game I would think it would be much easier though. The format should:
Be traversable (I can look through it and find the start of structure and maybe check its name
Be able to hold multiple classes and data in a single file
Have identifiable starts and ends to sections: such as the space in text files
Maybe have it's own icon to represent it??
How do I do this in c++ ?
The first stage in determining how to structure your save-file is determining what information needs to be stored. Presumably, you have a list of entities, each of which with generic information (probably derived from one of a few base classes), such as position, velocity etc.
One of the best things you can do to implement a map format is to have a save-parser for each class (some can just derive from the base class' save-parser). So for instance, if you have a player class, which derives from CBaseNPC, you could most-likely simply derive from CBaseNPC, override the parser, calling the base-class function, and adding any other necessary fields, for example, if we had (pseudocode):
void CBaseNPC::Save() {
SaveToFile( health );
SaveToFile( armor );
SaveToFile( weapons );
SaveToFile( position );
SaveToFile( angles );
}
Then for your player class:
void CPlayer::Save() {
CBaseNPC::Save();
SaveToFile( achievement_progress );
}
Obviously, this is just a simple example, and no doubt your saving parsers will have more fields etc. to deal with.
Dealing with the structure of the file itself, the main thing you need to worry about is delimiters, how will your main load-parser recognise what each field corresponds to?
I suppose the best way to explain this would be with an example, the following could be a simple start to a save-file:
Map: {mapname}
Gametime: {gametime}
===Player===
Health: {health}
Armor: {armor}
Weapons: {wep1 (wep1Ammo), wep2 (wep2Ammo), wep3 (wep3Ammo)}
Position: {x, y, z}
Angles: {yaw, pitch, roll} // Could be quaternion instead.
AchievementProgress: {arbritraryData}
===Player===
===NPC-npc_name===
Health: {health}
Armor: {armor}
Weapons: {wep1 (wep1Ammo), wep2 (wep2Ammo), wep3 (wep3Ammo)}
Position: {x, y, z}
Angles: {yaw, pitch, roll} // Could be quaternion instead.
===NPC-npc_name===
===Entity-item_name===
Position: {x, y, z}
Angles: {yaw, pitch, roll}
Model: {modelname}
===Entity-item_name===
Here we have used the "===" string as a delimiter for the start of a class's parameters, and a new line as the delimiter for the parameters within each class.
It is then a relatively simple matter of structuring your parser so it reads in the map name, and loads it. Then sets the game-time to the value specified in the save-file.
It then looks through the file until it finds a "===" reads the string it encounters, and looks it up from a dictionary (possibly an std::map or std::unordered_map) to determine the class to create (or edit) with the information in the file. Once it has determined the class type, it can then proceed to call the Load() function from that class, which will retrieve all the information contained. The parser then looks for the next instance of the "==={string encountered}===" and closes that class. It then proceeds following the same procedure with the next class encountered.
Sorry for the length of this post, and I'm sure it could be made briefer and there are probably some things I have missed, I just wrote this off the top of my head, so there may be erroneous things here, but I hope it puts you on the right path to getting a workable save-file format. :)
If you still have any problems or questions regarding my post, please comment, I'll do my best to answer promptly.