Fill poker pots - c#

Essentially there is a table and player A raises to 100$, player B calls (accepts), player C only has 50$ so the pots are created as 100$ (between player A and B) and 150$ (between all three players because everyone chips in at 50$).
How would I implement such a function and handle all the pots properly?
This is what I have so far:
static public void FillPots(Room r, decimal Val, int Player)
{
decimal NewRaise = Val;
if (NewRaise > 0)
{
foreach (Program.Player pz in r.Seated)
{
if (pz == null) { continue; }
if (pz.BuyIn < NewRaise)
{
Pot _pot = new Pot { PotSize = r.MaxPlayers, PotBuy = (NewRaise - pz.BuyIn), PotVal = new decimal[r.MaxPlayers] };
Array.Clear(_pot.PotVal, 0, r.MaxPlayers);
r.Pots.Add(_pot);
NewRaise -= (NewRaise - pz.BuyIn);
}
}
}
for (int i = 0; i < r.Pots.Count; i++)
{
if (r.Pots[i].PotVal[Player] == 0m && NewRaise >= r.Pots[i].PotBuy)
{
r.Pots[i].PotVal[Player] += r.Pots[i].PotBuy;
NewRaise -= r.Pots[i].PotBuy;
}
}
if (NewRaise > 0)
{
Pot _pot = new Pot { PotSize = r.MaxPlayers, PotBuy = (NewRaise), PotVal = new decimal[r.MaxPlayers] };
Array.Clear(_pot.PotVal, 0, r.MaxPlayers);
_pot.PotVal[Player] += NewRaise;
r.Pots.Add(_pot);
NewRaise = 0;
}
}
It's all pretty confusing. It is critical to keep the position of every individual player relative to the player number (int Player) within the array.

