How to track the leader of a 2D racing game - algorithm

I'm working on a top-down racing game and I want to know which car is the leader.
My checkpoints are colliders spread along the road.
In the example, there are 5 checkpoints (let's call them c0, ..., c4). 3 laps must be completed for the race to end.
My current algorithm creates an array like this
[c0, c1, c2, c3, c4, c0, c1, c2, c3, c4, c0, c1, c2, c3, c4, c0]
for each car. Each car keeps an index of where it is at the moment and this index is updated when the car touches a checkpoint.
The problem is that if some cars have the same index, the game doesn't know which one is the leader. Is there a better approach to track the leader than mine?

A very very simple way is creating "progress image" beforehand.
Here, "progress image" is a enough resolution image data whose pixels has progress value.
To estimate the progress of car, simply ectract the value from this image.

Instead of only keeping track of the checkpoint index you could rather store current lap, checkpoint and additionally the timestamp of when those checkpoints were reached directly in the car itself like e.g.
public class Car : MonoBehaviour
{
public int Lap;
public int Checkpoint;
public float LastCheckpointTime;
}
This way if you have an array
Car[] cars;
you could order them using Linq like e.g.
var orderedCars = cars.OrderBy(c => c.Lap)
.ThenBy(c => c.Checkpoint)
.ThenBy(c => c.LastCheckpointTime)
.ToList();
Then you only need to update those indices and time accordingly using e.g. Time.time whenever a car touches your checkpoint or lap trigger and refresh the ranking. I would then place some more of those triggers to have more precision.
This way you can also add additional fields and checks like e.g. only increasing lap and checkpoint if they have been passed in the correct order to avoid skipping or going backwards through the lap line multiple times ;)

Just keep for each car the time stamp when last checkpoint was reached, to decide between 2 identical indexes (as proposed by derHugo).
The checkpoints allow you to control that cars didn't use shortcuts.
To address the real position of a car located between 2 checkpoints :
Define the track as a polyline at the center of the road, starting from point O located on beginning of lap,
For one car, find the point P of the track located at smallest distance between the car and the track,
Compute the distance OP along the Poly line.

Related

Finding optimal swapping paths in employees moving to different cities

We have a problem where we want to find the optimal path for swapping employees' locations across the country.
Hypothetically, a company allows for employees to request to move to another city only if a vacancy is available in that city, and also if someone is willing to take their soon-to-be vacant position. Examine the example:
Employee A who currently works in Los Angeles wants to move to Boston.
Employee B who currently works in Boston wants to move to New York.
Employee C who currently works in New York wants to move to Los Angeles.
In the above triangle, we can grant all three employees the permission to do the move, since there won't be any vacancies once they move. But the situation gets more complex when:
Multiple employees are competing for the same location. We can solve this with a hypothetical score of some sort, like more years working for the company gets the priority.
We have more cities to consider. (in the hundreds)
We have more employees to consider. (in the hundreds of thousands)
Ultimately the goal is to grant the highest number of move permissions without leading to any vacancies in the system.
We're currently exploring the idea of simulating all the swapping paths, and then selecting the one that generates the highest number of moves.
But I feel that this problem existed in the wild before, I just don't know what keywords to look for in order to get more insights. Any ideas? What algorithms should we look into?
Remove the impossible move requests, like this
A,B are specific cities. n is amy city
RAB is a request to move from A to B
RAn is a request to move from A
RnA is a reuest to move to A
CAn is the number of requests to move from A
CnA is the number of requests to move to A
set flag TRUE
WHILE ( flag == TRUE )
set flag = FALSE
LOOP A over all cities
IF CAn > CnA then not all RAn can be permitted.
Remove lower scoring requests until CAn == CnA.
set flag TRUE
Once these "impossible" moves are removed, all of the remaining move requests are "in-balance". That is, all of the move requests to a city are equal all of those from a city. From that point on it no longer matters which cycles you choose to implement: once you implement them, the remainings requests are still all in-balance. And no matter which move-cycle and which order they are implemented in, it stays in-balance until all remaining requests are zero, and the total number of moves will be exactly the same no matter how they are implemented. ( This explanation is due to https://stackoverflow.com/users/109122/rbarryyoung )
Here is C++ code implementing this
void removeForbidden()
{
bool flag = true;
while (flag)
{
flag = false;
for (auto &city : sCity)
{
auto vFrom = RequestCountFrom(city);
auto vTo = RequestCountTo(city);
if (vFrom.size() > vTo.size())
{
for (int k = vTo.size(); k < vFrom.size(); k++)
{
vFrom[k]->allowed = false;
}
flag = true;
}
}
}
std::cout << "Permitted moves:\n";
for (auto &R : vRequest)
{
if (R.allowed)
std::cout << R.text();
}
}
The complete application code is at https://gist.github.com/JamesBremner/5f49beaca59a7a7043e356fbb35f0d09
The input is a space delimited text file with 4 columns: employee name, employee score, from city, to city
Here is sample input based on your example but adding another request that cannot be permitted
e1 1 a b
e2 1 b c
e3 1 c a
e4 0 a c
The output from this is
Permitted moves:
e1 1 a b
e2 1 b c
e3 1 c a
Note: I have not implemented the scoring. For simplicity I assume that move requests are entered in order of descending score. So, the requests that are dropped when necessary, change according to the order you enter them. I assume you will be able to implement whatever scoring system you require. Also note that, unless you calculate a unique score for every request from a city, then which requests are denied may vary with the order of input.
I was about to post this in a comment but it was more than the the actually allowed characters.
I'm not sure about existing advanced algorithms that could potentially solve this problem, but you can custom fit some fundamental ones:
An employee wanting to move from city1 to some city2 is a directed edge from city1 to city2. Make sure that if 2 employees want to move from A to B, you add 2 directed edges for that or somehow keep count of the quantity.
Find disjoint components of the graph.
In each disjoint component, find the largest possible circle. A circle means A -> B -> C -> A.
Remove those edges and keep count of the number of successful swaps.
Rpeat until there are no circles in any of the disjoint components.
This is a greedy algorithm. At the moment I'm still not quite sure if it would produce the optimal solution in each and every situation. Any input is appreciated.

Relational Learning: What does this Prolog Output say?

I need to find relations in a prolog dataset. I have different kinds of trains with different features, for example Train1:
has_car(rel_east1,car_11).
has_car(rel_east1,car_12).
has_car(rel_east1,car_13).
infront(car_11,car_12).
infront(car_12,car_13).
size(car_11,long).
size(car_12,long).
size(car_13,short).
shape(car_11,hexagon).
shape(car_12,rectangle).
shape(car_13,hexagon).
load(car_11,rectangle).
load(car_12,circle).
load(car_13,triangle).
I have ten different trains. Now I used the Metagol algorithm which shall learn the different relations within the different trains. As a result I get a list with different clauses. And here is my problem: I don't understand the inductive steps in between the clauses. For example:
relational(A):-has_car(A,B),relational_1(B).
relational_1(A):-relational_2(A,rectangle).
relational_2(A,B):-relational_3(A),shape(A,B).
relational_3(A):-infront(A,B),relational_4(B).
relational_4(A):-load(A,triangle).
The only thing I know is, that the whole clause says: "There is a Train which contains a car which is in the shape rectangle. This car is in front of another car which contains a triangle."
But can anybody explain the code to me? Line for line?
For example, I don't understand how to read the 2nd line: "If there is a relation 1 with A, then there is also a relation 2 between A and rectangle"?
I am not 100% sure, but I think the relational_x predicates, are relations (predicates) that are 'invented' by metagol for your learning task.
As naming invented predicates is a hard task (for which there is not a good solution for ) you get these type of names.
For instance if you used the example `kinship1' here : https://github.com/metagol/metagol
?- [kinship1].
Warning: /media/sam/9bb6ab40-5f17-481e-aba8-7bd9e4e05d66/home/sam/Documents/Prolog_practise/metagol/metagol.pl:250:
Local definition of metagol:list_to_set/2 overrides weak import from lists
true.
?- a.
% learning grandparent/2
% clauses: 1
% clauses: 2
% clauses: 3
grandparent_1(A,B):-father(A,B).
grandparent_1(A,B):-mother(A,B).
grandparent(A,B):-grandparent_1(A,C),grandparent_1(C,B).
true .
It learns the grandparent/2 relation by also learning grandparent_1/2. Which we as humans would call parent/2.
So relational_4(A):-load(A,triangle). you might call 'car carrying a load which is triangle shaped' . and relational_3(A):-infront(A,B),relational_4(B). would then be 'car in front of a car carrying a load which is triangle shaped' etc
relational_4(A):-load(A,triangle).
If an object A is loaded with a triangle then A is relational_4
or
There is a car which has a load which is a triangle.
relational_3(A):-infront(A,B),relational_4(B).
If an object A is infront of object B and B is relational_4 then A is relational_3
or
Car A is infront of a car B which has a load which is a triangle
relational_2(A,B):-relational_3(A),shape(A,B).
If A is relational_3 and has shape B then A relational_2 B.
or
Car A is a car infront of another car which is loaded with a triangle, car A has an unspecified shape.
relational_1(A):-relational_2(A,rectangle).
If an object A is relational_2 rectangle then A is relational_1
or
There is a car which has a rectangle shape, it is infront of a car which caries a triangle load.
relational(A):-has_car(A,B),relational_1(B).
If an object A has a car B and B is relational_1 then relational A.
There is a train which has a car, that car is a rectangle in shape and it is infront of a car that has a triangle load

In prolog how do you represent state transitions and actions performed by objects?

I have a problem domain consisting of several city state nodes and paths indicating the cost association between places/cities, also the agent is a chopper which can fly from one city to the next. The scenario problem is for a chopper to take off from one city and land at another. I know how to implement city states and transitions ok without operations such as takeoff, land etc..., I am just not sure how you represent the agent operations in terms of states or data structures, in order to satisfy an outcome effect such as:- chopper_islanded(true), chopper_at(cityj).
% nodes
place(rescueship).
place(citya).
place(cityb).
place(cityc).
place(cityd).
place(citye).
place(cityf).
place(cityg).
place(cityh).
place(cityi).
place(cityj).
% objects
is_chopper(chopper1).
% connections
path(rescueship, citya, 100).
path(rescueship, cityc, 200).
path(rescueship, cityb, 150).
path(cityc, cityd, 110).
path(cityd, citye, 140).
path(cityd, cityf, 100).
path(citya, cityi, 70).
path(cityi, cityg, 130).
path(cityb, cityg, 90).
path(cityi, cityf, 50).
path(citye, cityf, 90).
path(citye, cityj, 50).
path(cityh, cityj, 90).
path(cityi, cityh, 70).
path(citya,cityc,120).
path(citya,cityb,60).
% chopper attributes
chopper_islanded(true).
chopper_islanded(false).
chopper_at(X):- chopper_islanded(true); chopper_islanded(false), place(X), is_chopper(chopper1).
% place states, G=on ground, A= in air, v[list of conditions],Ch = chopper
state(v([G,A],P,Ch)):- chopper_islanded(G), chopper_islanded(A), place(P), chopper_at(Ch).
% chopper operations
%takeOff(V1,V2):- place(V1), place(V2).
%takeOff(v([_,A,P),v([false,A],P)).
%land(chopper):- chopper_islanded(false).
%flyto(p1,p2) :- path(p1,p2,_), chopper_islanded(false).
% tried many attempts to implement operations but couldn't understand how to represent an action
connected(P1,P2,C):- path(P1,P2,C) ; path(P2,P1,C).
transition(S1,S2,C) :- connected(S1,S2,C).
initial(rescueship).
goal(cityj).
% breadth first search uses an initialised state and a goal state which has been omitted for clarity.
bfgs(P)
To solve the route I use a breadth first search algorithm which works ok without any chopper operations, it finds the quickest route approximately and returns the list of travelled nodes. My biggest issue is how does one represent actions that the chopper does in order to achieve a certain state, and what data structure is best to use for this? sorry if the code is a mess! I have been stumped trying to figure out the semantics, so I haven't omitted my mistakes to demonstrate to others that I have tried at least.
Think in terms of relations between actions and states.
First describe what an action in a specific state of the chopper leads to. For example:
action_state0_state(take_off, landed, flying).
action_state0_state(land, flying, landed).
action_state0_state(crash, flying, crashed).
action_state0_state(repair, crashed, landed).
Using just these simple definitions, you can already reason about a list of actions and the eventual state of the chopper that starts - for example - in landed position:
?- length(As, _), foldl(action_state0_state, As, landed, S).
As = [],
S = landed
As = [take_off],
S = flying
As = [take_off, land],
S = landed
As = [take_off, crash],
S = crashed
As = [take_off, land, take_off],
S = flying
As = [take_off, crash, repair],
S = landed .
A list of actions seems an appropriate data structure in this case, since the empty list makes sense, the number of elements is not known in advance etc.

Algorithm to create unique random concatenation of items

I'm thinking about an algorithm that will create X most unique concatenations of Y parts, where each part can be one of several items. For example 3 parts:
part #1: 0,1,2
part #2: a,b,c
part #3: x,y,z
And the (random, one case of some possibilities) result of 5 concatenations:
0ax
1by
2cz
0bz (note that '0by' would be "less unique " than '0bz' because 'by' already was)
2ay (note that 'a' didn't after '2' jet, and 'y' didn't after 'a' jet)
Simple BAD results for next concatenation:
1cy ('c' wasn't after 1, 'y' wasn't after 'c', BUT '1'-'y' already was as first-last
Simple GOOD next result would be:
0cy ('c' wasn't after '0', 'y' wasn't after 'c', and '0'-'y' wasn't as first-last part)
1az
1cx
I know that this solution limit possible results, but when all full unique possibilities will gone, algorithm should continue and try to keep most avaible uniqueness (repeating as few as possible).
Consider real example:
Boy/Girl/Martin
bought/stole/get
bottle/milk/water
And I want results like:
Boy get milk
Martin stole bottle
Girl bought water
Boy bought bottle (not water, because of 'bought+water' and not milk, because of 'Boy+milk')
Maybe start with a tree of all combinations, but how to select most unique trees first?
Edit: According to this sample data, we can see, that creation of fully unique results for 4 words * 3 possibilities, provide us only 3 results:
Martin stole a bootle
Boy bought an milk
He get hard water
But, there can be more results requested. So, 4. result should be most-available-uniqueness like Martin bought hard milk, not Martin stole a water
Edit: Some start for a solution ?
Imagine each part as a barrel, wich can be rotated, and last item goes as first when rotates down, first goes as last when rotating up. Now, set barells like this:
Martin|stole |a |bootle
Boy |bought|an |milk
He |get |hard|water
Now, write sentences as We see, and rotate first barell UP once, second twice, third three and so on. We get sentences (note that third barell did one full rotation):
Boy |get |a |milk
He |stole |an |water
Martin|bought|hard|bootle
And we get next solutions. We can do process one more time to get more solutions:
He |bought|a |water
Martin|get |an |bootle
Boy |stole |hard|milk
The problem is that first barrel will be connected with last, because rotating parallel.
I'm wondering if that will be more uniqe if i rotate last barrel one more time in last solution (but the i provide other connections like an-water - but this will be repeated only 2 times, not 3 times like now). Don't know that "barrels" are good way ofthinking here.
I think that we should first found a definition for uniqueness
For example, what is changing uniqueness to drop ? If we use word that was already used ? Do repeating 2 words close to each other is less uniqe that repeating a word in some gap of other words ? So, this problem can be subjective.
But I think that in lot of sequences, each word should be used similar times (like selecting word randomly and removing from a set, and after getting all words refresh all options that they can be obtained next time) - this is easy to do.
But, even if we get each words similar number od times, we should do something to do-not-repeat-connections between words. I think, that more uniqe is repeating words far from each other, not next to each other.
Anytime you need a new concatenation, just generate a completely random one, calculate it's fitness, and then either accept that concatenation or reject it (probabilistically, that is).
const C = 1.0
function CreateGoodConcatenation()
{
for (rejectionCount = 0; ; rejectionCount++)
{
candidate = CreateRandomConcatination()
fitness = CalculateFitness(candidate) // returns 0 < fitness <= 1
r = GetRand(zero to one)
adjusted_r = Math.pow(r, C * rejectionCount + 1) // bias toward acceptability as rejectionCount increases
if (adjusted_r < fitness)
{
return candidate
}
}
}
CalculateFitness should never return zero. If it does, you might find yourself in an infinite loop.
As you increase C, less ideal concatenations are accepted more readily.
As you decrease C, you face increased iterations for each call to CreateGoodConcatenation (plus less entropy in the result)

Seeking an algorithm to efficiently layout calendar event banners

I'm looking for an algorithm to efficiently place all-day/multi-day event banners, much like the month view in Outlook or Google Calendar. I have a number of events with a begin and end date, ordered by increasing begin (and then end) date (or any other order you please, I'm gathering events from a database table). I would like to minimize the average amount of vertical space used up, because after the event banners I will need to place other events just for that day (these always come after the banners for a given date). So, for example, if I had two events, one 1/10-1/11 and one 1/11-1/15, I would prefer to arrange them like so (each column is a single day):
bbbbb
aa
and not like:
aa
bbbbb
because when I add the events just for the day (x, y, and z), I can do this (I would prefer the first, do not want the second):
bbbbb vs. aa
aa xyz bbbbb
xyz
But it isn't as simple as placing the longer events first, because with 1/10-1/11, 1/13-1/14, and 1/11-1/13, I would want:
aa cc
bbb
as opposed to:
bbb
aa cc
because this would allow for events x and y:
aa cc vs. bbb
xbbby aa cc
x y
And of course I would prefer to do this in one pass. For the data structure, I'm currently using a map from date to list, where for each day of an event I add the event to the corresponding list. So a three-day event appears in three lists,each one under one of the days in the map. This is a convenient structure for transforming the result into visual output, but I'm open to other data structures as well. I'm currently using a greedy algorithm, where I just add each event in order, but that can produce unwanted artifacts like:
aa ccc
bbbbb
dd
eeeeeeeeeeeeeeeee
This wastes a lot of space for most of the "e" event days.
Any ideas?
Here is a high-level sketch of one possible solution (using day-of-week integers instead of full-blown dates). This interface:
public interface IEvent {
public abstract int getFirst(); // first day of event
public abstract int getLast(); // last day of event
public abstract int getLength(); // total number of days
public abstract char getLabel(); // one-char identifier
// true if this and that have NO days in common
public abstract boolean isCompatible(IEvent that);
// true if this is is compatible with all events
public abstract boolean isCompatibleWith(Collection<IEvent> events);
}
must be implemented to use the algorithm expressed in the layout method below.
In addition, the concrete class must implement Comparable to create a natural order where longer events precede shorter events. (My sample implementation for the demo below used an order of descending length, then ascending start date, then ascending label.)
The layout method takes a collection of IEvent instances and returns a Map that assigns to each row in the presentation the set of events that can be shown in that row.
public Map<Integer,Set<IEvent>> layout(Collection<IEvent> events) {
Set<IEvent> remainingEvents = new TreeSet<IEvent>(events);
Map<Integer,Set<IEvent>> result = new TreeMap<Integer,Set<IEvent>>();
int day = 0;
while (0 < remainingEvents.size()) {
Set<IEvent> dayEvents = new TreeSet<IEvent>();
for(IEvent e : remainingEvents) {
if (e.isCompatibleWith(dayEvents)) {
dayEvents.add(e);
}
}
remainingEvents.removeAll(dayEvents);
result.put(day, dayEvents);
++day;
}
return result;
}
Each row is composed by selecting the longest remaining event and progressively selecting all additional events (in the order described above) that are compatible with previously-selected events for the current row. The effect is that all events "float" upward as far as possible without collision.
The following demo shows the two scenarios in your question, along with a randomly-created set of events.
Event collection:
x(1):4
b(5):2..6
y(1):5
a(2):1..2
z(1):6
Result of layout:
0 -> {b(5):2..6}
1 -> {a(2):1..2, x(1):4, y(1):5, z(1):6}
Visual presentation:
bbbbb
aa xyz
Event collection:
x(1):1
b(3):2..4
a(2):1..2
c(2):4..5
y(1):5
Result of layout:
0 -> {b(3):2..4, x(1):1, y(1):5}
1 -> {a(2):1..2, c(2):4..5}
Visual presentation:
xbbby
aa cc
Event collection:
f(2):1..2
h(2):1..2
d(4):1..4
e(4):2..5
c(1):6
a(2):5..6
g(4):2..5
b(2):0..1
Result of layout:
0 -> {d(4):1..4, a(2):5..6}
1 -> {e(4):2..5, b(2):0..1, c(1):6}
2 -> {g(4):2..5}
3 -> {f(2):1..2}
4 -> {h(2):1..2}
Visual presentation:
ddddaa
bbeeeec
gggg
ff
hh
I think in a situation like this, you're much better off making sure your data is organized properly first and then rendering it. I know you want a single pass, but I think the results would be alot better.
For instance, organize the data into the lines you'll need to have for a given day and organize the events the best way possible, starting with the longest events (don't need to be displayed first, but they do need to be organized first) and moving down to the shortest events. This will allow you to render your output accordingly not wasting any space, and avoiding those "e" event days. Additionally, then:
bbb
aa cc
or
aa cc
bbb
won't matter because x and y can always go on either side of bbb or even between aa and cc
I hope you find this helpful.

Resources