Giả lập đồng hồ (clock) trên console bằng C++

chào các bạn ! :slight_smile:
mình vừa làm xong 1 chương trình nhỏ sau, đồng hồ trên console , nhưng có 1 vấn đề là kim giây chạy có khi nhanh hơn hoặc chậm hơn so với thời gian của đồng hồ thật, lúc đầu mới chạy minh lấy thời gian của hệ thống, lý do là mình sử dụng biến mili giay cho chạy lặp với do while ,mili giay tăng thì giây tăng thì giờ tăng thì ngày tăng thì tháng tăng thì năm tăng, và cái đồng hộ này mình dự kiến là đến 2080 thì hết pin :smile:
vì sử dụng vòng lặp nên có khi máy chạy chậm có khi máy chạy nhanh, ảnh hưởng đến thời gian, nên mình muốn hỏi có cách nào để có thể động bộ được với thời gian thật, nghĩa là kim ms sẽ chạy ổn định và k bị ngáo đá :V mình tìm trên mạng thì có 1 số bạn sử dụng sleep cho nó tạm dừng 1000, và như thế mình sẽ bỏ đi phần chạy kim ms có được k nhỉ ’

https://github.com/AnhQuanTran/cpp

#ifndef _CRT_SECURE_NO_WARNINGS // for by pass warning library ctime on visual studio
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <iostream>
#include <ctime>
using namespace std;

class clock_console{
private:
	int hour, minute, second, milisecond, day, month, year;

	void run_time(){
		milisecond++;
		if (milisecond == 60){
			milisecond = 0;
			cout << "\a";
			second++;
			if (second >= 60){
				second = 0;
				minute++;
				if (minute == 60){
					minute = 0;
					hour++;
					if (hour == 24){
						hour = 0;
						day++;
						if (day == 1 + day_month(month)){
							day = 1;
							month++;
							if (month == 13){
								month = 1;
								year++;
								if (year == 2081){   // clock only run to 2080
									cout << "Out of battery" << endl;
									system("pause");
									exit(0);
								}
							}
						}
					}
				}
			}
		}
	}

	void clock_24h(){
		system("cls");
		cout << "       ,--.-----.--." << endl;
		cout << "       |--|-----|--|" << endl;
		cout << "       |--|     |--|" << endl;
		cout << "       |  |-----|  |" << endl;
		cout << "     __|--|     |--|__" << endl;
		cout << "    /  |  |-----|  |  \\ " << endl;
		cout << "   /    \\_|-----|_/    \\ " << endl;
		cout << "  /   ______---______   \\/\\ " << endl;
		cout << " /   /               \\   \\/" << endl;
		cout << "{   /      Armani     \\   }" << endl;
		cout << "|  {                   }  |-," << endl;

		cout << (hour < 10 ? "|  |    0" : "|  |    ") << hour << (minute < 10 ? " : 0" : " : ") << minute
			<< (second < 10 ? " : 0" : " : ") << second << "   |  | |" << "\t\t    [email protected]" << endl;

		/*
		if (hour < 10)  cout << "|  |    0" << hour;
		else  cout << "|  |    " << hour;

		if (minute < 10)  cout << " : 0" << minute;
		else cout << " : " << minute;

		if (second < 10)  cout << " : 0" << second << "   |  | |" << endl;
		else cout << " : " << second << "   |  | |" << endl;
		*/
	}

