### Trouble with Loops

I'm trying to make a constantly-updating analog clock display. Here's my code so far (excuse the messiness- I've been trying all kinds of permutations to fix this problem):

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111`` ``````#include "library.h" const double pi = acos(-1.0); void get_times() { int year = get_calendar_date() / 10000; int month = (get_calendar_date() / 100)%100; int day = (get_calendar_date() % 10000)%100; int hour = get_clock_time() / 10000; int minute = (get_clock_time() / 100)%100; int second = (get_clock_time() % 1000)%100; /*print("Year: "); print(year); new_line(); print("Month: "); print(month); new_line(); print("Day: "); print(day); new_line(); if(hour > 12) { print("Hour: "); print(hour-12); print(" P.M."); } else { print("Hour: "); print(hour); print(" A.M."); } new_line(); print("Minute: "); print(minute); new_line(); print("Second: "); print(second);*/ } void circle(int const R, int counter) { set_pen_width(3); if(counter<=360) { counter = counter+1; draw_distance((2*pi*R)/360); turn_right_by_degrees(1); circle(R,counter); } } void ticks(int num) { if(num<12) { set_heading_degrees(30*num); set_pen_width(2); set_pen_color(color::white); move_to(200,200); draw_distance(150); set_pen_color(color::black); draw_distance(25); ticks(num+1); } } void hour_hand(int hour, int minute) { set_heading_degrees(hour*30 + minute*0.5); move_to(200,200); set_pen_color(color::black); set_pen_width(3); draw_distance(80); } void minute_hand(int minute) { set_heading_degrees(minute*6); move_to(200,200); set_pen_color(color::black); set_pen_width(3); draw_distance(120); } void second_hand(int second) { while(true) { set_heading_degrees(second*6); move_to(200,200); set_pen_color(color::red); set_pen_width(2); draw_distance(120); wait(0.02); } } void run_clock(int hour, int minute, int second) { while(true) { get_times(); hour_hand(hour,minute); minute_hand(minute); second_hand(second); wait(0.02); } } void main() { int counter = 0; int R = 175; int num = 0; make_window(400,525); move_to(25,200); circle(R,counter); ticks(num); get_times(); //hour_hand(hour, minute); //minute_hand(minute); //second_hand(second); run_clock(hour,minute,second); }``````

To call the run_clock function, I have to initialize the variables hour, minute, and second in the main. That's not currently in my code, because when I do this, none of my hands appear on the clock. My code worked fine before I tried to make it loop: I initialized each hour/minute/second variable as its respective get_clock_time value, then called the functions hour_hand, minute_hand, and second_hand, and everything was displayed as it should have been. I'm at a loss as to how to get this to loop properly.

Any help/suggestions would be appreciated.
^

You assigned local values in get_times(), when get_times() returns they'll be gone.

That double while loop is gonna get you later.
Last edited on
Okay. I made my variables in get_times() global, so they'll be available everywhere, and removed them as parameters. I also removed the while loop in second_hand(). It draws the hands now, but all 3 are always at 12 o'clock and they still don't redraw.

I don't understand- this means that now my variables are not being assigned the correct values, right?
Your run clock function has an infinite loop, so the drawing functions never get to do anything. Same for the second_hand function.

 I made my variables in get_times() global, so they'll be available everywhere, and removed them as parameters.

IMO, don't do that. Make them variables in main, send references to them to the get_times function, so the values are available in main. Then send them as const arguments to which ever drawing function needs them.

Hope all goes well.
That sounds like what I did before- won't that just print a static picture of the clock that displays the time at the time the program is run? I want to have an infinite loop to make the clock actually update.
Passing by reference instead of using global variables will not change the behavior of your program, it will just show that you understand how to follow good practice.

Technically, though, the optimal solution is to make this a class with the variables as members, so no globals or passing references, etc - but I think that's out of the scope of this thread. It's always good to learn good design and good practice, though.
But your infinite loop means execution never escapes that function, the functions coming after it are never called.

Even though it might be OK for run_clock to have an infinite loop, it is not OK for second_hand to do so, because control never gets to do the 2nd iteration of run_clock. So execution goes into an infinite loop after only 1 iteration of second_hand, so it works as expected for 1 second then nothing seems to change, because the variable second is not being updated.

I would still put some limit on the run_clock function, otherwise the program never ends. In a real program, that would involve some kind of interrupt from the GUI system (a key press or mouse click say) - I am not sure whether such events are available in your environment.

If you remove the infinite loop from the second_hand function, and just call all the drawing functions in order, you will need some way of storing where each hand was drawn, so subsequent calls can erase it, then draw the new one.

When I did this years ago, I had it updating the correct angle of each of the 3 hands every second. So the hour hand angle was correct taking into account the hours minutes & seconds, similar for the minute hand.

With the variables in the get_time function, it would probably be better if it returned a structure (even better a pointer to the struct) containing the values, then run_clock can have access to all of them. Alternatively, if get_time is only being called from 1 place in your code, just put the code into the run_clock function. The first method is preferred from a design point of view, the second is more quick & easy & dirty.

Just wondering what the units are for the wait function - hopefully not seconds because your clock would be rather inaccurate. Shouldn't wait be called for 1 second, between calls to second_hand? And if the erasing of the previous position happened at the beginning of the function, then you would see the second hand being updated each second. Even better, would be to update the second hand every 0.1 of a second so it looks like it is smoothly animated.

One last thing, the C++ standard specifies that main return an int, not void. If you don't return an int explicitly, one is returned implicitly.

HTH

Last edited on
Ok. Thanks for the comments everyone. Here's where I'm at now:

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113`` ``````#include "library.h" const double pi = acos(-1.0); int get_times(/*int year, int month, int day,*/ int hour, int minute, int second) { //year = get_calendar_date() / 10000; //month = (get_calendar_date() / 100)%100; //day = (get_calendar_date() % 10000)%100; hour = get_clock_time() / 10000; minute = (get_clock_time() / 100)%100; second = (get_clock_time() % 1000)%100; //print("Year: "); print(year); //new_line(); //print("Month: "); print(month); //new_line(); //print("Day: "); print(day); new_line(); if(hour > 12) { print("Hour: "); print(hour-12); print(" P.M."); } else { print("Hour: "); print(hour); print(" A.M."); } new_line(); print("Minute: "); print(minute); new_line(); print("Second: "); print(second); return(second); } void circle(int const R, int counter) { set_pen_width(3); if(counter<=360) { counter = counter+1; draw_distance((2*pi*R)/360); turn_right_by_degrees(1); circle(R,counter); } } void ticks(int num) { if(num<12) { set_heading_degrees(30*num); set_pen_width(2); set_pen_color(color::white); move_to(200,200); draw_distance(150); set_pen_color(color::black); draw_distance(25); ticks(num+1); } } void hour_hand(int hour, int minute) { set_heading_degrees(hour*30 + minute*0.5); move_to(200,200); set_pen_color(color::black); set_pen_width(3); draw_distance(80); } void minute_hand(int minute) { set_heading_degrees(minute*6); move_to(200,200); set_pen_color(color::black); set_pen_width(3); draw_distance(120); } void second_hand(int second) { set_heading_degrees(second*6); move_to(200,200); set_pen_color(color::red); set_pen_width(2); draw_distance(120); } void run_clock(int hour, int minute, int second) { while(true) { get_times(hour,minute,second); second_hand(second); minute_hand(minute); hour_hand(hour, minute); wait(0.02); } } void main() { int year = 0; int month = 0; int day = 0; int hour = 0; int minute = 0; int second = 0; int counter = 0; int R = 175; int num = 0; make_window(400,525); move_to(25,200); circle(R,counter); ticks(num); //hour_hand(hour, minute); //minute_hand(minute); //second_hand(second); run_clock(hour,minute,second); }``````

I know my loop is working because when I print the results in the console, the time updates constantly. So that's good. Now if I understand this correctly, I need to devise a way of storing those results so they can be used by my run_clock function. I turned my get_times function into an int, but then realized that I wasn't sure if I could return multiple values. I need to return a discrete value for each time variable, right? How can I do that?

ps. I will use the year, month, and day later on in my program, but for now I've commented them out. I also realize that I'll have to devise a method for erasing the old drawing of my hands each time the program updates, but this should be fairly simple and I just want to focus on getting it to draw correctly right now.
Last edited on
 I need to return a discrete value for each time variable, right? How can I do that?

TheIdeasMan wrote:
 With the variables in the get_time function, it would probably be better if it returned a structure (even better a pointer to the struct) containing the values, then run_clock can have access to all of them.

HTH
At this point I'd say go for the Class technique.
Topic archived. No new replies allowed.