Skip to content

Commit 6ebe0de

Browse files
authored
Merge pull request #7508 from Kenysdev/46_50.js
#46 - javascript -> #50
2 parents 079b45e + d67fb8c commit 6ebe0de

File tree

5 files changed

+853
-0
lines changed

5 files changed

+853
-0
lines changed
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
_____________________________________
3+
https://github.com/kenysdev
4+
2024 - JavaScript
5+
_______________________________________________________
6+
#46 X VS BLUESKY
7+
-------------------------------------------------------
8+
* EJERCICIO:
9+
* La alternativa descentralizada a X, Bluesky, comienza a atraer
10+
* a nuevos usuarios. ¿Cómo funciona una red de este estilo?
11+
*
12+
* Implementa un sistema que simule el comportamiento de estas
13+
* redes sociales.
14+
*
15+
* Debes crear las siguientes operaciones:
16+
* - Registrar un usuario por nombre e identificador único.
17+
* - Un usuario puede seguir/dejar de seguir a otro.
18+
* - Creación de post asociado a un usuario. Debe poseer
19+
* texto (200 caracteres máximo), fecha de creación
20+
* e identificador único.
21+
* - Eliminación de un post.
22+
* - Posibilidad de hacer like (y eliminarlo) en un post.
23+
* - Visualización del feed de un usuario con sus 10 publicaciones
24+
* más actuales ordenadas desde la más reciente.
25+
* - Visualización del feed de un usuario con las 10 publicaciones
26+
* más actuales de los usuarios que sigue ordenadas
27+
* desde la más reciente.
28+
*
29+
* Cuando se visualiza un post, debe mostrarse:
30+
* ID de usuario, nombre de usuario, texto del post,
31+
* fecha de creación y número total de likes.
32+
*
33+
* Controla errores en duplicados o acciones no permitidas.
34+
*/
35+
// ________________________________________________________
36+
const { format } = require('util');
37+
38+
const log = {
39+
info: (message, ...args) => console.log(`[INFO] ${format(message, ...args)}`),
40+
warning: (message, ...args) => console.warn(`[WARN] ${format(message, ...args)}`),
41+
error: (message, ...args) => console.error(`[ERROR] ${format(message, ...args)}`),
42+
};
43+
44+
class Posts {
45+
constructor() {
46+
this.__post_dt = {};
47+
}
48+
49+
__verifyPost(idUser, idPost, nameFunc) {
50+
if (!(idUser in this.__post_dt)) {
51+
log.error("'%s': El ID %s no tiene posts.", nameFunc, idUser);
52+
return false;
53+
}
54+
55+
if (!(idPost in this.__post_dt[idUser])) {
56+
log.error("'%s': El Post (%s) no existe.", nameFunc, idPost);
57+
return false;
58+
}
59+
60+
return true;
61+
}
62+
63+
createPost(idUser, content) {
64+
if (content.length > 200) {
65+
log.error("'createPost': content > 200 caracteres.");
66+
return;
67+
}
68+
69+
if (!(idUser in this.__post_dt)) {
70+
this.__post_dt[idUser] = {};
71+
}
72+
73+
const idPost = Object.keys(this.__post_dt[idUser]).length + 1;
74+
this.__post_dt[idUser][idPost] = {
75+
content,
76+
timestamp: new Date(),
77+
likes: new Set(),
78+
};
79+
80+
log.info("El ID %s creó un post(ID: %s).", idUser, idPost);
81+
}
82+
83+
deletePost(idUser, idPost) {
84+
if (this.__verifyPost(idUser, idPost, "deletePost")) {
85+
delete this.__post_dt[idUser][idPost];
86+
log.info("El post: %s de usuario: %s ha sido eliminado.", idPost, idUser);
87+
}
88+
}
89+
90+
likePost(idUser, idAuthor, idPost) {
91+
if (this.__verifyPost(idAuthor, idPost, "likePost")) {
92+
this.__post_dt[idAuthor][idPost].likes.add(idUser);
93+
log.info("El usuario %s dio like al post %s de usuario %s.", idUser, idPost, idAuthor);
94+
}
95+
}
96+
97+
removeLike(idUser, idAuthor, idPost) {
98+
if (this.__verifyPost(idAuthor, idPost, "removeLike")) {
99+
this.__post_dt[idAuthor][idPost].likes.delete(idUser);
100+
log.info("El usuario %s anuló el like al post %s de usuario %s.", idUser, idPost, idAuthor);
101+
}
102+
}
103+
104+
getRecentPosts(idUser, limit = 10) {
105+
if (idUser in this.__post_dt) {
106+
const sortedPosts = Object.values(this.__post_dt[idUser])
107+
.sort((a, b) => b.timestamp - a.timestamp);
108+
109+
return sortedPosts.slice(0, limit);
110+
}
111+
112+
return [];
113+
}
114+
}
115+
116+
class Users {
117+
constructor() {
118+
this.__users_dt = {};
119+
}
120+
121+
__idExists(id, nameFunc = "") {
122+
if (id in this.__users_dt) {
123+
return true;
124+
}
125+
126+
log.warning("'%s': ID: %s no encontrada.", nameFunc, id);
127+
return false;
128+
}
129+
130+
addUser(name) {
131+
const id = Object.keys(this.__users_dt).length + 1;
132+
this.__users_dt[id] = {
133+
name,
134+
following: new Set(),
135+
followers: new Set(),
136+
};
137+
138+
log.info("Usuario %s-%s registrado.", id, name);
139+
}
140+
141+
followUser(id, toId) {
142+
if (this.__idExists(id, "followUser") && this.__idExists(toId, "followUser")) {
143+
this.__users_dt[id].following.add(toId);
144+
this.__users_dt[toId].followers.add(id);
145+
log.info("ID: %s está siguiendo a ID: %s.", id, toId);
146+
}
147+
}
148+
149+
unfollowUser(id, toId) {
150+
if (this.__idExists(id, "unfollowUser") && this.__idExists(toId, "unfollowUser")) {
151+
this.__users_dt[id].following.delete(toId);
152+
this.__users_dt[toId].followers.delete(id);
153+
log.info("El ID: %s dejó de seguir al ID: %s.", id, toId);
154+
}
155+
}
156+
157+
getName(idUser) {
158+
if (this.__idExists(idUser, "getName")) {
159+
return this.__users_dt[idUser].name;
160+
}
161+
162+
return "";
163+
}
164+
}
165+
166+
// ________________________________________________________
167+
class Program {
168+
constructor(posts, users) {
169+
this.__posts = new posts();
170+
this.__users = new users();
171+
}
172+
173+
__printFeed(idUser) {
174+
const name = this.__users.getName(idUser);
175+
if (!name) {
176+
console.log(`Usuario ID: ${idUser} no encontrado.`);
177+
return;
178+
}
179+
180+
const last10 = this.__posts.getRecentPosts(idUser, 10);
181+
console.log(`\nFeed\n_______\nID: '${idUser}' - Nombre: '${name}'`);
182+
if (last10.length === 0) {
183+
console.log("No tiene publicaciones.");
184+
return;
185+
}
186+
187+
last10.forEach(post => {
188+
console.log(`_______\n${post.content}`);
189+
console.log(`Creado: '${post.timestamp}'`);
190+
console.log(`Likes: '${post.likes.size}'`);
191+
});
192+
}
193+
194+
run() {
195+
// CLI
196+
}
197+
198+
tests() {
199+
this.__users.addUser("Ken"); // id=1
200+
this.__users.addUser("Zoe"); // id=2
201+
202+
this.__users.followUser(1, 2);
203+
this.__users.followUser(2, 1);
204+
this.__users.unfollowUser(2, 1);
205+
206+
this.__posts.createPost(2, "Primer post."); // id=1
207+
this.__posts.createPost(2, "Segundo post."); // id=2
208+
this.__posts.deletePost(2, 2);
209+
this.__posts.createPost(2, "Otro post."); // id=2
210+
this.__posts.likePost(1, 2, 1);
211+
this.__posts.removeLike(1, 2, 1);
212+
this.__posts.likePost(1, 2, 2);
213+
214+
this.__printFeed(2);
215+
this.__printFeed(1);
216+
}
217+
}
218+
219+
// _______________________________________
220+
const program = new Program(Posts, Users);
221+
program.tests();
222+
// program.run();
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
_____________________________________
3+
https://github.com/kenysdev
4+
2024 - JavaScript
5+
_______________________________________________________
6+
#47 CALENDARIO DE ADVIENTO
7+
-------------------------------------------------------
8+
* EJERCICIO:
9+
* ¡Cada año celebramos el aDEViento! 24 días, 24 regalos para
10+
* developers. Del 1 al 24 de diciembre: https://adviento.dev
11+
*
12+
* Dibuja un calendario por terminal e implementa una
13+
* funcionalidad para seleccionar días y mostrar regalos.
14+
* - El calendario mostrará los días del 1 al 24 repartidos
15+
* en 6 columnas a modo de cuadrícula.
16+
* - Cada cuadrícula correspondiente a un día tendrá un tamaño
17+
* de 4x3 caracteres, y sus bordes serán asteríscos.
18+
* - Las cuadrículas dejarán un espacio entre ellas.
19+
* - En el medio de cada cuadrícula aparecerá el día entre el
20+
* 01 y el 24.
21+
*
22+
* Ejemplo de cuadrículas:
23+
* **** **** ****
24+
* *01* *02* *03* ...
25+
* **** **** ****
26+
*
27+
* - El usuario seleccioná qué día quiere descubrir.
28+
* - Si está sin descubrir, se le dirá que ha abierto ese día
29+
* y se mostrará de nuevo el calendario con esa cuadrícula
30+
* cubierta de asteríscos (sin mostrar el día).
31+
*
32+
* Ejemplo de selección del día 1
33+
* **** **** ****
34+
* **** *02* *03* ...
35+
* **** **** ****
36+
*
37+
* - Si se selecciona un número ya descubierto, se le notifica
38+
* al usuario.
39+
*/
40+
// ________________________________________________________
41+
42+
const readlineSync = require('readline-sync');
43+
44+
let mtx = [];
45+
for (let i = 0; i < 4; i++) {
46+
let row = [];
47+
for (let j = 0; j < 6; j++) {
48+
row.push(`*${(i * 6 + j + 1).toString().padStart(2, '0')}*`);
49+
}
50+
mtx.push(row);
51+
}
52+
53+
const ln = "**** ".repeat(6) + "\n";
54+
55+
function printMatrix() {
56+
mtx.forEach(row => {
57+
console.log(ln + row.join(" ") + "\n" + ln);
58+
});
59+
}
60+
61+
while (true) {
62+
printMatrix();
63+
64+
let day = readlineSync.question("A descubrir: ");
65+
66+
if (day.match(/^\d+$/) && parseInt(day) > 0 && parseInt(day) <= 24) {
67+
let r = Math.floor((parseInt(day) - 1) / 6);
68+
let c = (parseInt(day) - 1) % 6;
69+
70+
if (mtx[r][c] === "****") {
71+
console.log(`El día ${day} ya está descubierto.`);
72+
} else {
73+
mtx[r][c] = "****";
74+
}
75+
} else {
76+
console.log("Día inválido, debe ser entre 1 y 24.");
77+
}
78+
}

0 commit comments

Comments
 (0)