	void clock_12h(){
		system("cls");
		cout << "       ,--.-----.--." << endl;
		cout << "       |--|-----|--|" << endl;
		cout << "       |--|     |--|" << endl;
		cout << "       |  |-----|  |" << endl;
		cout << "     __|--|     |--|__" << endl;
		cout << "    /  |  |-----|  |  \\ " << endl;
		cout << "   /    \\_|-----|_/    \\ " << endl;
		cout << "  /   ______---______   \\/\\ " << endl;
		cout << " /   /               \\   \\/" << endl;
		cout << "{   /      Armani     \\   }" << endl;
		cout << "|  {                   }  |-," << endl;

		if (hour == 0)       cout << "|  |  " << hour + 12;
		else if (hour < 10)  cout << "|  |  0" << hour;
		else if (hour <= 12) cout << "|  |  " << hour;
		else if (hour > 12 && hour < 22)  cout << "|  |  0" << hour - 12;
		else cout << "|  |  " << hour - 12;

		if (minute < 10)  cout << " : 0" << minute;
		else cout << " : " << minute;

		if (second < 10)  cout << " : 0" << second;
		else cout << " : " << second;

		if (hour < 12) cout << "  AM" << " |  | |" << "\t\t    [email protected]" << endl;
		else cout << "  PM" << " |  | |" << "\t\t    [email protected]" << endl;
	}

	void calender_number(){
		cout << (day < 10 ? "|  {     0" : "|  {     ") << day << "/"
			<< (month < 10 ? "0" : "") << month << "/" << year << "    }  |-'" << endl;
		cout << "{   \\                 /   }" << endl;
		cout << " \\   `------___------'   /\\ " << endl;
		cout << "  \\     __|-----|__     /\\/" << endl;
		cout << "   \\   /  |-----|  \\   /" << endl;
		cout << "    \\  |--|     |--|  /" << endl;
		cout << "     --|--|     |--|--" << endl;
		cout << "       |  |-----|  |" << endl;
		cout << "       |--|     |--|" << endl;
		cout << "       |--|-----|--|" << endl;
		cout << "       `--'-----`--'" << endl;
		cout << endl;
	}

	void calender_name(){
		cout << "|  {";
		switch (month){
		case 1: cout << "  January "
			<< (day < 10 ? "0" : "") << day << ", " << year << " }  |-'" << endl;
			break;
		case 2: cout << " February "
			<< (day < 10 ? "0" : "") << day << ", " << year << " }  |-'" << endl;
			break;
		case 3: cout << "   March "
			<< (day < 10 ? "0" : "") << day << ", " << year << "  }  |-'" << endl;
			break;
		case 4: cout << "   April "
			<< (day < 10 ? "0" : "") << day << ", " << year << "  }  |-'" << endl;
			break;
		case 5: cout << "    May "
			<< (day < 10 ? "0" : "") << day << ", " << year << "   }  |-'" << endl;
			break;
		case 6: cout << "   June "
			<< (day < 10 ? "0" : "") << day << ", " << year << "   }  |-'" << endl;
			break;
		case 7: cout << "   July "
			<< (day < 10 ? "0" : "") << day << ", " << year << "   }  |-'" << endl;
			break;
		case 8: cout << "  August "
			<< (day < 10 ? "0" : "") << day << ", " << year << "  }  |-'" << endl;
			break;
		case 9: cout << " September "
			<< (day < 10 ? "0" : "") << day << ", " << year << "}  |-'" << endl;
			break;
		case 10: cout << "  October "
			<< (day < 10 ? "0" : "") << day << ", " << year << " }  |-'" << endl;
			break;
		case 11: cout << " November "
			<< (day < 10 ? "0" : "") << day << ", " << year << " }  |-'" << endl;
			break;
		case 12: cout << " December "
			<< (day < 10 ? "0" : "") << day << ", " << year << " }  |-'" << endl;
			break;
		}
		cout << "{   \\                 /   }" << endl;
		cout << " \\   `------___------'   /\\ " << endl;
		cout << "  \\     __|-----|__     /\\/" << endl;
		cout << "   \\   /  |-----|  \\   /" << endl;
		cout << "    \\  |--|     |--|  /" << endl;
		cout << "     --|--|     |--|--" << endl;
		cout << "       |  |-----|  |" << endl;
		cout << "       |--|     |--|" << endl;
		cout << "       |--|-----|--|" << endl;
		cout << "       `--'-----`--'" << endl;
		cout << endl;
	}

