Tabla de contenido:

Mastermind Game en VHDL: 3 pasos
Mastermind Game en VHDL: 3 pasos

Video: Mastermind Game en VHDL: 3 pasos

Video: Mastermind Game en VHDL: 3 pasos
Video: Mastermind Game on Basys3 2024, Mes de julio
Anonim
Mastermind Game en VHDL
Mastermind Game en VHDL
Mastermind Game en VHDL
Mastermind Game en VHDL

Para nuestro proyecto, creamos el juego "Mastermind" en VHDL para jugar en el tablero Basys3. Mastermind es un juego de descifrar códigos que se juega tradicionalmente con clavijas y un tablero de juego. El jugador uno coloca clavijas de colores variados en una fila de 4, escondidas del jugador dos. El jugador dos tiene "x" número de intentos colocando clavijas en el tablero en una fila visible para el jugador uno. Después de cada intento, al jugador dos se le informan 2 números: cuántas clavijas son del color correcto y cuántas clavijas están en la posición correcta en la fila. Usando esas pistas, el jugador dos debe adivinar la secuencia correcta de pines que el jugador uno colocó en el número asignado.

En nuestra implementación, el juego es para un solo jugador. El programa genera una combinación aleatoria de clavijas, y el jugador debe usar el tablero Basys3 para adivinar la secuencia correcta. Hay cuatro "colores", representados por valores binarios. La pantalla de 7 segmentos muestra tres valores: vueltas restantes, número de pines en la posición correcta y número de pines que son del color correcto en la posición incorrecta (estos valores comienzan en 9, 0 y 0). El jugador usa los interruptores en el tablero para seleccionar los valores binarios para su conjetura y acciona otro interruptor para enviar la conjetura. Si son correctos, el juego termina y la pantalla de 7 segmentos muestra "GG". De lo contrario, el contador de turnos disminuye en 1 y el jugador recibe información basada en cuántos pines en su conjetura coinciden con el color o la posición de los pines en la combinación. Si el jugador se queda sin turnos sin adivinar correctamente, la pantalla muestra "GO" (que representa el fin del juego). El jugador también puede activar el interruptor de reinicio para comenzar de nuevo en cualquier momento.

Paso 1: Materiales

Materiales
Materiales
Materiales
Materiales
Materiales
Materiales

Dado que todo el juego se puede jugar en el tablero, los únicos materiales necesarios son el tablero Basys3, un cable micro USB para conectar al tablero y una computadora / computadora portátil que puede usar para codificar.

Paso 2: el código

El código
El código
El código
El código

Para que este juego funcione en FPGA, la forma más sencilla de escribirlo sería crear una máquina de estado. Tener una máquina de estado permite la experiencia secuencial e interactiva necesaria para que el juego realmente funcione. Para que todo funcione sin problemas, la máquina de estado se basará en la señal del reloj interno de la FPGA, asegurando que todo esté sincronizado. El módulo principal es una máquina de estados con cuatro estados; Estado inicial (inicial), estado SubmitAnswer (SubAns), estado de visualización (Dis) y estado CheckEndGame (CheckEnd). Junto con la máquina de estado, el módulo principal tiene dos submódulos, una pantalla de siete segmentos de 4 dígitos (que tiene su propio submódulo ClkDivider) y el generador de números aleatorios (en realidad, un generador de números pseudoaleatorios). También hay un bloque de proceso básico para que los LED sobre cada interruptor se enciendan cuando se encienden como una forma de que las personas vean lo que están ingresando más fácilmente. Se puede ver una descripción básica del código en el mapa mental que se muestra en la imagen.

El primer componente a tener en cuenta es el generador de números aleatorios (randomgen). Dado que técnicamente no es posible obtener verdaderos números aleatorios generados a partir del hardware, la solución más simple fue hacer que el gen aleatorio fuera realmente un Registro de cambio de retroalimentación lineal (LFSR). El LFSR tiene una entrada de clk y una salida "a" (un número de 12 bits). Cada ciclo de reloj, se genera un nuevo número de 12 bits a partir de "000000000001", que eventualmente pasa por todas las combinaciones de 12 bits de unos y ceros antes de repetirse. La salida "a" se da en cada ciclo de reloj, por lo que se ejecuta continuamente en todo momento. El clk se asigna al Clk desde el módulo principal, y "a" se asigna a la señal RandNum en el módulo principal.

El segundo submódulo es la pantalla de siete segmentos de 4 dígitos. Esta es una forma bastante sencilla de mostrar una pantalla de siete segmentos de 4 dígitos. La pantalla se establece en Clk desde el módulo principal, sin embargo, este submódulo tiene su propio submódulo de ClkDivider. El ClkDivider (configurado en 1298 Hz) se usa para acelerar el reloj del Siete Segmentos para que todos los dígitos parezcan estar activados al mismo tiempo (ya que solo un dígito puede estar activado a la vez). La variable “dígito” se usa para recorrer los puntos en la pantalla, y con cada dígito vienen las condiciones de una pantalla de entrada básica de 4 bits, con opciones para mostrar los dígitos del 0 al 9 y tampoco nada. El dígito más a la izquierda en la pantalla no se establece en nada, ya que no se usa en este juego.

