1
+ //#50 { Retos para Programadores } PLANIFICADOR DE OBJETIVOS DE AÑO NUEVO
2
+ /*
3
+ * EJERCICIO:
4
+ * El nuevo año está a punto de comenzar...
5
+ * ¡Voy a ayudarte a planificar tus propósitos de nuevo año!
6
+ *
7
+ * Programa un gestor de objetivos con las siguientes características:
8
+ * - Permite añadir objetivos (máximo 10)
9
+ * - Calcular el plan detallado
10
+ * - Guardar la planificación
11
+ *
12
+ * Cada entrada de un objetivo está formado por (con un ejemplo):
13
+ * - Meta: Leer libros
14
+ * - Cantidad: 12
15
+ * - Unidades: libros
16
+ * - Plazo (en meses): 12 (máximo 12)
17
+ *
18
+ * El cálculo del plan detallado generará la siguiente salida:
19
+ * - Un apartado para cada mes
20
+ * - Un listado de objetivos calculados a cumplir en cada mes
21
+ * (ejemplo: si quiero leer 12 libros, dará como resultado
22
+ * uno al mes)
23
+ * - Cada objetivo debe poseer su nombre, la cantidad de
24
+ * unidades a completar en cada mes y su total. Por ejemplo:
25
+ *
26
+ * Enero:
27
+ * [ ] 1. Leer libros (1 libro/mes). Total: 12.
28
+ * [ ] 2. Estudiar Git (1 curso/mes). Total: 1.
29
+ * Febrero:
30
+ * [ ] 1. Leer libros (1 libro/mes). Total: 12.
31
+ * ...
32
+ * Diciembre:
33
+ * [ ] 1. Leer libros (1 libro/mes). Total: 12.
34
+ *
35
+ * - Si la duración es menor a un año, finalizará en el mes
36
+ * correspondiente.
37
+ *
38
+ * Por último, el cálculo detallado debe poder exportarse a .txt
39
+ * (No subir el fichero)
40
+ */
41
+
42
+ const fs = require ( 'fs' ) ;
43
+ const readline = require ( 'readline' ) ;
44
+
45
+ const filePath = 'goals.txt' ;
46
+ const maxGoals = 10 ;
47
+ const log = console . log ;
48
+
49
+ const rl = readline . createInterface ( {
50
+ input : process . stdin ,
51
+ output : process . stdout
52
+ } ) ;
53
+
54
+ let goals = [ ] ;
55
+
56
+ const monthNames = [
57
+ "January" , "February" , "March" , "April" , "May" , "June" ,
58
+ "July" , "August" , "September" , "October" , "November" , "December"
59
+ ] ;
60
+
61
+ const menu = ( ) => {
62
+ log ( '\n--- New Year Goals Planner ---' ) ;
63
+ log ( '1. Add Goal' ) ;
64
+ log ( '2. View Goals' ) ;
65
+ log ( '3. Calculate Detailed Year Plan' ) ;
66
+ log ( '4. Export Plan to .txt' ) ;
67
+ log ( '5. Exit' ) ;
68
+ rl . question ( 'Select an option: ' , handleMenuOption ) ;
69
+ } ;
70
+
71
+ const handleMenuOption = ( option ) => {
72
+ switch ( option ) {
73
+ case '1' :
74
+ addGoal ( ) ;
75
+ break ;
76
+ case '2' :
77
+ viewGoals ( ) ;
78
+ break ;
79
+ case '3' :
80
+ calculateDetailedYearPlan ( ) ;
81
+ break ;
82
+ case '4' :
83
+ exportPlan ( ) ;
84
+ break ;
85
+ case '5' :
86
+ exitProgram ( ) ;
87
+ break ;
88
+ default :
89
+ log ( 'Invalid option, choose a number between 1 and 5. Please try again.' ) ;
90
+ menu ( ) ;
91
+ break ;
92
+ }
93
+ } ;
94
+
95
+ const addGoal = ( ) => {
96
+ if ( goals . length >= maxGoals ) {
97
+ log ( 'Maximum number of goals reached.' ) ;
98
+ return menu ( ) ;
99
+ }
100
+
101
+ askGoalName ( ) ;
102
+ } ;
103
+
104
+ const askGoalName = ( ) => {
105
+ log ( 'Examples of goals: Learn, Read, Practice' ) ;
106
+ rl . question ( 'Goal Name: ' , ( name ) => {
107
+ if ( ! name ) {
108
+ log ( 'Goal name cannot be empty. Please try again.' ) ;
109
+ return askGoalName ( ) ;
110
+ }
111
+ askQuantity ( name ) ;
112
+ } ) ;
113
+ } ;
114
+
115
+ const askQuantity = ( name ) => {
116
+ log ( 'Please enter a positive number for the quantity.' ) ;
117
+ rl . question ( 'Quantity: ' , ( quantity ) => {
118
+ const quantityNum = parseInt ( quantity ) ;
119
+ if ( isNaN ( quantityNum ) || quantityNum <= 0 ) {
120
+ log ( 'Quantity must be a positive number. Please try again.' ) ;
121
+ return askQuantity ( name ) ;
122
+ }
123
+ askUnits ( name , quantityNum ) ;
124
+ } ) ;
125
+ } ;
126
+
127
+ const askUnits = ( name , quantity ) => {
128
+ log ( 'Examples of units: Books, Courses, Languages' ) ;
129
+ rl . question ( 'Units: ' , ( units ) => {
130
+ if ( ! units ) {
131
+ log ( 'Units cannot be empty. Please try again.' ) ;
132
+ return askUnits ( name , quantity ) ;
133
+ }
134
+ askDeadline ( name , quantity , units ) ;
135
+ } ) ;
136
+ } ;
137
+
138
+ const askDeadline = ( name , quantity , units ) => {
139
+ log ( 'Deadline must be a number between 1 and 12 months.' ) ;
140
+ rl . question ( 'Deadline (in months, max 12): ' , ( deadline ) => {
141
+ const deadlineNum = parseInt ( deadline ) ;
142
+ if ( isNaN ( deadlineNum ) || deadlineNum < 1 || deadlineNum > 12 ) {
143
+ log ( 'Deadline must be a number between 1 and 12. Please try again.' ) ;
144
+ return askDeadline ( name , quantity , units ) ;
145
+ }
146
+ goals . push ( { name, quantity, units, deadline : deadlineNum } ) ;
147
+ log ( 'Goal added!' ) ;
148
+ menu ( ) ;
149
+ } ) ;
150
+ } ;
151
+
152
+ const viewGoals = ( ) => {
153
+ if ( goals . length === 0 ) {
154
+ log ( 'No goals registered.' ) ;
155
+ } else {
156
+ log ( '\nGoals:' ) ;
157
+ goals . forEach ( ( goal , index ) => {
158
+ log ( `${ index + 1 } . ${ goal . name } - ${ goal . quantity } ${ goal . units } over ${ goal . deadline } months` ) ;
159
+ } ) ;
160
+ }
161
+ menu ( ) ;
162
+ } ;
163
+
164
+ const capitalizeFirstLetterOfEachWord = ( string ) => {
165
+ return string . split ( ' ' ) . map ( word => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) ) . join ( ' ' ) ;
166
+ } ;
167
+
168
+
169
+ const calculateDetailedYearPlan = ( ) => {
170
+ if ( goals . length === 0 ) {
171
+ log ( 'No goals to calculate.' ) ;
172
+ return menu ( ) ;
173
+ }
174
+
175
+ const plan = { } ;
176
+ goals . forEach ( goal => {
177
+ const totalTasks = goal . quantity ;
178
+ const totalMonths = goal . deadline ;
179
+ const monthlyGoal = Math . floor ( totalTasks / totalMonths ) ;
180
+ const remainder = totalTasks % totalMonths ;
181
+
182
+ for ( let month = 1 ; month <= totalMonths ; month ++ ) {
183
+ if ( ! plan [ month ] ) {
184
+ plan [ month ] = [ ] ;
185
+ }
186
+
187
+ // Calculate the number of tasks for the current month
188
+ let tasksForMonth = monthlyGoal ;
189
+ if ( month <= remainder ) {
190
+ tasksForMonth += 1 ; // Distribute the remainder tasks
191
+ }
192
+
193
+ const capitalizedGoalName = capitalizeFirstLetterOfEachWord ( goal . name ) ;
194
+ const capitalizeGoalUnits = capitalizeFirstLetterOfEachWord ( goal . units ) ;
195
+
196
+ plan [ month ] . push ( `${ capitalizedGoalName } (${ tasksForMonth } ${ capitalizeGoalUnits } /month). Total: ${ goal . quantity } . Deadline: ${ monthNames [ totalMonths - 1 ] } .` ) ;
197
+ }
198
+ } ) ;
199
+
200
+ log ( '\n--- Detailed Year Plan ---' ) ;
201
+ for ( let month = 1 ; month <= 12 ; month ++ ) {
202
+ log ( `${ monthNames [ month - 1 ] } :` ) ;
203
+ if ( plan [ month ] ) {
204
+ plan [ month ] . forEach ( ( item , index ) => {
205
+ log ( `[ ] ${ index + 1 } . ${ item } ` ) ;
206
+ } ) ;
207
+ } else {
208
+ log ( 'No goals for this month.' ) ;
209
+ }
210
+ }
211
+ menu ( ) ;
212
+ } ;
213
+
214
+ const exportPlan = ( ) => {
215
+ const plan = [ ] ;
216
+ goals . forEach ( goal => {
217
+ const monthlyGoal = Math . ceil ( goal . quantity / goal . deadline ) ;
218
+ for ( let month = 1 ; month <= goal . deadline ; month ++ ) {
219
+ plan . push ( `Month ${ month } : ${ goal . name } (${ monthlyGoal } ${ goal . units } /month). Total: ${ goal . quantity } .` ) ;
220
+ }
221
+ } ) ;
222
+
223
+ fs . writeFile ( filePath , plan . join ( '\n' ) , ( err ) => {
224
+ if ( err ) throw err ;
225
+ log ( `Plan exported to ${ filePath } ` ) ;
226
+ menu ( ) ;
227
+ } ) ;
228
+ } ;
229
+
230
+ const exitProgram = ( ) => {
231
+ log ( 'Exiting the program.' ) ;
232
+ rl . close ( ) ;
233
+ } ;
234
+
235
+ menu ( ) ;
236
+
237
+ /* Output example:
238
+
239
+ --- Detailed Year Plan ---
240
+ January:
241
+ [ ] 1. Learn Programing Languages (2 Languages/month). Total: 6. Deadline: April.
242
+ [ ] 2. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
243
+ [ ] 3. Practice Martial Arts (2 Kunfu Style/month). Total: 8. Deadline: April.
244
+ February:
245
+ [ ] 1. Learn Programing Languages (2 Languages/month). Total: 6. Deadline: April.
246
+ [ ] 2. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
247
+ [ ] 3. Practice Martial Arts (2 Kunfu Style/month). Total: 8. Deadline: April.
248
+ March:
249
+ [ ] 1. Learn Programing Languages (1 Languages/month). Total: 6. Deadline: April.
250
+ [ ] 2. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
251
+ [ ] 3. Practice Martial Arts (2 Kunfu Style/month). Total: 8. Deadline: April.
252
+ April:
253
+ [ ] 1. Learn Programing Languages (1 Languages/month). Total: 6. Deadline: April.
254
+ [ ] 2. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
255
+ [ ] 3. Practice Martial Arts (2 Kunfu Style/month). Total: 8. Deadline: April.
256
+ May:
257
+ [ ] 1. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
258
+ June:
259
+ [ ] 1. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
260
+ July:
261
+ [ ] 1. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
262
+ August:
263
+ [ ] 1. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
264
+ September:
265
+ [ ] 1. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
266
+ October:
267
+ [ ] 1. Read Fiction Books (1 Books/month). Total: 10. Deadline: November.
268
+ November:
269
+ [ ] 1. Read Fiction Books (0 Books/month). Total: 10. Deadline: November.
270
+ */
0 commit comments