	int day_month(int month){
		switch (month){
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12: return 31;
			break;
		case 6:
		case 4:
		case 9:
		case 11: return 30;
			break;
		case 2: return 28;
			break;
		}
	}

public:
	clock_console(){
		time_t full_time;
		time(&full_time);
		struct tm *sub_time;
		sub_time = localtime(&full_time);
		this->milisecond = 0;
		this->second = sub_time->tm_sec;
		this->minute = sub_time->tm_min;
		this->hour = sub_time->tm_hour;
		this->day = sub_time->tm_mday;
		this->month = 1 + sub_time->tm_mon;
		this->year = 1900 + sub_time->tm_year; // tm_year = nam hien tai  - 1900
		/*
		note:
		struct tm {
		int tm_sec;  //  0 - 61
		int tm_min;  //  0 - 59
		int tm_hour; //  0 - 23
		int tm_mday; //  1 - 31
		int tm_mon;  //  0 - 11
		int tm_year; // bat dau tu 1900
		};
		*/
	}

	void run(){
		int option1, option2;
		do{
			system("cls");
			cout << "1 - 12h" << endl;
			cout << "2 - 24h" << endl;
			cin >> option1;
		} while (option1 < 1 || option1 > 2);

		do{
			system("cls");
			cout << "1 - DD/MM/YYY" << endl;
			cout << "2 - Month Day, Year" << endl;
			cin >> option2;
		} while (option2 < 1 || option2 > 2);

		if (option1 == 1 && option2 == 1){
			do{
				run_time();
				clock_12h();
				calender_number();
			} while (1);
		}
		else if (option1 == 1 && option2 == 2){
			do{
				run_time();
				clock_12h();
				calender_name();
			} while (1);
		}
		else if (option1 == 2 && option2 == 1){
			do{
				run_time();
				clock_24h();
				calender_number();
			} while (1);
		}
		else{
			do{
				run_time();
				clock_24h();
				calender_name();
			} while (1);
		}
	}

	void new_time(){
		char temp;
		do{
			system("cls");
			cout << "Input Second : Minute : Hour" << endl;
			cin >> second >> temp >> minute >> temp >> hour;
			cout << "Input YYYY/MM/DD" << endl;
			cin >> year >> temp >> month >> temp >> day;
		} while (second<0 || second>59 || minute<0 || minute>59 || hour<0 || hour>23
			|| year<1994 || year>2080 || month<1 || month>12 || day<1 || day>day_month(month));
		run();
	}
};

int main(){
	clock_console now;

	int option;
	do{
		system("cls");
		cout << "       | |              | |                                       | |       " << endl;
		cout << "  ____ | |  ___    ____ | |  _     ____  ___   ____    ___   ___  | |  ____ " << endl;
		cout << " / ___)| | / _ \\  / ___)| | / )   / ___)/ _ \\ |  _ \\  /___) / _ \\ | | / _  )" << endl;
		cout << "( (___ | || |_| |( (___ | |< (   ( (___| |_| || | | ||___ || |_| || |( (/ / " << endl;
		cout << " \\____)|_| \\___/  \\____)|_| \\_)   \\____)\\___/ |_| |_|(___/  \\___/ |_| \\____)" << endl;
		cout << endl;
		cout << "1 - Run" << endl;
		cout << "2 - Set new time" << endl;
		cout << "3 - Exit" << endl;
		cin >> option;
	} while (option < 1 || option > 3);

	switch (option){
	case 1: now.run();
		break;
	case 2: now.new_time();
		break;
	case 3: return 0;
		break;
	}
	system("pause");
	return 0;
}

Demo:

2 Likes

Gọi hàm lấy giwò hệ thống. Sau đó check để hiện lên.

nghĩa là bạn cứ lấy giờ hệ thống liên tục , lấy xong hiện lên rồi lại lấy rồi lại hiện lên hả?

Cho em hỏi là bác tự nghĩ ra cái hình đồng hồ hay là lấy từ web nào ạ :vhs:

bạn vào mấy trang ascii art thích hình nào thì up ảnh lên, nó tự sinh cho mã ascii giống hình

1 Like

