Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Completed Work Ряковский #24

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Language: Cpp
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
BreakBeforeBraces: Allman
ColumnLimit: 120
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
PointerAlignment: Left
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.cache
build
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.15)

project(TimeChecker)

file(GLOB SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp)
file(GLOB HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/src/*.h)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_executable(TimeChecker ${SOURCE_FILES} ${HEADER_FILES})

set_target_properties(TimeChecker PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON)
101 changes: 101 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 15,
"patch": 0
},
"include": [],
"configurePresets": [
{
"name": "windows-base",
"hidden": true,
"generator": "Ninja",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
},
"architecture": {
"value": "x64",
"strategy": "external"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "Debug",
"displayName": "Debug Config",
"description": "Debug build using Ninja generator",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/Debug",
"installDir": "${sourceDir}/install/Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"environment": {},
"vendor": {},
"condition": {
"type": "notEquals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "Release",
"displayName": "Release Config",
"description": "Release build using Ninja generator",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/Release",
"installDir": "${sourceDir}/install/Release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
},
"environment": {},
"vendor": {},
"condition": {
"type": "notEquals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "Debug-Windows",
"displayName": "Debug Config",
"description": "Debug build using Ninja generator",
"inherits": "windows-base",
"binaryDir": "${sourceDir}/build/Debug",
"installDir": "${sourceDir}/install/Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"environment": {},
"vendor": {},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "Release-Windows",
"displayName": "Release Config",
"description": "Release build using Ninja generator",
"inherits": "windows-base",
"binaryDir": "${sourceDir}/build/Release",
"installDir": "${sourceDir}/install/Release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
},
"environment": {},
"vendor": {},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
}
]
}
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,33 @@ a30b4d51-11b4-49b2-b356-466e92a66df7 Иванов Иван Иванович 16.0
Примеры входного и выходного файлов приложены к настоящему техническому заданию.

## Автор решения

Ряковский Дмитрий Сергеевич
## Описание реализации

1. Чтение файла
- Читаем первую строчку для определения необходимых часов в неделю и сохранения их в переменную.
- Все последующие строчки читаем информацию о пользователях основываясь на их ID (ФИО + Время работы).
- Если пользователь уже существует в базе, добавляем новое время работы к общему времени этого пользователя.
- Если пользователь новый, создаём новую запись с его данными.
2. Запись результатов в новый файл
- Смотрим на общее время работы каждого пользователя и сравниваем с необходимым минимумом.
- Сохраняем пользоватей в соотвествующий список недоработки/переработки.
- Сортируем списки, выводим и сохраняем в файле
## Инструкция по сборке и запуску решения
Собиралась программа под Windows, используя Clang 17, CMake 3.15 и генератор Ninja.
Когда установлены эти зависимости и добавлены в PATH, нужно выполнить данные шаги:
1. Клонировать репозиторий с помощью
~~~
git clone https://github.com/Dyncais/school2024-test-task6.git proj
~~~

2. Зайти в эту папку в терминале и выполнить команду
~~~
cmake --preset Release-Windows
~~~

3. Когда конфигурация закончится, выполнить команду для сборки
~~~
cmake --build build/Release --target TimeChecker
~~~

4. Файл report.txt нужно положить в папку, в которой находится TimeChecker.exe. Затем можно запускать программу и в этой же папке появится result.txt
155 changes: 155 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#include <algorithm>
#include <cstdlib>
#include <exception>
#include <fstream>
#include <iostream>
#include <map>
#include <ranges>
#include <string>
#include <utility>
#include <vector>


struct PersonInfo
{
std::string Name;
std::string MiddleName;
std::string LastName;
double Worktime;
};

constexpr std::vector<std::string> SplitString(std::string_view str, std::string_view delimiters)
{
std::vector<std::string> output;
size_t first = 0;

while (first < str.size())
{
const auto second = str.find_first_of(delimiters, first);

if (first != second)
output.emplace_back(str.substr(first, second - first));

if (second == std::string_view::npos)
break;

first = second + 1;
}

return output;
}

std::string GetFirstUTF8Char(const std::string& str)
{
if (str.empty())
{
return "";
}

unsigned char firstByte = static_cast<unsigned char>(str[0]);

size_t charLength = 1;
if (firstByte >= 0xF0)
{
charLength = 4;
}
else if (firstByte >= 0xE0)
{
charLength = 3;
}
else if (firstByte >= 0xC0)
{
charLength = 2;
}

return str.substr(0, charLength);
}

bool compareByUTF8(const std::pair<std::string, double>& a, const std::pair<std::string, double>& b)
{
return a.first < b.first;
}

int main()
{
std::string line;
double hours;
std::map<std::string, struct PersonInfo> InfoWeek;

std::ifstream in("report.txt");
try
{
std::getline(in, line);
hours = stod(line);
}
catch (const std::exception& exp)
{
std::cout << "Expected: First Line Hours: " << exp.what() << '\n';
std::exit(1);
}

if (in.is_open())
{
while (std::getline(in, line))
{
std::vector Person = SplitString(line, " ");
if (!InfoWeek.contains(Person[0]))
{
InfoWeek.emplace(std::pair<std::string, PersonInfo>{
Person[0], PersonInfo((Person[1]), Person[2], Person[3], stod(Person[5]))});
}
else
{
if (InfoWeek[Person[0]].Name == (Person[1])) //Если у разнофамильцев почему-то одинаковое UUID, то вероятно сбой/ошибка в UUID. Такие ситуации крайне-крайне маловероятны
InfoWeek[Person[0]].Worktime += stod(Person[5]);
else
{
std::cout << "Different Person with same UUID. Check UUID generator" << '\n';
std::exit(1);
}
}
}
}

in.close();

std::ofstream fout("result.txt");
if (fout.is_open())
{
std::vector<std::pair<std::string, double>> OverWorkedPersonPlus;
std::vector<std::pair<std::string, double>> UnderWorkedPersonMinus;

for (auto& [_, info] : InfoWeek)
{
if (info.Worktime > hours * 1.1)
{
OverWorkedPersonPlus.push_back(std::make_pair(info.Name + ' ' + GetFirstUTF8Char(info.MiddleName) +
'.' + GetFirstUTF8Char(info.LastName) + '.',
info.Worktime - hours));
}

if (info.Worktime < hours * 0.9)
{
UnderWorkedPersonMinus.push_back(std::make_pair(info.Name + ' ' + GetFirstUTF8Char(info.MiddleName) +
'.' + GetFirstUTF8Char(info.LastName) + '.',
info.Worktime - hours));
}
}
std::sort(UnderWorkedPersonMinus.begin(), UnderWorkedPersonMinus.end(), compareByUTF8);
std::sort(OverWorkedPersonPlus.begin(), OverWorkedPersonPlus.end(), compareByUTF8);

for (const auto& [name, time] : UnderWorkedPersonMinus)
{
fout << name << ' ' << time << '\n';
}

if(!OverWorkedPersonPlus.empty()) //OverWorkedPersonPlus[0] существует, если есть хоть 1 человек с переработкой
fout << OverWorkedPersonPlus[0].first << " +" << OverWorkedPersonPlus[0].second;

for (const auto& [name, time] : OverWorkedPersonPlus | std::views::drop(1))
{
fout << '\n' << name << " +" << time;
}
}
fout.close();
}