Rock, Paper, Scissors. Mi primer "proyecto". ¿Qué mejoraríais?

widim

Buenas, llevo 5 meses aprendiendo a programar y este es el primer "proyecto" (si es que se le puede llamar así) que hago, es un proyecto muy simple, lo sé, pero lo he hecho sin seguir ningún tutorial y aunque sea lo más simple del mundo me gustaría refinar el código al máximo.

En realidad he hecho tres proyectos aunque sean de lo mismo. El primero lo hice en Java, y lo podéis ver aquí:

https://paste.ofcode.org/r3pwmzwwtuGmtysucnyu8U

Aquí creo que podría haber usado enums en vez de las constantes, pero tampoco controlo demasiado las primeras. Le añadí un diccionario muy básico para usarlo como log de partidas. El código es procedural, podía haberlo hecho con clases, y quizá implementarle alguna interfaz para hacerlo más abstracto y bonito, pero no creo que me aporte demasiado.

El loop infinito que veis para iniciar el juego es un poco chapuza, pero bueno.

Por otra parte, hice lo mismo pero en JS y no tengo mucho que comentar. El primero creo que es un poco más chapucero y lo hice para experimentar un poco con el DOM, usando prototipos para probar un poco la herencia y tal.

https://jsitor.com/tMTEKq3_q

Y este último que lo terminé ayer, tampoco dista mucho del primero y este es 100% en la consola, aquí estuve probando las clases en JS.

https://jsitor.com/eeALszk5D (soy consciente de que hay un bug xD)

Acepto cualquier crítica y recomendación. Saludos!

2
Martita-

Simplemente es poner la palabra y te pone si ganas o no, no?

Yo pondria como una especie de loading, que salieran las 3 imagenes cargando, y al final se seleccionara una de las 3, y comparara con lo que has elegido tu, y en la pantalla final saliera la imagen que has elegido tu, y la que ha sacado la maquina, y el mensaje que ya sacas.

Si haces eso, pues te quedara algo mejor, ahora mismo solo es un dialog con un input y un texto.

1 1 respuesta
TheDamien

He ganado 3-1, me gusta.

1
widim

#2 Si. Pero yo me refería más a la parte del código. El diseño ya sé que es una mierda simple de narices XD

Gracias. Perdón si no se ha entendido bien el tema.

1 comentario moderado
widim

#5

Google no ha sabido apreciarlo al parecer...

ya he mandado mi portfolio con esto y una calculadora que suma, resta y multiplica a los de Discord. A ver si tengo mas suerte.

5
LLoid

aprende a utilizar git y sube el repositorio a github

el código pues es lo que es, no hay mucho que comentar xd

2 1 respuesta
Wei-Yu

Está bien, además estás cacharreando con clases también que eso al principio suele costar. Ahora es cosa de ir tirando más código y probando nuevas cosas.

Tampoco hay mucho que se pueda decir, pero dos cosas pequeñas que se me ocurieron, si tienes un if con un return no necesitas añadir el else, porque si el if se cumple nunca se ejecutará lo que viene detrás. Esto ayuda a que quites indentación que cuando se empiezan a acumular niveles de indentación se hace más difícil leer el código. Además de eso los valores con los que juegas (ROCK, PAPER, SCISSORS) los metería como constantes para que te los pille bien el IDE (sé que te autocompletará igualmente las palabras igualmente, pero mejor tenerlo a nivel de lenguaje y no de texto).

1 1 respuesta
Oscar03

Haz un monopoly, lo hice en un trabajo del grado superior en python y me sirvio mucho para aprender.

1
widim

#7 #8 Gracias, a ver, se que no hay mucho de donde sacar, pero es que tampoco tenia muchas ideas de qué hacer XD perdonad si el tema es un poco mierda

el codigo ya lo tengo subido a github, pero tampoco veia mucho sentido a ponerlo para estas cosas simples, por eso lo he puesto en esas paginas que es algo más "directo" de ver

entonces cómo lo harías? si tengo que retornar uno de tres posibles valores en una función

return DRAW / PLAYER / CPU

necesito un else para retornar al menos uno de ellos, de la otra forma sólo podría retornar dos, no? el que cumpla y luego el "default" por llamarlo de alguna forma.

if (winner === 'PLAYER') {
return 'PLAYER'
}

return 'COMPUTER'

}

qué hago con el 'DRAW' entonces?

con lo de las constantes tienes toda la razón, de hecho en Java lo hice así XD

1 respuesta
Puni

Haz versión Piedra, Papel, Tijera, Lagarto, Spock.

Verás que el código a base de ifs y switchs se vuelve un poco farragoso. Quizás te venga bien hacer algún tipo de "cuadrícula" donde tengas codificado quién gana a quién.

Si de repente te apetece implementar algo más complicado sería mucho más sencillo

3 1 respuesta
widim

#11 Joder, no lo he hecho, pero me lo estoy imaginando mentalmente y tiene pinta de que la funcion para computar el ganador puede llegar a convertirse en una montaña de mierda

