영문 타자연습 프로그램 만들기
1) 헤더파일
1-1)Header.h
#ifndef __HEADER_H__
#define __HEADER_H__
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <string>
#include <vector>
#include "TypingGameHelper.h"
#endif // ! __HEADER_H__
1-2) TypingGameHelper.h
#ifndef __TYPING_GAME_HELPER_H__
#define __TYPING_GAME_HELPER_H__
#include <Windows.h>
#include <cstdio>
#include <string>
void putStringOnPosition(int x, int y, const std::string& content);
void showConsoleCursor(bool showFlag);
void clear();
#endif
1-3) TypingSystem.h
#ifndef __TYPING_SYSTEM_H__
#define __TYPING_SYSTEM_H__
#include "Header.h"
#include "User.h"
class TypingSystem {
private:
//문장들이 저장됨. vector로 받아서 문장의 갯수 제한 없앰
std::vector<std::string> sentences;
// 현재 사용자
User* currentUser = nullptr;
public:
//디스크로부터 데이터를 읽어와서 문장 리스트를 초기화 하는 함수
void loadData();
//데이터 출력 함수
void printData();
//시작하는 함수
void start();
//메뉴 출력함수
void printMenu();
// 메뉴를 입력받을때 문자 하나를 입력받기.
char getChar();
// 문자입력받기
std::string getString();
void typingStart();
int compare(const std::string& original, const std::string& input);
};
#endif // !__TYPING_SYSTEM_H__
1-4) User.h
#ifndef __USER_H__
#define __USER_H__
#include "Header.h"
class User {
public:
//파일명
std::string username;
// 평균 타자 속도
float avgSpeed = 0.0f;
//타자 문장을 얼마나 입력했는지
int typingCount = 0;
User(const std::string& username);
void save();
void load();
void printUserInfo();
};
#endif // !
2) 소스파일
2-1) Main.cpp
#include "Header.h"
#include "TypingSystem.h"
int main() {
srand(time(0));
TypingSystem* s = new TypingSystem();
s->start();
return 0;
}
2-2) TypingGameHelper.cpp
#include "TypingGameHelper.h"
#include <string>
void putStringOnPosition(int x, int y, const std::string& content) {
// Move Cursor
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
// Print string
printf("%s", content.c_str());
}
void showConsoleCursor(bool showFlag) {
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(out, &cursorInfo);
cursorInfo.bVisible = showFlag; // set the cursor visibility
SetConsoleCursorInfo(out, &cursorInfo);
}
void clear() {
system("cls");
}
2-3) TypingSystem.h
#include "TypingSystem.h"
void TypingSystem::loadData(){
FILE* infile = fopen("sentences.txt", "r");
for (;;) {
// 파일의 끝에 도달하면 종료해라
if (feof(infile) == 1) break;
char line[512] = {0, };
// null 문자를 위한 공간을 남겨 두는 것.
fscanf(infile, "%511[^\n]s", line);
fgetc(infile);
sentences.push_back(line);
}
fclose(infile);
}
void TypingSystem::printData(){
for (int i = 0; i < sentences.size(); i++) {
printf("%s\n", sentences[i].c_str());
}
}
void TypingSystem::start() {
this->loadData();
for (;;) {
clear();
printMenu();
char input = getChar();
if (input == '1' && currentUser == nullptr ) {
putStringOnPosition(6, 4, "아이디를 입력해 주세요:");
std::string username = getString();
currentUser = new User(username);
//로그인 진행
//사용자로부터 입력을 받아서 해당 입력된 문자열을 통해
// 문자열과 동일한 파일명이 있으면 그 파일에서 데이터를 읽어와서
// 평균타수, 총 타자연습갯수를 불러오는 로직을 형성
}
else if (input == '1' && currentUser != nullptr) {
//로그아웃 진행
delete currentUser;
currentUser = nullptr;
}
else if (input == '2' && currentUser != nullptr) {
//타자연습 진행
typingStart();
}
else if (input == '3' && currentUser != nullptr) {
//유저 정보 출력
currentUser->printUserInfo();
}
else if (input == 'x' || input == 'X') {
//종료
putStringOnPosition(6, 13, "프로그램을 종료 합니다.");
break;
}
else {
}
}
}
void TypingSystem::printMenu(){
if (currentUser == nullptr) {
putStringOnPosition(6, 3, "1. 로그인");
}
else {
putStringOnPosition(6, 3, "1. 로그아웃");
putStringOnPosition(6, 4, "2. 타자연습 시작");
putStringOnPosition(6, 5, "3. 연습 통계 보기");
}
putStringOnPosition(6, 12, "메뉴를 입력해 주세요(종료는 X 입력) : ");
}
char TypingSystem::getChar(){
fseek(stdin, 0, SEEK_END);
char c;
scanf("%c", &c);
return c;
}
std::string TypingSystem::getString(){
char input[100];
fseek(stdin, 0, SEEK_END);
scanf("%99[^\n]s", input);
return input;
}
void TypingSystem::typingStart(){
float types_per_min = 0.0f;
for (int i = 0; i < 5; i++) {
clear();
// sprintf를 위해서 만들어둔 배열
char buff[128];
//상단에 분당 타수를 출력 합니다.
sprintf(buff, "분당 타수: %.2f / 평균타수 %.2f", types_per_min, currentUser->avgSpeed);
putStringOnPosition(6, 5, buff);
// 프로그램이 시작한지 몇초가 지난지 나옴.
float start = (float)clock() / CLOCKS_PER_SEC;
int target = rand() % sentences.size();
sprintf(buff, "문장: %s", sentences[target].c_str());
putStringOnPosition(6, 6, buff);
//문자열을 사용자로부터 입력받는 곳
putStringOnPosition(6, 7, "입력: ");
std::string input = getString();
float end = (float)clock() / CLOCKS_PER_SEC;
// 시간이 얼마나 흘렀는지 계산
float delta = end - start;
// 분당 몇 타수 계산
types_per_min = sentences[target].size() / delta * 60;
int matches = compare(sentences[target], input);
float match_ratio = (float)matches / sentences[target].size();
types_per_min = types_per_min * match_ratio;
// 타이핑 카운트 계산
currentUser->typingCount++;
currentUser->avgSpeed = (currentUser->avgSpeed * ((float)currentUser->typingCount - 1.0 ) + types_per_min) / (float)currentUser->typingCount ;
// 입력된 문자열과, 해당 문자열의 일치율
// 입력 속도를 계산 후 출력
}
currentUser->save();
putStringOnPosition(6, 8, "연습이 종료되었습니다.");
putStringOnPosition(6, 9, "계속하려면 엔터키를 눌러주세요: ");
fseek(stdin, 0, SEEK_END);
fgetc(stdin);
}
int TypingSystem::compare(const std::string& original, const std::string& input){
int count = 0;
int size = original.size() < input.size() ? original.size() : input.size();
for (int i = 0; i < size; i++) {
//at : 파라미터를 입력받아 파라미터 위치에 있는 문자를 리턴해줌.
// original.c_str()[i] 와 같다.
if (original.at(i) == input.at(i)) {
count++;
}
}
return count;
}
2-4) User.cpp
#include "User.h"
User::User(const std::string& username) {
this->username = username;
FILE* fp = fopen(username.c_str(), "r");
bool exists = fp != nullptr;
if (exists) fclose(fp);
if (exists) {
putStringOnPosition(6, 5, "사용자가 존재합니다... 불러오는중...");
load();
putStringOnPosition(6, 6, "계속하려면 엔터를 입력해주세요");
fseek(stdin, 0, SEEK_END);
fgetc(stdin);
}
else {
putStringOnPosition(6, 5, "사용자가 존재하지 않습니다... 새로 만드는 중...");
save();
putStringOnPosition(6, 6, "계속하려면 엔터를 입력해주세요");
fseek(stdin, 0, SEEK_END);
fgetc(stdin);
}
}
void User::save(){
FILE* outfile = fopen(username.c_str(), "w");
fprintf(outfile, "%f\n", avgSpeed);
fprintf(outfile, "%d", typingCount);
fclose(outfile);
}
void User::load(){
FILE* infile = fopen(username.c_str(), "r");
fscanf(infile, "%f", &avgSpeed);
fgetc(infile);
fscanf(infile, "%d", &typingCount);
fclose(infile);
}
void User::printUserInfo(){
char avgSpeed[50];
//sprintf는 문자열에다 %f(포맷스트링) 를 집어넣을수 있음.
sprintf(avgSpeed, "평균 타수: %f", this->avgSpeed);
char count[50];
sprintf(count, "타이핑 횟수 : %d", this->typingCount);
putStringOnPosition(6, 6, avgSpeed);
putStringOnPosition(6, 7, count);
putStringOnPosition(6, 8, "계속 하려면 엔터키를 눌러 주세요");
fseek(stdin, 0, SEEK_END);
fgetc(stdin);
}