Skip to content

Commit 33a7340

Browse files
authored
Merge pull request #7480 from Kenysdev/50.rs
#50 - rust
2 parents c7c3e89 + 7ed4e97 commit 33a7340

File tree

1 file changed

+249
-0
lines changed
  • Roadmap/50 - PLANIFICADOR DE OBJETIVOS DE AÑO NUEVO/rust

1 file changed

+249
-0
lines changed
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
/*
2+
_____________________________________
3+
https://github.com/kenysdev
4+
2024 - Rust
5+
__________________________________________
6+
#50 PLANIFICADOR DE OBJETIVOS DE AÑO NUEVO
7+
------------------------------------------
8+
* EJERCICIO:
9+
* El nuevo año está a punto de comenzar...
10+
* ¡Voy a ayudarte a planificar tus propósitos de nuevo año!
11+
*
12+
* Programa un gestor de objetivos con las siguientes características:
13+
* - Permite añadir objetivos (máximo 10)
14+
* - Calcular el plan detallado
15+
* - Guardar la planificación
16+
*
17+
* Cada entrada de un objetivo está formado por (con un ejemplo):
18+
* - Meta: Leer libros
19+
* - Cantidad: 12
20+
* - Unidades: libros
21+
* - Plazo (en meses): 12 (máximo 12)
22+
*
23+
* El cálculo del plan detallado generará la siguiente salida:
24+
* - Un apartado para cada mes
25+
* - Un listado de objetivos calculados a cumplir en cada mes
26+
* (ejemplo: si quiero leer 12 libros, dará como resultado
27+
* uno al mes)
28+
* - Cada objetivo debe poseer su nombre, la cantidad de
29+
* unidades a completar en cada mes y su total. Por ejemplo:
30+
*
31+
* Enero:
32+
* [ ] 1. Leer libros (1 libro/mes). Total: 12.
33+
* [ ] 2. Estudiar Git (1 curso/mes). Total: 1.
34+
* Febrero:
35+
* [ ] 1. Leer libros (1 libro/mes). Total: 12.
36+
* ...
37+
* Diciembre:
38+
* [ ] 1. Leer libros (1 libro/mes). Total: 12.
39+
*
40+
* - Si la duración es menor a un año, finalizará en el mes
41+
* correspondiente.
42+
*
43+
* Por último, el cálculo detallado debe poder exportarse a .txt
44+
* (No subir el fichero)
45+
*/
46+
47+
use std::collections::HashMap;
48+
use std::io::{self, Write};
49+
use std::process::Command;
50+
use chrono::Local;
51+
use std::fs::File;
52+
53+
#[derive(Debug)]
54+
struct Goal {
55+
name: String,
56+
quantity: i32,
57+
units: String,
58+
}
59+
60+
struct ObjectivePlanner {
61+
goals: Vec<Goal>,
62+
months: Vec<String>,
63+
pending_monthly: HashMap<usize, Vec<i32>>,
64+
}
65+
66+
impl ObjectivePlanner {
67+
fn new() -> Self {
68+
let months = vec![
69+
"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
70+
"Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
71+
].iter().map(|&s| s.to_string()).collect();
72+
73+
ObjectivePlanner {
74+
goals: Vec::new(),
75+
months,
76+
pending_monthly: HashMap::new(),
77+
}
78+
}
79+
80+
fn read_line(prompt: &str) -> String {
81+
print!("{}", prompt);
82+
io::stdout().flush().unwrap();
83+
let mut input = String::new();
84+
io::stdin().read_line(&mut input).unwrap();
85+
input.trim().to_string()
86+
}
87+
88+
fn add(&mut self) -> io::Result<()> {
89+
if self.goals.len() >= 10 {
90+
println!("\nMáximo de 10 objetivos alcanzado.");
91+
return Ok(());
92+
}
93+
94+
println!("Ingrese los detalles del objetivo:");
95+
let name = Self::read_line("Meta: ");
96+
97+
let quantity = match Self::read_line("Cantidad: ").parse::<i32>() {
98+
Ok(n) if n > 0 => n,
99+
_ => {
100+
println!("\nError: Ingrese una cantidad válida.");
101+
return Ok(());
102+
}
103+
};
104+
105+
let units = Self::read_line("Unidades: ");
106+
107+
let months = match Self::read_line("Plazo (en meses): ").parse::<i32>() {
108+
Ok(n) if (1..=12).contains(&n) => n,
109+
_ => {
110+
println!("\nError: Ingrese un plazo válido (1-12 meses).");
111+
return Ok(());
112+
}
113+
};
114+
115+
if !name.is_empty() && !units.is_empty() {
116+
let goal = Goal {
117+
name,
118+
quantity,
119+
units,
120+
};
121+
122+
let goal_id = self.goals.len();
123+
let monthly = quantity / months;
124+
let extra = quantity % months;
125+
126+
let monthly_quantities: Vec<i32> = (0..months)
127+
.map(|m| monthly + if m < extra { 1 } else { 0 })
128+
.collect();
129+
130+
self.pending_monthly.insert(goal_id, monthly_quantities);
131+
self.goals.push(goal);
132+
println!("\nObjetivo añadido exitosamente.");
133+
} else {
134+
println!("\nDatos inválidos.");
135+
}
136+
137+
Ok(())
138+
}
139+
140+
fn calculate_plan(&self) -> Option<HashMap<String, Vec<String>>> {
141+
if self.goals.is_empty() {
142+
return None;
143+
}
144+
145+
let mut plan: HashMap<String, Vec<String>> = HashMap::new();
146+
147+
for (goal_id, goal) in self.goals.iter().enumerate() {
148+
if let Some(monthly_quantities) = self.pending_monthly.get(&goal_id) {
149+
for (month, &quantity) in monthly_quantities.iter().enumerate() {
150+
if quantity > 0 {
151+
let month_name = &self.months[month];
152+
let task = format!(
153+
"[ ] {} ({} {}/mes). Total: {}.",
154+
goal.name, quantity, goal.units, goal.quantity
155+
);
156+
plan.entry(month_name.clone())
157+
.or_insert_with(Vec::new)
158+
.push(task);
159+
}
160+
}
161+
}
162+
}
163+
164+
if plan.is_empty() {
165+
None
166+
} else {
167+
Some(plan)
168+
}
169+
}
170+
171+
fn write_ordered_plan<W: Write>(&self, mut writer: W) -> io::Result<()> {
172+
if let Some(plan) = self.calculate_plan() {
173+
for month in &self.months {
174+
if let Some(tasks) = plan.get(month) {
175+
writeln!(writer, "{}:", month)?;
176+
for task in tasks {
177+
writeln!(writer, " {}", task)?;
178+
}
179+
writeln!(writer)?;
180+
}
181+
}
182+
}
183+
Ok(())
184+
}
185+
186+
fn save_plan(&self) -> io::Result<()> {
187+
if self.calculate_plan().is_none() {
188+
println!("\nNo hay planificación para guardar.");
189+
return Ok(());
190+
}
191+
192+
let filename = format!(
193+
"plan_{}.txt",
194+
Local::now().format("%Y%m%d_%H%M")
195+
);
196+
197+
let file = File::create(&filename)?;
198+
self.write_ordered_plan(file)?;
199+
println!("\nPlan guardado en {}.", filename);
200+
Ok(())
201+
}
202+
203+
fn display_plan(&self) {
204+
if self.calculate_plan().is_none() {
205+
println!("\nNo hay objetivos planificados.");
206+
return;
207+
}
208+
209+
self.write_ordered_plan(io::stdout())
210+
.expect("Error al mostrar el plan");
211+
}
212+
213+
fn clear_screen() {
214+
if cfg!(target_os = "windows") {
215+
Command::new("cmd").args(["/c", "cls"]).status().unwrap();
216+
} else {
217+
Command::new("clear").status().unwrap();
218+
}
219+
}
220+
221+
pub fn run(&mut self) -> io::Result<()> {
222+
Self::clear_screen();
223+
224+
loop {
225+
println!("\nGestor de Objetivos:");
226+
println!("1. Añadir objetivo");
227+
println!("2. Calcular plan detallado");
228+
println!("3. Guardar planificación");
229+
println!("4. Salir");
230+
231+
match Self::read_line("\nSeleccione una opción: ").as_str() {
232+
"1" => self.add()?,
233+
"2" => self.display_plan(),
234+
"3" => self.save_plan()?,
235+
"4" => {
236+
println!("\n¡Adiós!");
237+
break;
238+
}
239+
_ => println!("\nOpción inválida."),
240+
}
241+
}
242+
Ok(())
243+
}
244+
}
245+
246+
fn main() -> io::Result<()> {
247+
let mut planner = ObjectivePlanner::new();
248+
planner.run()
249+
}

0 commit comments

Comments
 (0)