diff --git a/internal/actioninfo/actioninfo.go b/internal/actioninfo/actioninfo.go index 566bf8b..cde3670 100644 --- a/internal/actioninfo/actioninfo.go +++ b/internal/actioninfo/actioninfo.go @@ -1,9 +1,29 @@ package actioninfo +import ( + "fmt" + "log" +) + +// DataParser — интерфейс для тренировок и прогулок. type DataParser interface { - // TODO: добавить методы + Parse(datastring string) error + ActionInfo() (string, error) } +// Info — выводит инфу по всем строкам dataset через dp. func Info(dataset []string, dp DataParser) { - // TODO: реализовать функцию + for _, data := range dataset { + err := dp.Parse(data) + if err != nil { + log.Printf("Ошибка парсинга строки '%s': %v", data, err) + continue + } + info, err := dp.ActionInfo() + if err != nil { + log.Printf("Ошибка формирования информации по строке '%s': %v", data, err) + continue + } + fmt.Println(info) + } } diff --git a/internal/daysteps/daysteps.go b/internal/daysteps/daysteps.go index 9012585..fa3098d 100644 --- a/internal/daysteps/daysteps.go +++ b/internal/daysteps/daysteps.go @@ -1,13 +1,59 @@ package daysteps +import ( + "errors" + "fmt" + "strconv" + "strings" + "time" + + "github.com/Yandex-Practicum/tracker/internal/personaldata" + "github.com/Yandex-Practicum/tracker/internal/spentenergy" +) + +// DaySteps — структура для дневных шагов. type DaySteps struct { - // TODO: добавить поля + Steps int + Duration time.Duration + personaldata.Personal } -func (ds *DaySteps) Parse(datastring string) (err error) { - // TODO: реализовать функцию +// Parse разбирает строку вида "678,0h50m" +func (ds *DaySteps) Parse(datastring string) error { + parts := strings.Split(datastring, ",") + if len(parts) != 2 { + return errors.New("некорректный формат строки для DaySteps") + } + steps, err := strconv.Atoi(parts[0]) + if err != nil { + return fmt.Errorf("ошибка парсинга количества шагов: %w", err) + } + duration, err := time.ParseDuration(parts[1]) + if err != nil { + return fmt.Errorf("ошибка парсинга длительности: %w", err) + } + + if steps <= 0 { + return errors.New("шаги должны быть положительным числом") + } + if duration <= 0 { + return errors.New("длительность должна быть положительным числом") + } + + ds.Steps = steps + ds.Duration = duration + return nil } +// ActionInfo возвращает строку с инфой о прогулке func (ds DaySteps) ActionInfo() (string, error) { - // TODO: реализовать функцию + distance := spentenergy.Distance(ds.Steps, ds.Height) + calories, err := spentenergy.WalkingSpentCalories(ds.Steps, ds.Weight, ds.Height, ds.Duration) + if err != nil { + return "", fmt.Errorf("ошибка расчета калорий для прогулки: %w", err) + } + return fmt.Sprintf( + "Количество шагов: %d.\nДистанция составила %.2f км.\nВы сожгли %.2f ккал.\n", + ds.Steps, distance, calories, + ), nil } diff --git a/internal/personaldata/personaldata.go b/internal/personaldata/personaldata.go index 48fd8f6..78381d3 100644 --- a/internal/personaldata/personaldata.go +++ b/internal/personaldata/personaldata.go @@ -1,9 +1,15 @@ package personaldata +import "fmt" + +// Personal — структура с личными данными пользователя. type Personal struct { - // TODO: добавить поля + Name string // Имя пользователя + Weight float64 // Вес (кг) + Height float64 // Рост (м) } +// Print — выводит данные пользователя на экран. func (p Personal) Print() { - // TODO: реализовать функцию + fmt.Printf("Имя: %s\nВес: %.2f кг.\nРост: %.2f м.\n\n", p.Name, p.Weight, p.Height) } diff --git a/internal/spentenergy/spentenergy.go b/internal/spentenergy/spentenergy.go index b0ea154..3705cca 100644 --- a/internal/spentenergy/spentenergy.go +++ b/internal/spentenergy/spentenergy.go @@ -1,29 +1,58 @@ package spentenergy import ( + "errors" "time" ) -// Основные константы, необходимые для расчетов. const ( - mInKm = 1000 // количество метров в километре. - minInH = 60 // количество минут в часе. - stepLengthCoefficient = 0.45 // коэффициент для расчета длины шага на основе роста. - walkingCaloriesCoefficient = 0.5 // коэффициент для расчета калорий при ходьбе. + stepLengthCoefficient = 0.45 + mInKm = 1000.0 + minInH = 60.0 + walkingCaloriesCoefficient = 0.5 ) -func WalkingSpentCalories(steps int, weight, height float64, duration time.Duration) (float64, error) { - // TODO: реализовать функцию +// Distance считает дистанцию в километрах по шагам и росту. +func Distance(steps int, height float64) float64 { + if steps < 0 || height <= 0 { + return 0 + } + stepLength := height * stepLengthCoefficient + return float64(steps) * stepLength / mInKm } -func RunningSpentCalories(steps int, weight, height float64, duration time.Duration) (float64, error) { - // TODO: реализовать функцию +// MeanSpeed считает среднюю скорость в км/ч. +func MeanSpeed(steps int, height float64, duration time.Duration) float64 { + if steps < 0 || height <= 0 || duration <= 0 { + return 0 + } + distance := Distance(steps, height) + hours := duration.Hours() + if hours == 0 { + return 0 + } + return distance / hours } -func MeanSpeed(steps int, height float64, duration time.Duration) float64 { - // TODO: реализовать функцию +// RunningSpentCalories считает потраченные калории при беге. +func RunningSpentCalories(steps int, weight, height float64, duration time.Duration) (float64, error) { + if steps <= 0 || weight <= 0 || height <= 0 || duration <= 0 { + return 0, errors.New("некорректные параметры для расчёта калорий при беге") + } + meanSpeed := MeanSpeed(steps, height, duration) + durationInMinutes := duration.Minutes() + calories := (weight * meanSpeed * durationInMinutes) / minInH + return calories, nil } -func Distance(steps int, height float64) float64 { - // TODO: реализовать функцию +// WalkingSpentCalories считает потраченные калории при ходьбе. +func WalkingSpentCalories(steps int, weight, height float64, duration time.Duration) (float64, error) { + if steps <= 0 || weight <= 0 || height <= 0 || duration <= 0 { + return 0, errors.New("некорректные параметры для расчёта калорий при ходьбе") + } + meanSpeed := MeanSpeed(steps, height, duration) + durationInMinutes := duration.Minutes() + calories := (weight * meanSpeed * durationInMinutes) / minInH + calories *= walkingCaloriesCoefficient + return calories, nil } diff --git a/internal/trainings/trainings.go b/internal/trainings/trainings.go index df7be33..7c608c5 100644 --- a/internal/trainings/trainings.go +++ b/internal/trainings/trainings.go @@ -1,13 +1,80 @@ package trainings +import ( + "errors" + "fmt" + "strconv" + "strings" + "time" + + "github.com/Yandex-Practicum/tracker/internal/personaldata" + "github.com/Yandex-Practicum/tracker/internal/spentenergy" +) + +// Training — данные о тренировке type Training struct { - // TODO: добавить поля + Steps int + TrainingType string + Duration time.Duration + personaldata.Personal } -func (t *Training) Parse(datastring string) (err error) { - // TODO: реализовать функцию +// Parse разбирает строку формата "3456,Ходьба,3h00m" +func (t *Training) Parse(datastring string) error { + parts := strings.Split(datastring, ",") + if len(parts) != 3 { + return errors.New("некорректный формат строки тренировки") + } + steps, err := strconv.Atoi(parts[0]) + if err != nil { + return fmt.Errorf("ошибка парсинга количества шагов: %w", err) + } + duration, err := time.ParseDuration(parts[2]) + if err != nil { + return fmt.Errorf("ошибка парсинга длительности: %w", err) + } + + if steps <= 0 { + return errors.New("шаги должны быть положительным числом") + } + if duration <= 0 { + return errors.New("длительность должна быть положительным числом") + } + + t.Steps = steps + t.TrainingType = parts[1] + t.Duration = duration + return nil } +// ActionInfo возвращает инфу о тренировке (строка и ошибка) func (t Training) ActionInfo() (string, error) { - // TODO: реализовать функцию + distance := spentenergy.Distance(t.Steps, t.Height) + speed := spentenergy.MeanSpeed(t.Steps, t.Height, t.Duration) + + var calories float64 + var err error + + switch strings.ToLower(t.TrainingType) { + case "бег", "run", "running": + calories, err = spentenergy.RunningSpentCalories(t.Steps, t.Weight, t.Height, t.Duration) + if err != nil { + return "", fmt.Errorf("ошибка расчета калорий для бега: %w", err) + } + return fmt.Sprintf( + "Тип тренировки: Бег\nДлительность: %.2f ч.\nДистанция: %.2f км.\nСкорость: %.2f км/ч\nСожгли калорий: %.2f\n", + t.Duration.Hours(), distance, speed, calories, + ), nil + case "ходьба", "walk", "walking": + calories, err = spentenergy.WalkingSpentCalories(t.Steps, t.Weight, t.Height, t.Duration) + if err != nil { + return "", fmt.Errorf("ошибка расчета калорий для ходьбы: %w", err) + } + return fmt.Sprintf( + "Тип тренировки: Ходьба\nДлительность: %.2f ч.\nДистанция: %.2f км.\nСкорость: %.2f км/ч\nСожгли калорий: %.2f\n", + t.Duration.Hours(), distance, speed, calories, + ), nil + default: + return "", errors.New("неизвестный тип тренировки") + } }