Độc đáo, nhưng đoạn code này không hay, nên tách làm nhiều hàm hoặc là design lại như thế nào chứ if nhiều thế này rất khó quản lý code.

https://github.com/AnhQuanTran/cpp/blob/56841e9b701908ed94473f074070c39128cda39d/clock_console.cpp#L15-L47

2 Likes

tách ra thành nhiều hàm,
hàm chạy kim giây, kim phút, kim giờ, ngày, tháng, năm, e sợ mỗi khi hàm này gọi hàm kia thế, nó lại chạy chậm hơn là rẽ nhánh :v

Tách ra thành nhiều hàm có chức năng hợp lý giúp em chỉnh sửa hay thay đổi code dễ dàng hơn sau này đó em.

1 Like

nhưng mà mỗi hàm chỉ có vài dòng, nếu tách thành nhiều hàm quá thì khi gọi hàm có mất chi phí về thời gian và bộ nhớ hơn là rẽ nhánh k nhỉ?

nếu tách ra thì có 7 hàm , về xử lý thì như thế nào với 7 câu if nhỉ , sợ là chậm hơn, nên e k tách

Mình pull request với code đẹp hơn tí xíu r đó.

3 Likes

pull request là gi ta? mình mới dùng git :3 đk lâu rồi nhưng giờ mới dùng, chưa kịp đọc tài liệu sử dụng, mới up được 1 file code lên :v

việc tách các phần của hàm in clock ra có tác dụng tối ưu hơn vậy bạn
với lại như vấn đề ở đâu, phần s làm sao để nó chạy đúng nhỉ, đồng bộ với thời gian của hệ thống

Muốn đồng bộ tgian hệ thống thì có thể gettime liên tục. nếu thời gian đã trôi qua cỡ 1s thì vẽ đồng hồ.
Còn tách hàm vậy dễ đọc code hơn, tránh trùng lặp code (1 tính năng dùng lại 2 lần trở lên thì nên tách thành 1 hàm) + mốt nếu bạn thích sửa giao diện thì dễ hơn.

4 Likes

mình k muốn đồng bộ theo kiểu lấy thời gian từ hệ thống liên tục mà chỉ lấy 1 lần, và ct sẽ tự chạy đúng ấy

Mình nghĩ chương trình bạn chậm do thao tác vẽ nhiều.
Nên nó chạy bị chậm lúc tính toán do đó kéo theo bị lệch giời gian.

2 Likes

1 phần độ trễ kim giây là do hàm in, nhưng sau khi chỉnh ms về thấp xuống, thì nó vẫn k thể đúng, khi nhanh khi chậm k ổn định, bỏ hẳn hàm in ra,chỉ để lại số, vẫn thế
mình nghĩ chạy đúng hay k do 1 phần do hàm in 1 phần do vòng lặp và kiểm tra rẽ nhánh

Bạn có thể in sau khi milisecond = 60 (or khi đủ 1 giây)
Tại lúc đó giao diện mới được cập nhật.
Như vậy có thể tăng tốc lên tí xíu.

3 Likes

Đại khai như sau. Nếu bạn muốn làm 1 cái đồng hồ chính xác cỡ 0.1s thì sau 0.09s bạn lấy time hệ thống 1 lần sau đó hiển thị nó lên màn hình.
Để làm sao cứ đúng 0.09s lấy giờ 1 lần thì bạn dùng kĩ thuậ fix FPS. Gỉa code.

t_last = t_now = 0;
while(isRunning) {
  t_last = t_now.
  //Hàm thục thi.
  t_mow = getTine(); //Lấy giờ sau khi chạy xong hàm
  sleep(1000.0f / FPS - t_now + t_last) // Sleep 1 khoảng thời gian động.
}

Khi đó bạn ổn định được chu kỳ lấy thời gian mà không làm tăng chíp.
Còn việc vẽ lại màn hình có thể dùng bộ đêm hoặc gotoxy.

Chúc bạn thành công.

2 Likes

Thanks :slight_smile: :slight_smile:

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?