I can't speak to C#, but since you have no answers here I'll tell you in general how to handle poker pots. There are two methods: pot-centric and player-centric. I generally prefer the latter since there is less data to manage.
You need one variable for the "combined pot" (let's call it POT), one variable for the "current total bet amount" (CBET), one for last raise amount (LRAISE), and three variables for each player: stake (PSTAKE[N]), "current bet" (PBET[N]), "contribution to pot" (PCONTRIB[N]).
When the hand is dealt, set POT and each player's PCONTRIB[] to 0. If there were antes, add them to POT and to each player's PCONTRIB[], removing them from PSTAKE[].
At the start of each betting round, set CBET, LRAISE and all PBET[] to 0. If this is the first round, and there are blinds, set those players' PBET[] to the blind amounts, removing them from PSTAKE[].
Each player in turn has three choices: (1) fold (you might want to disallow this if CBET is 0), (2) call, in which case he must make his PBET[] equal to CBET (if CBET is 0, this is called a "check", otherwise the call amount is CBET-PBET[], which must be moved from PSTAKE[] to PBET[]). (3) raise, in which the player must increase the CBET amount by at least LRAISE (and obeying any other limits, this amount becoming the new LRAISE), moving the needed amount from his stake. Note: you also need to keep track of who the last raiser was, so that he is not allowed to raise himself.
If the player's stake is insufficient to call or raise, he can go "all in" (if otherwise allowed) moving his entire stake to his PBET[]. When all players have called CBET or gone all in, the betting round is over. If one player raised, all the others folded, and none is all in, then just award the pot to the raiser. Otherwise for each player, add his PBET[] to his PCONTRIB[] and to the POT.
If hand continues to showdown, award the pot like this: Start with the best hand: his winnable amount (W) is his PCONTRIB[]. Go to each player (including him), subtract from POT the lesser of W and that player's PCONTRIB[], and award it to winner. Remove winner from player list, remove any players whose PCONTRIB[] is now 0, and continue with next best hand. Remove that winner, etc., and continue until POT is 0.
The pot-centric method I think is more complex. Instead of keeping each player's contribution, you keep a list of central pot and side pots, and for each pot a list of players involved in that pot (there might be as many pots as players). Then the pots are awarded outside-in, instead of inside-out as above. This is more like how dealers are taught to do it in real games.

Update:
I just realized I was "skipping ahead" and not actually answering what OP was asking. But I'll leave my answer here because this question still shows up in searches related to programmatic poker pot resolution. I had already developed all the action logic prior to resolving where the chips all go.
Previous Answer:
Is it ever too late to answer an unanswered question? I was also looking for the answer to this. The answers I found were a bit confusing, so I finally wrote my own code on dotnetfiddle:
https://dotnetfiddle.net/P0wgR5
Seeing as how I didn't do it exactly as Lee Daniel Crocker mentioned, I wonder if there are bugs with what I've done. I'd be happy to fix them and update code here.
I'm not sure if it's good practice to paste 140 lines of code into StackOverflow, but that's how many lines I ended up with. The console shows what's being done, and you can experiment with hand creation in the Main function.
I tested this thoroughly, and compared the results to this pot calculator:
https://www.pokerlistings.com/rules-for-poker-all-in-situations-poker-side-pot-calculator
The results appeared to line up.

Related

Handling hundreds of AI efficiently

To practice AI, I decided to make a AI simulation game like Cuboid Sandbox. Like Cuboid Sandbox, it would have 3 teams of AI (however mine has red, green, and blue rather than red, yellow, and blue).
In Cuboid Sandbox, there was a max of 750 in total and mine has no limit (yet). Through testing, I've found that Cuboid Sandbox doesn't seem to have any drops in framerate no matter how many AI there currently is (using bandicam's framerate counter since there's none in the game so it may be slightly inaccurate although it never looked choppy/laggy).
And in mine, I start to drop to 40fps at around 100 AI in total.
I've tracked this down to where I update my food lists for the AI
Food is separated by each team (if a team has no food left, it goes to the nearest) and for each AI I set a list called 'availableFoodSources' to a list called 'redFood' that's set in the spawner function when it spawns the food on startup and only updates when a food source is destroyed or a new one is spawned.
At large amounts of AI this causes a lot of lag.
There's also another similar loop (removed due to immense amount of lag) where I check for if an enemy tribe distance is less than 20 by loop through all other AI tribes and checking the distance for each one.
I'm not sure how to tackle either of these issues.
Also I'm using StateMachineBehaviour in unity which removes my ability to (easily) use coroutines.
Here's the bit of code where I update availableFoodSources:
if (aIController.team == Color.red)
{
availableFoodSources = spawner.redFood;
}
if (aIController.team == Color.green)
{
availableFoodSources = spawner.greenFood;
}
if (aIController.team == Color.blue)
{
availableFoodSources = spawner.blueFood;
}
if (!Attacking)
{
if (animator.transform.GetComponent<AIController>().hunger > 30)
{
GameObject f = FindClosestFoodSource(animator.transform);
Vector3 closestFoodPos = f.transform.position;
Debug.DrawLine(animator.transform.position, closestFoodPos);
closestFoodPos.y = animator.transform.position.y;
animator.GetComponent<NavMeshAgent>().SetDestination(closestFoodPos);
}
else
{
animator.SetBool("Walking", false);
}
}

How to properly check the available path on a maze [duplicate]

What are the possible ways to solve a maze?
Ive got two ideas, but I think they are not very elegant.
Base situation: We have a matrix, and the elements in this matrix are ordered in a way that it represents a maze, with one way in, and one out.
My first idea was to send a robot through the maze, following one side, until it's out of the maze. I think this is a very slow solution.
The second one passes through every successive item marked with 1, checks where it can go (up, right, down, left) chooses one way and it continues its path there. This is even slower than the first one.
Of course it's a bit faster if I make the two bots multi-threaded at every junction, but thats also not the best way.
There needs to be better solutions to send a bot through a maze.
EDIT
First: Thanks for the nice answers!
The second part of my question is: What to do in the case if we have a multi-dimensional graph? Are there special practices for that, or is the answer of Justin L. usable for that too?
I think it's not the best way for this case.
The third question:
Which of these maze solver algorithms is/are the fastest? (Purely hypothetically)
You can think of your maze as a tree.
A
/ \
/ \
B C
/ \ / \
D E F G
/ \ \
H I J
/ \
L M
/ \
** O
(which could possibly represent)
START
+ +---+---+
| A C G |
+---+ + + +
| D B | F | J |
+---+---+ +---+---+
| L H E I |
+---+ +---+---+
| M O |
+ +---+
FINISH
(ignoring left-right ordering on the tree)
Where each node is a junction of paths. D, I, J, L and O are dead ends, and ** is the goal.
Of course, in your actual tree, each node has a possibility of having as many as three children.
Your goal is now simply finding what nodes to traverse to to find the finish. Any ol' tree search algorithm will do.
Looking at the tree, it's pretty easy to see your correct solution by simply "tracing up" from the ** at the deepest part of the tree:
A B E H M **
Note that this approach becomes only slightly more complicated when you have "loops" in your maze (i.e., when it is possible, without backtracing, you re-enter a passage you've already traversed through). Check the comments for one nice solution.
Now, let's look at your first solution you mentioned, applied to this tree.
Your first solution is basically a Depth-First Search, which really isn't that bad. It's actually a pretty good recursive search. Basically, it says, "Always take the rightmost approach first. If nothing is there, backtrack until the first place you can go straight or left, and then repeat.
A depth-first search will search the above tree in this order:
A B D (backtrack) E H L (backtrack) M ** (backtrack) O (backtrack thrice) I
(backtrack thrice) C F (backtrack) G J
Note that you can stop as soon as you find the **.
However, when you actually code a depth-first search, using recursive programming makes makes everything much easier. Even iterative methods work too, and you never have to explicitly program how to backtrack. Check out the linked article for implementations.
Another way of searching a tree is the Breadth-First solution, which searches through trees by depth. It'd search through the above tree in this order:
A (next level) B C (next level) D E F G (next level)
H I J (next level) L M (next level) ** O
Note that, due to the nature of a maze, breadth-first has a much higher average amount of nodes it checks. Breadth-first is easily implementing by having a queue of paths to search, and each iteration popping a path out of a queue, "exploding it" by getting all of the paths that it can turn into after one step, and putting those new paths at the end of the queue. There are no explicit "next level" commands to code, and those were just there to aid in understanding.
In fact, there is a whole expansive list of ways to search a tree. I've just mentioned the two simplest, most straightforward way.
If your maze is very, very long and deep, and has loops and crazies, and is complicated, I suggest the A* algorithm, which is the industry standard pathfinding algorithm which combines a Breadth-First search with heuristics...sort of like an "intelligent breadth-first search".
It basically works like this:
Put one path in a queue (the path where you only walk one step straight into the maze). A path has a "weight" given by its current length + its straight-line distance from the end (which can be calculated mathematically)
Pop the path with the lowest weight from the queue.
"Explode" the path into every path that it could be after one step. (i.e., if your path is Right Left Left Right, then your exploded paths are R L L R R and R L L R L, not including illegal ones that go through walls)
If one of these paths has the goal, then Victory! Otherwise:
Calculate the weights of the exploded paths, and put all of them back into the queue (not including the original path)
Sort the queue by weight, lowest first. Then repeat from Step #2
And that's A*, which I present specially highlighted because it is more or less the industry standard pathfinding algorithm for all applications of pathfinding, including moving from one edge of the map to another while avoiding off-road paths or mountains, etc. It works so well because it uses a shortest possible distance heuristic, which gives it its "intelligence". A* is so versatile because, given any problem, if you have a shortest possible distance heuristic available (ours is easy -- the straight line), you can apply it.
BUT it is of great value to note that A* is not your only option.
In fact, the wikipedia category of tree traversal algorithms lists 97 alone! (the best will still be on this page linked earlier)
Sorry for the length =P (I tend to ramble)
Lots of maze-solving algorithms exist:
http://en.wikipedia.org/wiki/Maze_solving_algorithm
http://www.astrolog.org/labyrnth/algrithm.htm#solve
For a robot, Tremaux's algorithm looks promising.
An interesting approach, at least I found it interesting, is to use cellular automata. In short a "space" cell surrounded by 3 "wall" cells turns into a "wall" cell. At the end the only space cells left are the ones on route to the exit.
If you look at the tree Justin put in his answer then you can see that leaf nodes have 3 walls. Prune the tree until you have a path.
This is one of my favorite algorithms ever....
1) Move forward
2) Are you at a wall?
2a) If yes, turn left
3) Are you at the finish?
3a) If no, go to 1
3b) If yes, solved
How about building a graph out of your Matrix and using Breadth First Search, Depth First Search or Dijkstras Algorithm?
I had a similar problem in one of my University Comp. Sci. courses. The solution we came up with was to follow the left hand wall (right hand wall will work just as well). Here is some pseudocode
While Not At End
If Square To Left is open,
Rotate Left
Go Forward
Else
Rotate Right
End If
Wend
That's basically it. The complex part is keeping track of which direction your facing, and figuring out which grid position is on your left based on this direction. It worked for any test case I put up against it. Interesting enough the Professors solution was something along the lines of:
While Not At End
If Can Go North
Go North
ElseIf Can Go East
Go East
ElseIf Can Go South
Go South
ElseIf Can Go West
Go West
EndIf
Wend
Which will work well for most simple mazes, but fails on the a maze that looks like the following:
SXXXXXXXXXXXXX
X X
X X
X X
XXX X
X X X
X XXXXXXXXXXX XXXE
X X
XXXXXXXXXXXXXXXXXXX
With S and E being the start and end.
With anything that doesn't follow the wall, you end up having to keep a list of the places you have been, so that you can backtrack if necessary, when you fall into a dead end, and so that you don't get caught in a loop. If you follow the wall, there's no need to keep track of where you've been. Although you won't find the most optimal path through the maze, you will always get through it.
This is a very simple representation to simulate maze in C++ :)
#ifndef vAlgorithms_Interview_graph_maze_better_h
#define vAlgorithms_Interview_graph_maze_better_h
static const int kMaxRows = 100;
static const int kMaxColumns = 100;
class MazeSolver
{
private:
char m_matrix[kMaxRows][kMaxColumns]; //matrix representation of graph
int rows, cols; //actual rows and columns
bool m_exit_found;
int m_exit_row, m_exit_col;
int m_entrance_row, m_entrance_col;
struct square //abstraction for data stored in every verex
{
pair<int, int> m_coord; //x and y co-ordinates of the matrix
square* m_parent; //to trace the path backwards
square() : m_parent(0) {}
};
queue<square*> Q;
public:
MazeSolver(const char* filename)
: m_exit_found(false)
, m_exit_row(0)
, m_exit_col(0)
, m_entrance_row(0)
, m_entrance_col(0)
{
ifstream file;
file.open(filename);
if(!file)
{
cout << "could not open the file" << endl << flush;
// in real world, put this in second phase constructor
}
init_matrix(file);
}
~MazeSolver()
{
}
void solve_maze()
{
//we will basically use BFS: keep pushing squares on q, visit all 4 neighbors and see
//which way can we proceed depending on obstacle(wall)
square* s = new square();
s->m_coord = make_pair(m_entrance_row, m_entrance_col);
Q.push(s);
while(!m_exit_found && !Q.empty())
{
s = Q.front();
Q.pop();
int x = s->m_coord.first;
int y = s->m_coord.second;
//check if this square is an exit cell
if(x == m_exit_row && y == m_exit_col)
{
m_matrix[x][y] = '>'; // end of the path
m_exit_found = true;
//todo: try breaking? no= queue wont empty
}
else
{
//try walking all 4 neighbors and select best path
//NOTE: Since we check all 4 neighbors simultaneously,
// the path will be the shortest path
walk_path(x-1, y, s);
walk_path(x+1, y, s);
walk_path(x, y-1, s);
walk_path(x, y+1, s);
}
} /* end while */
clear_maze(); //unset all previously marked visited shit
//put the traversed path in maze for printing
while(s->m_parent)
{
m_matrix[s->m_coord.first][s->m_coord.second] = '-';
s = s->m_parent;
} /* end while */
}
void print()
{
for(int i=0; i<rows; i++)
{
for(int j=0; j<cols; j++)
cout << m_matrix[i][j];
cout << endl << flush;
}
}
private:
void init_matrix(ifstream& file)
{
//read the contents line-wise
string line;
int row=0;
while(!file.eof())
{
std::getline(file, line);
for(int i=0; i<line.size(); i++)
{
m_matrix[row][i] = line[i];
}
row++;
if(line.size() > 0)
{
cols = line.size();
}
} /* end while */
rows = row - 1;
find_exit_and_entry();
m_exit_found = false;
}
//find and mark ramp and exit points
void find_exit_and_entry()
{
for(int i=0; i<rows; i++)
{
if(m_matrix[i][cols-1] == ' ')
{
m_exit_row = i;
m_exit_col = cols - 1;
}
if(m_matrix[i][0] == ' ')
{
m_entrance_row = i;
m_entrance_col = 0;
}
} /* end for */
//mark entry and exit for testing
m_matrix[m_entrance_row][m_entrance_col] = 's';
m_matrix[m_exit_row][m_exit_col] = 'e';
}
void clear_maze()
{
for(int x=0; x<rows; x++)
for(int y=0; y<cols; y++)
if(m_matrix[x][y] == '-')
m_matrix[x][y] = ' ';
}
// Take a square, see if it's the exit. If not,
// push it onto the queue so its (possible) pathways
// are checked.
void walk_path(int x, int y, square* parent)
{
if(m_exit_found) return;
if(x==m_exit_row && y==m_exit_col)
{
m_matrix[x][y] = '>';
m_exit_found = true;
}
else
{
if(can_walk_at(x, y))
{
//tag this cell as visited
m_matrix[x][y] = '-';
cout << "can walk = " << x << ", " << y << endl << flush;
//add to queue
square* s = new square();
s->m_parent = parent;
s->m_coord = make_pair(x, y);
Q.push(s);
}
}
}
bool can_walk_at(int x, int y)
{
bool oob = is_out_of_bounds(x, y);
bool visited = m_matrix[x][y] == '-';
bool walled = m_matrix[x][y] == '#';
return ( !oob && !visited && !walled);
}
bool is_out_of_bounds(int x, int y)
{
if(x<0 || x > rows || y<0 || y>cols)
return true;
return false;
}
};
void run_test_graph_maze_better()
{
MazeSolver m("/Users/vshakya/Dropbox/private/graph/maze.txt");
m.print();
m.solve_maze();
m.print();
}
#endif
Just an idea. Why not throw some bots in there in the monte carlo fashion.
Let's call the first generation of bots gen0.
We only keep the bots from gen0 that have some continuous roads in this way:
-from the start to some point
or -from some point to the end
We run a new gen1 of bots in new random dots, then we try to connect the roads of the bots of gen1 with those of gen0 and see if we get a continous road from start to finish.
So for genn we try to connect with the bots form gen0, gen1, ..., genn-1.
Of course a generation lasts only a feasibil finit amount of time.
I don't know if the complexion of the algorithm will prove to be practical for small data sets.
Also the algorithm assumes we know start and finish points.
some good sites for ideas:
http://citeseerx.ist.psu.edu/
http://arxiv.org/
If the robot can keep track of its location, so it knows if it has been to a location before, then depth-first search is the obvious algorithm. You can show by an adversarial argument that it is not possible to get better worst-case performance than depth-first search.
If you have available to you techniques that cannot be implemented by robots, then breadth-first search may perform better for many mazes, as may Dijkstra's algorithm for finding the shortest path in a graph.
Same answer as all questions on stack-overflow ;)
Use vi!
http://www.texteditors.org/cgi-bin/wiki.pl?Vi-Maze
It's truly fascinating to see a text editor solve an ascii-maze, I'm sure the emacs guys have an equivalent ..
there are many algorithms, and many different settings that specify which algorithm is best.
this is just one idea about an interesting setting:
let's assume you have the following properties...
you move a robot and you want to minimize its movement, not its CPU usage.
that robot can either inspect only its neighbouring cells or look along corridors either seeing or not seeing cross-ways.
it has GPS.
it knows the coordinates of its destination.
then you can design an A.I. which...
draws a map – every time it receives new information about the maze.
calculates the minimal known path lengths between all unobserved positions (and itself and the destination).
can prioritize unobserved positions for inspection based upon surrounding structures. (if it is impossible to reach the destination from there anyway...)
can prioritize unobserved positions for inspection based upon direction and distance to destination.
can prioritize unobserved positions for inspection based upon experience about collecting information. (how far can it see on average and how far does it have to walk?)
can prioritize unobserved positions to find possible shortcuts. (experience: are there many loops?)
This azkaban algorithm might also help you,
http://journals.analysisofalgorithms.com/2011/08/efficient-maze-solving-approach-with.html
The best way to solve a maze is to use a connectivity algorithm such as union-find which is a quasi-linear time algorithm assuming path compression is done.
Union-Find is a data structure that tells you whether two elements in a set are transitively connected.
To use a union-find data structure to solve a maze, first the neighbor connectivity data is used to build the union-find data structure. Then the union find is compressed. To determine whether the maze is solvable the entrance and exit values are compared. If they have the same value, then they are connected and the maze is solvable. Finally, to find a solution, you start with the entrance and examine the root associated with each of its neighbors. As soon as you find a previously unvisited neighbor with the same root as the current cell, you visit that cell and repeat the process.
The main disadvantage of this approach is that it will not tell you the shortest route through the maze, if there is more than one path.
Not specifically for your case, but I've come across several programming contest questions where I found the Lee's algorithm quite handy to code up quickly. Its not the most efficient for all cases, but is easy to crank out. Here's one I hacked up for a contest.