El módulo principal consta de la máquina de estado. Los cuatro estados del proceso son Inicial, SubAns, Dis y CheckEnd. Cuando está en el estado inicial, si SubmitBtn (interruptor utilizado para enviar su respuesta para verificación) está configurado en "1", entonces la máquina pasa al estado SubAns. Siempre que Rbtn (interruptor utilizado para restablecer la máquina) se establece en "1", la máquina vuelve al estado inicial. Cuando se encuentra en el estado SubAns, cuando SubmitBtn = "0" nuevamente, pasa al estado Dis. Cuando está en el estado Dis, si la cuenta regresiva = 0 (los giros a la izquierda para adivinar caen a 0) o si el RSpotCount = 4 (es decir, el jugador tiene todos los colores correctos en los lugares correctos), la máquina pasa al estado CheckEnd. Si no ocurre ninguno de estos, cuando SubmitBtn = "1" nuevamente, vuelve al estado SubAns para permitir otra conjetura. Cuando esté en el estado CheckEnd, este es el final del juego, y la única salida es presionar el reinicio, devolviéndolo al estado inicial. Esto se puede ver fácilmente en el diagrama de la máquina de estado. Desde el punto de vista del comportamiento, el estado inicial inicializa todo de nuevo a la posición inicial. La cuenta regresiva (señal que guarda cuántos giros le quedan al jugador) se establece en 9, RSpotCount (señal que guarda cuántos de los colores que adivinaste están en el lugar correcto) se establece en 0, RColorCount (señal que guarda cuántos de los colores que adivinó son correctos pero en el lugar equivocado) se establece en 0, y la pequeña cuenta regresiva (señal que finalmente se asigna a Countdown que en realidad cambia cada turno en estados posteriores) se establece en 9. Además, en el estado inicial, el RandNum (número generado pseudoaleatorio) se divide en cuatro controles diferentes (uno para cada color de 3 bits) y se guarda en las señales check1, check2, check3, check4. Estas verificaciones son con lo que realmente se compara su conjetura, por lo que, aunque el LFSR siempre hace que RandNum cambie en cada ciclo, una vez que abandona el estado inicial, las verificaciones permanecen iguales, lo que permite comparar un valor guardado con su respuesta. Esto también significa que cada vez que se reinicia la máquina, el jugador tiene un nuevo valor para adivinar.

El estado SubmitAnswer (SubAns) cambia el habilitador de cuenta regresiva (señal de "cambio") a "1". Esto es necesario más adelante para que funcione el seguimiento de turnos. Después de eso, el estado compara las entradas del jugador de los interruptores con las comprobaciones realizadas en el estado anterior. La señal rs1, rs2, rs3, rs4 y las señales rc1, rc2, rc3, rc4 son tipos enteros que, dependiendo de las declaraciones If, se establecen en 1 o 0. La señal rs es para el punto correcto y rc para el color correcto. Por ejemplo, si el color 1 que adivina el jugador es igual al check1 del RandNum, entonces rs1 = 1 ya que eso significa que el color correcto está en el lugar correcto. Si el color 1 no es igual a check1, pero es igual a uno de los otros controles, entonces rc = 1. Esto se hace para cada color y cada control.

El estado de visualización (Dis) primero busca el habilitador de cuenta atrás. Si es "1", la cuenta regresiva baja 1 (por lo tanto, en el primer turno pasa de 9 a 8, etc.). De lo contrario, el turno no cambia. Independientemente de esa habilitación, todos los valores de rs de arriba se suman y se asignan a la señal RSpotCounter. Además, todos los valores rc se agregan y asignan al RColorCounter. Finalmente, a Countdown se le asigna el valor de pequeña cuenta atrás. Las señales RSpotCounter, RColorCounter y Countdown se convierten en std_logic_vectors de 4 bits fuera del proceso y se envían al submódulo de visualización de siete segmentos a través de un mapa de puertos. De esta manera, la pantalla muestra las cosas correctas hasta que envíe una nueva respuesta.

El estado CheckEnd es para saber si ha ganado o perdido. Si ha ganado (los 4 colores están en el lugar correcto, también conocido como RSpotCounter = 4), entonces "GG" (que se muestra técnicamente como 66) se muestra en el segmento de siete para mostrar que ha ganado. Si ha perdido (la cuenta regresiva ha llegado a 0), entonces "GO" (que se muestra técnicamente como 60) se muestra en la pantalla para Game Over. Con cualquiera de los resultados, al presionar el interruptor de reinicio en la posición de encendido, la máquina volverá al estado inicial para volver a jugar.

El código fuente se puede encontrar aquí.

Paso 3: Conclusión

Completar este proyecto nos enseñó mucho sobre la construcción de circuitos más complicados. Nuestro diseño inicial no era una máquina de estados finitos. Nos resultó difícil depurarlo y reescribimos el código varias veces utilizando diferentes métodos (incluido un FSM). Por sugerencia del instructor, seguimos con el enfoque de FSM y pudimos terminar el juego. Aprendimos que es mucho más efectivo diseñar el código basado en el hardware que con un enfoque de programación tradicional. También enfrentamos varios desafíos relacionados con la pantalla de siete segmentos. Lograr que mostrara varios números sin "imágenes fantasma" fue difícil, y tuvimos que usar un divisor de reloj para lograrlo. Si tuviéramos que desarrollar más este proyecto, conectaríamos LED de colores al Basys3 para que el usuario pueda ver colores (como en el juego tradicional) en lugar de representaciones numéricas de colores. En última instancia, obtuvimos una mayor comprensión del diseño de circuitos complejos, las aplicaciones de la vida real y los desafíos de usar hardware en lugar de ejecutar simulaciones en condiciones perfectas.

Recomendado: