I am simulating a fast food restaurant over three hours. The three hours are divided into 18 intervals of 600 seconds each. Each interval outputs statistics about what happened on those 600 seconds.
My original structure was like this:
int i;
for (i=0; i<18; i++)
interval(customerArrive);
int interval(double customerArrive)
...
...
int t;
for (t=0;t<600;t++)
This method of two (for loops) doesn't work because it doesn't allow time to be a continuous function. If an event happens (as in, a customer arrives) in the first interval at t=599, then this event will not exist at t=601 because everything is erased as the second interval begins.
The way I want to approach this is to make a while loop to allow time to be a continuous function, I just don't know how to 'convert' my code to this.
Would it be something like this?
while (t<10800)
{
...
}
I'm not sure what the condition needs to be for this while loop to exit.
If necessary, here is my full code: http://pastebin.com/3ec0Ks9u
"May be",i understood your problem.If you want something to be monitored (continuous function in your words),u need to take help of threads and timers,which is out of your scope for now.If you want to use something basic,the question is not well understood,please re-construct it.
[…] everything is erased as the second interval begins.
That's not due to the two for loops, but instead due to the fact that the outer for loop calls a function, and you reinitialize stuff in that function. So move that outer for loop into the function interval (probably changing the method name along the way, as it no longer fits). In that method you can write
int i, t;
… // initialize stuff
for (i=0; i<18; i++) {
for (t=0;t<600;t++) {
… // do stuff
}
}
Those loops won't erase anything, and you won't have to compute the values of i and t from some single counter.
allow time to be a continuous function
Obviously, time will still be discretized in those steps. As it would in your while loop. If you dont want discrete time steps, you'll have to radically change your code, e.g. by computing the times when customers arrive up front, and then stepping from event to event instead of in fixed increments.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I'm trying to create a timer to display in the top right hand corner of a game that counts from 99% down to 0% with 1% being dropped every second and the counter refreshing on the screen. ps (i'm new to coding so sorry if this is a dumb question)
I've tried using a simple countdown loop but it decreases all at once, and doesn't save the counter as a variable, which i need so i can print it at a specific point on the screen
void battery_life(){
int w, h;
get_screen_size(&w, &h);
int y=99;
while (y !=0)
y--;
draw_int (2*w/3+5,h-h+2,y);
draw_char(2*w/3+7,h-h+2,'%');
}
I expect that when i run this counter it -1% every second but it just counts down all at once and displays 0%
It's a rather broad question, but here are several general approaches, which all need to:
Separate the game logic from rendering, and
Using a state machine for updating game state, instead of pausing the execution.
Here are two different approaches:
Game loop
Since you are designing a game, it's likely you will have a game loop of some sort, i.e.:
while (!ending)
{
process_input();
update_state();
draw();
}
And your update_state and draw functions should have different responsibilities, similar to:
static int current_percentage = 100;
void update_state(void)
{
// keep the time of last update
static timestamp last_update_time = 0;
// decrease 'current_percentage' when needed
timestamp now = get_current_game_time();
if (seconds_elapsed(now, last_update_time) >= 1)
{
last_update_time = now;
current_percentage--;
}
}
void draw(void)
{
// just handle the drawing
draw_percentage(current_percentage);
}
Multiple threads
On the other hand, if you are using multiple threads, you would likely end up with a rather different approach:
static atomic_int current_percentage = 100;
void decrease_percentage(void)
{
atomic_fetch_sub(¤t_percentage, 1);
}
void draw(void)
{
// just handle the drawing
int percentage = atomic_load(¤t_percentage);
draw_percentage(percentage);
}
// no game loop - we will need to configure function callbacks
// for different events
void on_game_start(void)
{
// one thread should update the timer
call_periodically(1000 /* period in ms */, decrease_percentage /* what to call */);
// this should run at max possible fps
call_when_idle(draw /* what to call when idle */);
}
The latter approach is slightly shorter, although the main reason for this is because a lot of functionality is hidden inside the functions which configure the callbacks. The former one is simpler to reason about and doesn't have issues which arise with multithreaded code (deadlocks, race conditions - note the use of the atomic_int to ensure atomic updates), which is why a game loop is preferred if possible.
If your game needs to utilize multiple cores, then you will need to involve some sort of threading, which comes with its additional complexity. The implementation of the second approach would also depend on your platform, since timers are not a part of the C standard.
Finally, if you are using a game engine/framework (libgdx, Unity), you will likely have to implement the update and draw callbacks only, with the framework taking care of calling these functions when needed.
A couple things:
Your while does nothing. If you don't put your code inside brackets, it only executes the next line in a loop.
You're not waiting for a second anywhere.
You should probably rethink your approach - if you fix the above problems, when you call the function everything else in your program will freeze for 99 seconds except for the battery text changing.
Maybe a better approach would be to write a function that has a static int y = 99, and each time you call it draw the battery text and decrease y by 1 (static more or less means the value is remembered between calls).
Then, in your main game loop, you can check if a second has passed, and if so, execute that function.
You are missing brackets from your while loop so it's not going to work for a start!
You really need to implement a timer so that you can actually tell when a second has passed as your code could vary in operation speed, and definitely will when you make any changes.
How you do this is totally up to the system you are writing on and you haven't given enough information for us to help you.
Most often hardware running C has hardware timers and specific registers you need to target.
If you are using unity, You can simply use a coroutine to countdown percentage per seconds.
void countDown()
{
int percent = 99;
StartCoroutine(CountDownToZero(percent));
}
IEnumerator CountDownToZero(int percentage)
{
WaitForSeconds wait1sec = new WaitForSeconds(1f);
while(percentage > 0)
{
percentText.text = percentage.ToString()+"%";
yield return wait1sec;
percentage= percentage- 1;
}
percentText.text = "0%";
}
In case of other engines, they also provide scheduler to schedule the execution of functions.
In my project, have a data provider, which provides data in every 2 milli seconds. Following is the delegate method in which the data is getting.
func measurementUpdated(_ measurement: Double) {
measurements.append(measurement)
guard measurements.count >= 300 else { return }
ecgView.measurements = Array(measurements.suffix(300))
DispatchQueue.main.async {
self.ecgView.setNeedsDisplay()
}
guard measurements.count >= 50000 else { return }
let olderMeasurementsPrefix = measurements.count - 50000
measurements = Array(measurements.dropFirst(olderMeasurementsPrefix))
print("Measurement Count : \(measurements.count)")
}
What I am trying to do is that when the array has more than 50000 elements, to delete the older measurement in the first n index of Array, for which I am using the dropFirst method of Array.
But, I am getting a crash with the following message:
Fatal error: Can't form Range with upperBound < lowerBound
I think the issue due to threading, both appending and deletion might happen at the same time, since the delegate is firing in a time interval of 2 millisecond. Can you suggest me an optimized way to resolve this issue?
So to really fix this, we need to first address two of your claims:
1) You said, in effect, that measurementUpdated() would be called on the main thread (for you said both append and dropFirst would be called on main thread. You also said several times that measurementUpdated() would be called every 2ms. You do not want to be calling a method every 2ms on the main thread. You'll pile up quite a lot of them very quickly, and get many delays in their updating, as the main thread is going to have UI stuff to be doing, and that always eats up time.
So first rule: measurementUpdated() should always be called on another thread. Keep it the same thread, though.
Second rule: The entire code path from whatever collects the data to when measurementUpdated() is called must also be on a non-main thread. It can be on the thread that measurementUpdated(), but doesn't have to be.
Third rule: You do not need your UI graph to update every 2ms. The human eye cannot perceive UI change that's faster than about 150ms. Also, the device's main thread will get totally bogged down trying to re-render as frequently as every 2ms. I bet your graph UI can't even render a single pass at 2ms! So let's give your main thread a break, by only updating the graph every, say, 150ms. Measure the current time in MS and compare against the last time you updated the graph from this routine.
Fourth rule: don't change any array (or any object) in two different threads without doing a mutex lock, as they'll sometimes collide (one thread will be trying to do an operation on it while another is too). An excellent article that covers all the current swift ways of doing mutex locks is Matt Gallagher's Mutexes and closure capture in Swift. It's a great read, and has both simple and advanced solutions and their tradeoffs.
One other suggestion: You're allocating or reallocating a few arrays every 2ms. It's unnecessary, and adds undue stress on the memory pools under the hood, I'd think. I suggest not doing append and dropsFirst calls. Try rewriting such that you have a single array that holds 50,000 doubles, and never changes size. Simply change values in the array, and keep 2 indexes so that you always know where the "start" and the "end" of the data set is within the array. i.e. pretend the next array element after the last is the first array element (pretend the array loops around to the front). Then you're not churning memory at all, and it'll operate much quicker too. You can surely find Array extensions people have written to make this trivial to use. Every 150ms you can copy the data into a second pre-allocated array in the correct order for your graph UI to consume, or just pass the two indexes to your graph UI if you own your graph UI and can adjust it to accommodate.
I don't have time right now to write a code example that covers all of this (maybe someone else does), but I'll try to revisit this tomorrow. It'd actually be a lot better for you if you made a renewed stab at it yourself, and then ask us a new question (on a new StackOverflow) if you get stuck.
Update As #Smartcat correctly pointed this solution has the potential of causing memory issues if the main thread is not fast enough to consume the arrays in the same pace the worker thread produces them.
The problem seems to be caused by ecgView's measurements property: you are writing to it on the thread receiving the data, while the view tries to read from it on the main thread, and simultaneous accesses to the same data from multiple thread is (unfortunately) likely to generate race conditions.
In conclusion, you need to make sure that both reads and writes happen on the same thread, and can easily be achieved my moving the setter call within the async dispatch:
let ecgViewMeasurements = Array(measurements.suffix(300))
DispatchQueue.main.async {
self.ecgView.measurements = ecgViewMeasurements
self.ecgView.setNeedsDisplay()
}
According to what you say, I will assume the delegate is calling the measuramentUpdate method from a concurrent thread.
If that's the case, and the problem is really related to threading, this should fix your problem:
func measurementUpdated(_ measurement: Double) {
DispatchQueue(label: "MySerialQueue").async {
measurements.append(measurement)
guard measurements.count >= 300 else { return }
ecgView.measurements = Array(measurements.suffix(300))
DispatchQueue.main.async {
self.ecgView.setNeedsDisplay()
}
guard measurements.count >= 50000 else { return }
let olderMeasurementsPrefix = measurements.count - 50000
measurements = Array(measurements.dropFirst(olderMeasurementsPrefix))
print("Measurement Count : \(measurements.count)")
}
}
This will put the code in an serial queue. This way you can ensure that this block of code will run only one at a time.
I have a function that computes the Minimum Spanning Tree of a graph, and I have two different ways to compute the edge weights in the tree.
The edge_weight() function is called inside a few for loops over and over, and which function is used depends on the type of tree, which is specified outside of the main function (by the user).
My problem is that everything inside the for loops besides the edge_weight() function is identical, so I don't want to copy/paste code.
But at the same time I don't want to condition inside the for loops on which edge_weight() function to use, in order to avoid the overhead of a repeated if condition.
So what's the cleanest way to specify which function to use before the for loops start without copy/pasting the same code?
Can I have pointers to functions (does that slow the code down, though?)?
Can I put functions in variables, arrays?
EDIT: Speed is crucial for this application, hence my trying to avoid conditioning inside the for loops.
Here's some pseudo-code:
while(nodes < threshold)
{
for (int i = 0; i < K; i++)
{
if (nodes[i] == something)
{
weight = one_of_two_edge_weight_functions();
I'm creating a card game in pygame for my college project, and a large aspect of the game is how the game's AI reacts to the current situation. I have a function to randomly generate a number within 2 parameters, and this is how long I want the program to wait.
All of the code on my ai is contained within an if statement, and once called I want the program to wait generated amount of time, and then make it's decision on what to do.
Originally I had:
pygame.time.delay(calcAISpeed(AIspeed))
This would work well, if it didn't pause the rest of the program whilst the AI is waiting, stopping the user from interacting with the program. This means I cannot use while loops to create my timer either.
What is the best way to work around this without going into multi-threading or other complex solutions? My project is due in soon and I don't want to make massive changes. I've tried using pygame.time.Clock functions to compare the current time to the generated one, but resetting the clock once the operation has been performed has proved troublesome.
Thanks for the help and I look forward to your input.
The easiest way around this would be to have a variable within your AI called something like "wait" and set it to a random number (of course it will have to be tweaked to your program speed... I'll explain in the code below.). Then in your update function have a conditional that waits to see if that wait number is zero or below, and if not subtract a certain amount of time from it. Below is a basic set of code to explain this...
class AI(object):
def __init__(self):
#put the stuff you want in your ai in here
self.currentwait = 100
#^^^ All you need is this variable defined somewhere
#If you want a static number as your wait time add this variable
self.wait = 100 #Your number here
def updateAI(self):
#If the wait number is less than zero then do stuff
if self.currentwait <= 0:
#Do your AI stuff here
else:
#Based on your game's tick speed and how long you want
#your AI to wait you can change the amount removed from
#your "current wait" variable
self.currentwait -= 100 #Your number here
To give you an idea of what is going on above, you have a variable called currentwait. This variable describes the time left the program has to wait. If this number is greater than 0, there is still time to wait, so nothing will get executed. However, time will be subtracted from this variable so every tick there is less time to wait. You can control this rate by using the clock tick rate. For example, if you clock rate is set to 60, then you can make the program wait 1 second by setting currentwait to 60 and taking 1 off every tick until the number reaches zero.
Like I said this is very basic so you will probably have to change it to fit your program slightly, but it should do the trick. Hope this helps you and good luck with your project :)
The other option is to create a timer event on the event queue and listen for it in the event loop: How can I detect if the user has double-clicked in pygame?
I'm using Google Docs Spreadsheet API to keep track of a competition between some of my friends. I have some big ideas, but I'm stumped right now. I'm trying to create 20 different arrays inside of loops (see below) and then evaluate each one outside of the loop, and I really don't want to write 20 "if...then" statements.
NOTE: the following SUMMARY may or may not help you answer my question. You might want to skip down to the code, then read this if you need it :)
Summary of the program: Each player assigns point values in favor of one possible outcome of a set of binary-outcome events. As the events happen, players either gain the points assigned if their outcome occurs, or gain no points if the opposite outcome occurs. My goal is to 1) figure out exactly when a player is eliminated, and 2) highlight all remaining events that must be won for them to have a chance at tying for first.
Instead of trying to somehow evaluate all possibilities (5 players picking, 2^16 outcomes... I have zero computer science knowledge, but this seems like an incredibly huge task even for the modern computer) I've come up with an alternate idea. The script loops through each player, against each other opponent. It calculates the maximum number of points a player can score based on their value assignments and the already determined game. For one player and one opponent, it checks the best possible outcome by the player against that opponent, and if there is any opponent he cannot beat, even in the best case, then he is eliminated.
This part is easy-- after the loop runs inside the loop, I just adjust a global variable that I created earlier, and when the outer loop is done, just grab those variables and write them to the sheet.
Unfortunately, this misses the case of where he could have a best case against each individual opponent, but not against multiple opponents at once.
So the next step is what I'm trying to do now. I'm not even sure I can give a good explanation without just showing you the entire spreadsheet w/script, but I'll try. So what I want to do now is calculate the "value" of each event for each player against a given other player. If both player and opponent assigned points in favor of the same event outcome for one event, the event's value is the difference between the picks (positive if player picked higher, negative if lower), and it's the SUM if they picked opposite event outcomes. Now, I do the same thing as before-- take a best-case scenario for a player against a given opponent-- but now I check by how much the player can beat the opponent in a best-case scenario. Then I evaluate the (absolute value of the) event value against this difference, and if it's greater, then the event is a must win (or must lose if the event value is negative). And, if an event is both a "must-win" and a "must lose" event, then the player is eliminated.
The problem is that this second step requires me to create a new array of values for each player-opponent combination, and then do things with the values after they're created.
I realize one approach would be to create 20 different arrays, and throughout the entire loops, keep checking "if (player == "1" && opponent == 2){}" and populate the arrays accordingly, but this seems kind of ridiculous. And more importantly, this entire project is my attempt at learning javascript, so what's the point in using a time-intensive workaround that doesn't teach me anything new?
I'm trying to understand square bracket notation, since it seems to be the answer to my question, but a lot of people are also suggesting that it's impossible to create variable names by concatenating with the value of another variable... so anyway, here's what I'm trying. I'd really appreciate either a fix to my approach, or a better approach.
for (var player=1; player<6; player++){
if(player==1){look up certain columns in the spreadsheet and save them to variables}
//ditto for other players
for(var opponent=1; opponent<6; opponent++){
if(player!=opponent){
if(opponent==1){save more values to variables}
//ditto for other players
for(var row=9; row<24; row++) {
//Now the script goes down each row of an array containing the original
//spreadsheet info, and, based on information determined by the variables
//created above, get values corresponding to the player and opponent.
//So what I'd like to do here is create "array[1,2]==" and then "array[1,3]=="
//and so forth, creating them globally (I think I understand that term by now)
//so I can refer to them outside of the loops later to do some evaluatin'.
}
}}
//get array[1,2]...array[5,4] and do some operations with them.
Thanks for getting through this little novel... really looking forward to your advice and ideas!
How can I create arrays within a loop (within another loop)?
Code update 2
As you said: "i am trying to understand square bracket notation" You may take a look at my new demo and the code:
function getTeam(){
var array = [[1,2,3],[4,5,6],[7,8,9]]; // arrays within arrays
// array myTeam
var myTeam = [[],[],[],[]];
var playerNames = ["John", "Bert", "Dave", "Milton"];
var ages =[];
var weight = 104;
// loop over the team arrayadd each player (name, age and weight) to the team
for (i=0; i < myTeam.length; i++){
// fill the age array in a loop
for (j=0;j<myTeam.length;j++) {
ages[j] = 23 + j;
}
myTeam[i].push([playerNames[i], ages[i], weight]);
}
return myTeam;
}
And pass them back out in Javascript
Could you elaborate on this part?
Update
var valuesOfPlayers=[];
for (var player=1; player<6; player++){
// look up certain columns in the spreadsheet and save them to variables
// you could call a funcntion and return the values you
// collected in an array within an array as in the demo above
valuesOfPlayers[player] = lookupColumnValues(player);
for(var opponent=1; opponent<6; opponent++){
if(player!=opponent){
// save more values to variables
valuesOfPlayers[player] = addValuesToVar(player);
}
for(var row=9; row<24; row++) {
// if you collect the values in your first and second if clause
// what other information do you want to collect
// Please elaborate this part?
}
}}
One workaround:
I could create an array before the execution of the loops.
At the start of each loop, I could push a string literal to the array containing the value of player and opponent.
After the loops are done, I could split the array into multiple arrays, or just evaluate them in one big array using regular expressions.
I'd still rather create new arrays each time-- seems like it is a more universal way of doing this, and learning how would be more educational for me than using this workaround.