Unity 3d: rigidbody.AddForce(forceDirection.normalized * force) moving objects away from parent and joint

So, this seems to be a strange one (to me). I'm relatively new to Unity, so I'm sure this is me misunderstanding something.
I'm working on a VSEPR tutorial module in unity. VSEPR is the model by which electrons repel each other and form the shape (geometry) of atoms.
I'm simulating this by making (in this case) 4 rods (cylinder primitives) and using rigidbody.AddForce to apply an equal force against all of them. This works beautifully, as long as the force is equal. In the following image you'll see the rods are beautifully equi-distant at 109.47 degrees (actually you can "see" their attached objects, two lone pairs and two electron bonds...the rods are obscured in the atom shell.)
(BTW the atom's shell is just a sphere primitive - painted all pretty.)
HOWEVER, in the real world, the lone pairs actually exert SLIGHTLY more force...so when I add this additional force to the model...instead of just pushing the other electron rods a little farther away, it pushes the ENTIRE 4-bond structure outside the atom's shell.
THE REASON THIS SEEMS ODD IS...two things.
All the rods are children of the shell...so I thought that made them somewhat immobile compared to the shell (I.e. if they moved, the shell would move with them...which would be fine).
I have a ConfiguableJoint holding the rods to the center of the atoms shell ( 0,0,0). The x/y/z-motion is set to fixed. I thought this should keep the rods fairly immutably attached to the 0,0,0 center of the shell...but I guess not.
POINTS OF INTEREST:
The rods only push on each other, by a script attached to one rod adding force to an adjacent rod. they do not AddForce to the atom shell or anything else.
CODE:
void RepulseLike() {
if (control.disableRepulsionForce) { return; } // No force when dragging
//////////////////// DETERMINE IF FORCE APPLIED //////////////////////////////
// Scroll through each Collider that this.BondStick bumps
foreach (Collider found in Physics.OverlapSphere(transform.position, (1f))) {
// Don't repel self
if (found == this.collider) { continue; }
// Check for charged particle
if (found.gameObject.tag.IndexOf("Charge") < 0) { continue; }// No match "charge", not a charged particle
/////////////// APPLY FORCE ///////////////
// F = k(q1*q2/r^2)
// where
// k = Culombs constant which in this instance is represented by repulseChargeFactor
// r = distance
// q1 and q2 are the signed magnitudes of the charges, in this case -1 for electrons and +1 for protons
// Swap from local to global variable for other methods
other = found;
/////////////////////////////////
// Calculate pushPoints for SingleBonds
forceDirection = (other.transform.position - transform.position) * magnetism; //magnetism = 1
// F = k(q1*q2/distance^2), q1*q2 ia always one in this scenario. k is arbitrary in this scenario
force = control.repulseChargeFactor * (1 / (Mathf.Pow(distance, 2)));
found.rigidbody.AddForce(forceDirection.normalized * force);// * Time.fixedDeltaTime);
}//Foreach Collider
}//RepulseLike Method
You may want to use spheres to represent electrons, so apply forces onto them and re-orient(rotate) rods according to this sphere.
I think I found my own answer...unless someone has suggestions for a better way to handle this.
I simply reduced the mass of the electron rods, and increased the mass of the sphere. I'm not sure if this is the "best practices" solution or a kluge...so input still welcomed :-)

Vector direction for gravity in a circular orbit

I am currently working on a project in C# where i play around with planetary gravitation, which i know is a hardcore topic to graps to it's fullest but i like challenges. I've been reading up on Newtons laws and Keplers Laws, but one thing i cannot figure out is how to get the correct gravitational direction.
In my example i only have 2 bodies. A Satellite and a Planet. This is to make is simplify it, so i can grasp it - but my plan is to have multiple objects that dynamically effect each other, and hopefully end up with a somewhat realistic multi-body system.
When you have an orbit, then the satellite has a gravitational force, and that is ofcourse in the direction of the planet, but that direction isn't a constant. To explain my problem better i'll try using an example:
let's say we have a satellite moving at a speed of 50 m/s and accelerates towards the planet at a speed of 10 m/s/s, in a radius of 100 m. (all theoretical numbers) If we then say that the framerate is at 1, then after one second the object will be 50 units forward and 10 units down.
As the satellite moves multiple units in a frame and about 50% of the radius, the gravitational direcion have shifted alot, during this frame, but the applied force have only been "downwards". this creates a big margin of error, especially if the object is moving a big percentage of the radius.
In our example we'd probably needed our graviational direction to be based upon the average between our current position and the position at the end of this frame.
How would one go about calculating this?
I have a basis understanding of trigonometry, but mainly with focus on triangles. Assume i am stupid, because compared to any of you, i probably am.
(I made a previous question but ended up deleting it as it created some hostility and was basicly not that well phrased, and was ALL to general - it wasn't really a specific question. i hope this is better. if not, then please inform me, i am here to learn :) )
Just for reference, this is the function i have right now for movement:
foreach (ExtTerBody OtherObject in UniverseController.CurrentUniverse.ExterTerBodies.Where(x => x != this))
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R,2) * UniverseController.DeltaTime;
Vector2 NonNormTwo = (OtherObject.Position - Position).Normalized() * V;
Vector2 NonNormDir = Velocity + NonNormTwo;
Velocity = NonNormDir;
Position += Velocity * Time.DeltaTime;
}
If i have phrased myself badly, please ask me to rephrase parts - English isn't my native language, and specific subjects can be hard to phrase, when you don't know the correct technical terms. :)
I have a hunch that this is covered in keplers second law, but if it is, then i'm not sure how to use it, as i don't understand his laws to the fullest.
Thank you for your time - it means alot!
(also if anyone see multi mistakes in my function, then please point them out!)
I am currently working on a project in C# where i play around with planetary gravitation
This is a fun way to learn simulation techniques, programming and physics at the same time.
One thing I cannot figure out is how to get the correct gravitational direction.
I assume that you are not trying to simulate relativistic gravitation. The Earth isn't in orbit around the Sun, the Earth is in orbit around where the sun was eight minutes ago. Correcting for the fact that gravitation is not instantaneous can be difficult. (UPDATE: According to commentary this is incorrect. What do I know; I stopped taking physics after second year Newtonian dynamics and have only the vaguest understanding of tensor calculus.)
You'll do best at this early stage to assume that the gravitational force is instantaneous and that planets are points with all their mass at the center. The gravitational force vector is a straight line from one point to another.
Let's say we have a satellite moving at a speed of 50 m/s ... If we then say that the framerate is one frame per second then after one second the object will be 50 units right and 10 units down.
Let's make that more clear. Force is equal to mass times acceleration. You work out the force between the bodies. You know their masses, so you now know the acceleration of each body. Each body has a position and a velocity. The acceleration changes the velocity. The velocity changes the position. So if the particle starts off having a velocity of 50 m/s to the left and 0 m/s down, and then you apply a force that accelerates it by 10 m/s/s down, then we can work out the change to the velocity, and then the change to the position. As you note, at the end of that second the position and the velocity will have both changed by a huge amount compared to their existing magnitudes.
As the satellite moves multiple units in a frame and about 50% of the radius, the gravitational direcion have shifted alot, during this frame, but the applied force have only been "downwards". this creates a big margin of error, especially if the object is moving a big percentage of the radius.
Correct. The problem is that the frame rate is enormously too low to correctly model the interaction you're describing. You need to be running the simulation so that you're looking at tenths, hundredths or thousanths of seconds if the objects are changing direction that rapidly. The size of the time step is usually called the "delta t" of the simulation, and yours is way too large.
For planetary bodies, what you're doing now is like trying to model the earth by simulating its position every few months and assuming it moves in a straight line in the meanwhile. You need to actually simulate its position every few minutes, not every few months.
In our example we'd probably needed our graviational direction to be based upon the average between our current position and the position at the end of this frame.
You could do that but it would be easier to simply decrease the "delta t" for the computation. Then the difference between the directions at the beginning and the end of the frame is much smaller.
Once you've got that sorted out then there are more techniques you can use. For example, you could detect when the position changes too much between frames and go back and redo the computations with a smaller time step. If the positions change hardly at all then increase the time step.
Once you've got that sorted, there are lots of more advanced techniques you can use in physics simulations, but I would start by getting basic time stepping really solid first. The more advanced techniques are essentially variations on your idea of "do a smarter interpolation of the change over the time step" -- you are on the right track here, but you should walk before you run.
I'll start with a technique that is almost as simple as the Euler-Cromer integration you've been using but is markedly more accurate. This is the leapfrog technique. The idea is very simple: position and velocity are kept at half time steps from one another.
The initial state has position and velocity at time t0. To get that half step offset, you'll need a special case for the very first step, where velocity is advanced half a time step using the acceleration at the start of the interval and then position is advanced by a full step. After this first time special case, the code works just like your Euler-Cromer integrator.
In pseudo code, the algorithm looks like
void calculate_accel (orbiting_body_collection, central_body) {
foreach (orbiting_body : orbiting_body_collection) {
delta_pos = central_body.pos - orbiting_body.pos;
orbiting_body.acc =
(central_body.mu / pow(delta_pos.magnitude(),3)) * delta_pos;
}
}
void leapfrog_step (orbiting_body_collection, central_body, delta_t) {
static bool initialized = false;
calculate_accel (orbiting_body_collection, central_body);
if (! initialized) {
initialized = true;
foreach orbiting_body {
orbiting_body.vel += orbiting_body.acc*delta_t/2.0;
orbiting_body.pos += orbiting_body.vel*delta_t;
}
}
else {
foreach orbiting_body {
orbiting_body.vel += orbiting_body.acc*delta_t;
orbiting_body.pos += orbiting_body.vel*delta_t;
}
}
}
Note that I've added acceleration as a field of each orbiting body. This was a temporary step to keep the algorithm similar to yours. Note also that I moved the calculation of acceleration to it's own separate function. That is not a temporary step. It is the first essential step to advancing to even more advanced integration techniques.
The next essential step is to undo that temporary addition of the acceleration. The accelerations properly belong to the integrator, not the body. On the other hand, the calculation of accelerations belongs to the problem space, not the integrator. You might want to add relativistic corrections, or solar radiation pressure, or planet to planet gravitational interactions. The integrator should be unaware of what goes into those accelerations are calculated. The function calculate_accels is a black box called by the integrator.
Different integrators have very different concepts of when accelerations need to be calculated. Some store a history of recent accelerations, some need an additional workspace to compute an average acceleration of some sort. Some do the same with velocities (keep a history, have some velocity workspace). Some more advanced integration techniques use a number of techniques internally, switching from one to another to provide the best balance between accuracy and CPU usage. If you want to simulate the solar system, you need an extremely accurate integrator. (And you need to move far, far away from floats. Even doubles aren't good enough for a high precision solar system integration. With floats, there's not much point going past RK4, and maybe not even leapfrog.)
Properly separating what belongs to whom (the integrator versus the problem space) makes it possible to refine the problem domain (add relativity, etc.) and makes it possible to easily switch integration techniques so you can evaluate one technique versus another.
So i found a solution, it might not be the smartest, but it works, and it's pretty came to mind after reading both Eric's answer and also reading the comment made by marcus, you could say that it's a combination of the two:
This is the new code:
foreach (ExtTerBody OtherObject in UniverseController.CurrentUniverse.ExterTerBodies.Where(x => x != this))
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R,2) * Time.DeltaTime;
float VRmod = (float)Math.Round(V/(R*0.001), 0, MidpointRounding.AwayFromZero);
if(V > R*0.01f)
{
for (int x = 0; x < VRmod; x++)
{
EulerMovement(OtherObject, Time.DeltaTime / VRmod);
}
}
else
EulerMovement(OtherObject, Time.DeltaTime);
}
public void EulerMovement(ExtTerBody OtherObject, float deltaTime)
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R, 2) * deltaTime;
Vector2 NonNormTwo = (OtherObject.Position - Position).Normalized() * V;
Vector2 NonNormDir = Velocity + NonNormTwo;
Velocity = NonNormDir;
//Debug.WriteLine("Velocity=" + Velocity);
Position += Velocity * deltaTime;
}
To explain it:
I came to the conclusion that if the problem was that the satellite had too much velocity in one frame, then why not seperate it into multiple frames? So this is what "it" does now.
When the velocity of the satellite is more than 1% of the current radius, it seperates the calculation into multiple bites, making it more precise.. This will ofcourse lower the framerate when working with high velocities, but it's okay with a project like this.
Different solutions are still very welcome. I might tweak the trigger-amounts, but the most important thing is that it works, then i can worry about making it more smooth!
Thank's everybody that took a look, and everyone who helped be find the conclusion myself! :) It's awesome that people can help like this!