Gracias, intentare hacerlo porque tiene buena pinta para escalar un poco el proyecto.

Aunque no tengo ni idea de qué te refieres con lo de la cuadrícula :/

1 respuesta
Wei-Yu

#10 Yo digo algo así:

function getWinner(player, cpu) {
  if (player === cpu)
    return 'DRAW';
  
if (player === 'ROCK' && cpu === 'SCISSORS' ||
    player === 'PAPER' && cpu === 'ROCK' ||
    player === 'SCISSORS' && cpu === 'PAPER') {
    return 'PLAYER';
  }

  return 'CPU';

}

Es un ejemplo tonto y casi puramente estilístico pero yo normalmente intento reducir ese tipo de cosas, pero al final a fuerza de leer encontrarás qué es más sencillo para ti a la larga (porque en poco código todo se encuentra rápido, pero cuando hay mucho hay detalles tontos que llevan menos carga cognitiva).

1 1 respuesta
widim

#13 Gracias. Pues fijate que si mal no recuerdo llegué a hacerlo justo así, pero no tenía claro qué era mejor. Yo la verdad que veo más claro el hacer un

if (player === cpu) {
return 'DRAW'
} else if (todas las condicionales..) {
return 'PLAYER'
}
return 'CPU'

Dentro de mi cabeza, meter tantos if "sueltos" me da un poco de toc. Pero vaya, que llevo 5 meses programando, yo no tengo ni idea de nada aún XD y si dices que evitando ese else if, es más legible, te haré caso

Gracias de nuevo

Puni

#12 Por cuadrícula quería decir un array bidimensional. Es un clásico ejemplo de algo que puedes dibujar de forma muy clara en papel en una tabla de doble entrada, vamos, un array bidimensional, en el que codifiques qué gana y qué pierde.

1
ReloaD1010

En JS se puede optimizar esto muy facilmente con un objeto:

const weakness = {
  'ROCK': 'SCISSORS',
  'PAPER': 'ROCK',
  'SCISSORS': 'PAPER'
}
  determineWinner(cpu, player) {
    if (cpu === player) {
      return 'DRAW';
    } else if (weakness[player] === cpu) {
      return 'PLAYER';
    }

return 'CPU';
  }

Ese metodo ya no creceria nunca, aunque le metieses los casos de spock como te han puesto arriba.
Y sobre todo te recomiendo usar y destructurar objetos en los parametros de las funciones para saber que son. En typescript aun te puedes salvar, pero en JS es facil perder el hilo.
E.g.:

  constructor({isComputer} = {isComputer: false}) {
    ...
  }
  ...
  this.cpu = new Player({isComputer: true});
1 1 respuesta
widim

#16 Gracias!

Una cosa, podrías pasarme algún link de documentación donde expliquen lo de deconstruir objetos? Lo he intentado buscar y no consigo dar con ello. Se que se puede hacer algo parecido con arrays, pero con objetos no tenía ni idea.

No consigo comprender la syntax que usas ahí, y me vendría bien estudiarlo, que usar un new Player(true) sí que es cierto que es bastante chapucero.

Editado: Vale, nada, ya lo he encontrado creo. Voy a echarle un ojo porque como digo no me entero de qué está pasando ahí XD

ReloaD1010

es un poco criptico poner default values directamente en el constructor en JS. Si usases typescript seria un poco mas intuitivo ya que puedes definir la interfaz en otro lado y se diferencia con lo que es la instancia. P. eg:

interface PlayerConfig {
  isComputer: boolean;
}

class Player {
  constructor({isComputer}: PlayerConfig = {isComputer: false}) {}
}

Mira esta imagen: https://imgur.com/a/ioqfEr6
Lo azul es la definicion del objeto. Ahi es donde estas destructurandolo, solo demuestras su estructura.
Lo verde es un objeto anonimo. Puedes utilizar otro definido previamente y funcionara igual. Se usara ese valor cuando no hayas pasado nada al constructor.
Otro ejemplo de como se podria hacer lo mismo pero sin objetos anonimos:

const defaultConfig = {isComputer: false};
class Player {
  constructor({isComputer} = defaultConfig) {
    this.isComputer = isComputer;
  }
}

Y la magia de JS reside en su flexibilidad. Puedes utilizar fallbacks con el operador OR.

class Player {
  constructor({isComputer}) {
    this.isComputer = isComputer || false;
  }
}

En este caso, si omites isComputer, seria undefined, asi que en la asignacion dentro del constructor iria a la parte de la derecha.

1 respuesta
JuAn4k4

#18 isComputer ?? false.

1 respuesta
ReloaD1010

#19 se lo quise poner un poco mas explicito, creo que si esta empezando el OR es mas intuitivo.
Con el nullish coalescing operator no añades ninguna informacion en este caso. Si quisieras simplificarlo seria mas conveniente la doble negacion, pero dale tiempo al muchacho.

this.isComputer = !!isComputer;

Usuarios habituales

  • ReloaD1010
  • JuAn4k4
  • widim
  • Puni
  • Wei-Yu
  • Helzid
  • TheDamien