01/10/2018, 00:27

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

chào các bạn !
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
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 << "   |  | |" << "		    anh2uantran@gmail.com" << 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" << " |  | |" << "		    anh2uantran@gmail.com" << endl;
		else cout << "  PM" << " |  | |" << "		    anh2uantran@gmail.com" << 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:

Tao Không Ngu. viết 02:34 ngày 01/10/2018

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

HelloWorld viết 02:39 ngày 01/10/2018

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ả?

Nguyễn Hoàng Trung viết 02:32 ngày 01/10/2018

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

HelloWorld viết 02:40 ngày 01/10/2018

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

Mai Anh Dũng viết 02:32 ngày 01/10/2018

Độ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

HelloWorld viết 02:43 ngày 01/10/2018

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

Duy Quoc viết 02:29 ngày 01/10/2018

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.

HelloWorld viết 02:36 ngày 01/10/2018

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ỉ?

HelloWorld viết 02:38 ngày 01/10/2018

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

*grab popcorn* viết 02:32 ngày 01/10/2018

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

HelloWorld viết 02:42 ngày 01/10/2018

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

HelloWorld viết 02:30 ngày 01/10/2018

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

*grab popcorn* viết 02:33 ngày 01/10/2018

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.

HelloWorld viết 02:43 ngày 01/10/2018

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

*grab popcorn* viết 02:39 ngày 01/10/2018

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.

HelloWorld viết 02:34 ngày 01/10/2018

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

*grab popcorn* viết 02:27 ngày 01/10/2018

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.

Tao Không Ngu. viết 02:40 ngày 01/10/2018

Đạ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.

HelloWorld viết 02:30 ngày 01/10/2018

Còn việc vẽ lại màn hình có thể dùng bộ đêm hoặc gotoxy.

sử dụng gotoxy để vẽ lại đồng hồ, có tác dụng gì khác là in ra 1 cách bt bằng cách gọi hàm in clock nhi?

viết 02:27 ngày 01/10/2018

mình muốn tách ra, thời gian k bị phụ thuộc bởi tốc độ xử lý của mt, nhưng lại k muốn cứ get time hệ thông rồi in ra liên tục, chỉ muốn lấy 1 lần rồi nó tự chạy và có thể đúng giờ như tg của hệ thống

đâu có làm vậy được. Lúc nào cũng phải lấy thời gian thực hết, sao tự đếm được. Vì trên máy ko phải chỉ có 1 chương trình chạy, mà cả chục chương trình chạy với nhau, mỗi chương trình sẽ thay phiên nhau xài CPU. Vì vậy chương trình bạn chạy sẽ có lúc nhanh (được phép xài CPU liên tục), lúc chậm (xài CPU cách khoảng, hoặc chờ khá lâu mới được phép xài, vd anti-virus đang chạy thì nó sẽ chiếm CPU nhiều hơn) nên chỉ dựa vào vòng for để đếm thời gian là ko bao giờ chính xác.

Bài liên quan
0