Optimising movement on hex grid

I am making a turn based hex-grid game. The player selects units and moves them across the hex grid. Each tile in the grid is of a particular terrain type (eg desert, hills, mountains, etc) and each unit type has different abilities when it comes to moving over the terrain (e.g. some can move over mountains easily, some with difficulty and some not at all).
Each unit has a movement value and each tile takes a certain amount of movement based on its terrain type and the unit type. E.g it costs a tank 1 to move over desert, 4 over swamp and cant move at all over mountains. Where as a flying unit moves over everything at a cost of 1.
The issue I have is that when a unit is selected, I want to highlight an area around it showing where it can move, this means working out all the possible paths through the surrounding hexes, how much movement each path will take and lighting up the tiles based on that information.
I got this working with a recursive function and found it took too long to calculate, I moved the function into a thread so that it didn't block the game but still it takes around 2 seconds for the thread to calculate the moveable area for a unit with a move of 8.
Its over a million recursions which obviously is problematic.
I'm wondering if anyone has an clever ideas on how I can optimize this problem.
Here's the recursive function I'm currently using (its C# btw):
private void CalcMoveGridRecursive(int nCenterIndex, int nMoveRemaining)
{
//List of the 6 tiles adjacent to the center tile
int[] anAdjacentTiles = m_ThreadData.m_aHexData[nCenterIndex].m_anAdjacentTiles;
foreach(int tileIndex in anAdjacentTiles)
{
//make sure this adjacent tile exists
if(tileIndex == -1)
continue;
//How much would it cost the unit to move onto this adjacent tile
int nMoveCost = m_ThreadData.m_anTerrainMoveCost[(int)m_ThreadData.m_aHexData[tileIndex].m_eTileType];
if(nMoveCost != -1 && nMoveCost <= nMoveRemaining)
{
//Make sure the adjacent tile isnt already in our list.
if(!m_ThreadData.m_lPassableTiles.Contains(tileIndex))
m_ThreadData.m_lPassableTiles.Add(tileIndex);
//Now check the 6 tiles surrounding the adjacent tile we just checked (it becomes the new center).
CalcMoveGridRecursive(tileIndex, nMoveRemaining - nMoveCost);
}
}
}
At the end of the recursion, m_lPassableTiles contains a list of the indexes of all the tiles that the unit can possibly reach and they are made to glow.
This all works, it just takes too long. Does anyone know a better approach to this?
As you know, with recursive functions you want to make the problem as simple as possible. This still looks like it's trying to bite off too much at once. A couple thoughts:
Try using a HashSet structure to store m_lPassableTiles? You could avoid that Contains condition this way, which is generally an expensive operation.
I haven't tested the logic of this in my head too thoroughly, but could you set a base case before the foreach loop? Namely, that nMoveRemaining == 0?
Without knowing how your program is designed internally, I would expect m_anAdjacentTiles to contain only existing tiles anyway, so you could eliminate that check (tileIndex == -1). Not a huge performance boost, but makes your code simpler.
By the way, I think games which do this, like Civilization V, only calculate movement costs as the user suggests intention to move the unit to a certain spot. In other words, you choose a tile, and it shows how many moves it will take. This is a much more efficient operation.
Of course, when you move a unit, surrounding land is revealed -- but I think it only reveals land as far as the unit can move in one "turn," then more is revealed as it moves. If you choose to move several turns into unknown territory, you better watch it carefully or take it one turn at a time. :)
(Later...)
... wait, a million recursions? Yeah, I suppose that's the right math: 6^8 (8 being the movements available) -- but is your grid really that large? 1000x1000? How many tiles away can that unit actually traverse? Maybe 4 or 5 on average in any given direction, assuming different terrain types?
Correct me if I'm wrong (as I don't know your underlying design), but I think there's some overlap going on... major overlap. It's checking adjacent tiles of adjacent tiles already checked. I think the only thing saving you from infinite recursion is checking the moves remaining.
When a tile is added to m_lPassableTiles, remove it from any list of adjacent tiles received into your function. You're kind of doing something similar in your line with Contains... what if you annexed that if statement to include your recursive call? That should cut your recursive calls down from a million+ to... thousands at most, I imagine.
Thanks for the input everyone. I solved this by replacing the Recursive function with Dijkstra's Algorithm and it works perfectly.

Categories

Resources