2024-04-23 20:51:02 -05:00

218 lines
4.3 KiB
C

/*
* final_project.c
*
* Created: 4/3/2024 10:08:56 AM
* Author : bsw9xd
*/
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdbool.h>
#include "serial.h"
#include "clock.h"
volatile int seconds_remaining; //will be used by ISR
#define SPEAKER_PORT PORTE
#define SPEAKER_PIN 4 //rename?
#define ELEMENT_COUNT 7
//TODO get_button and display_element unnecessarily complex
uint8_t get_button() {
if(~PINE & (1 << 6)) return (1 << 2);
return ((~PINA) & ~(0b1100)); //TODO clean up
}
void display_element(uint8_t element, unsigned int time) {
uint8_t portd_state = 0;
uint8_t porte_state = 0;
if(element & (1 << 2)) porte_state = (1<<5);
portd_state = element & ~(0b1100);
PORTD ^= portd_state;
PORTE ^= porte_state;
beep(329.63, .25);
_delay_ms(time * 1000);
PORTD ^= portd_state;
PORTE ^= porte_state;
}
void init_io() {
DDRA = 0x00;
PORTA = 0xff;
DDRD = 0xff;
PORTD = 0xff;
DDRE = (1 << 4) | (1 << 5);
PORTE = 0xff;
}
void test_timer() {
for(;;) {
usart_txstr("timer test\n");
start_timer();
while(!timer_done());
stop_timer();
}
}
int main(void) {
cli();
timer_init_ctc();
init_io();
usart_init();
while(1) {
int level = 0;
//get level
usart_txstr(
"SIMON GAME\n"
"Enter your starting difficulty level:\n"
"1. Easy\n"
"2. Moderate\n"
"3. Give me pain.");
while((level > 3) || (level < 1)) level = (int)(usart_rxt_blocking() - '0');
//main simon game
while(level < 3) {
int display_time;
int sets;
int response_time;
int elements_min;
int elements_max;
double score;
uint8_t element_list[5]; // TODO
switch(level) {
case 1:
sets = 3;
display_time = 3;
response_time = 5;
elements_min = 3;
elements_max = 5;
break;
case 2:
sets = 4;
display_time = 2;
response_time = 7;
elements_min = 3;
elements_max = 10;
break;
case 3:
sets = 5;
display_time = 1;
response_time = 10;
elements_min = 5;
elements_max = 15;
break;
}
//main level
int max_score = 0;
int current_score = 0;
for(int set = 0; set < sets; set++) {
int elements = elements_min + ceil(((elements_max - elements_min) / (float)(sets - 1)) * set);
//generate, display elements
for(int element = 0; element < elements; element++) {
uint8_t element_bit = (rand() % ELEMENT_COUNT);
if(element_bit == 3) element_bit = 7;
uint8_t this_element = 1 << element_bit;
usart_txt('\n');
usart_txt(element_bit + '0');
usart_txt('\n');
element_list[element] = this_element; // could optimize
display_element(this_element, display_time);
}
//get elements
seconds_remaining = response_time;
start_timer();
uint16_t guess;
for(int element = 0; element < elements; element++) {
usart_txstr("\ngot element, waiting...\n");
do {
if(timer_done()) {
seconds_remaining--;
stop_timer(); //TODO only need one function
start_timer();
beep(261.63, .1);
}
else { guess = get_button(); }
} while((!guess) && (seconds_remaining > 0));
_delay_ms(250); //prevent double press
max_score++;
if(guess == element_list[element]) {
current_score++;
correct_beep();
}
else {
incorrect_beep();
}
}
}
score = (float)current_score / max_score;
if(score >= .8) {
level++;
usart_txstr("\nnext level\n");
}
else {
loose();
break;
}
}
if(level >= 3) win();
}
}
//timer interrupt
ISR(TIMER1_COMPA_vect) {
if(seconds_remaining-- > 0) return;
for(;;) {
beep();
}
}
void correct_beep() {
usart_txstr("\nCorrect!\n");
beep(440.0, .1);
}
void incorrect_beep() {
usart_txstr("\nIncorrect guess.\n");
beep(261.62, .2);
_delay_ms(25);
beep(261.62, .2);
}
void win() {
usart_txstr("\nYou beat the game!\n");
beep(262., .5);
beep(392., .5);
}
void loose() {
usart_txstr("\nYou loose, try again?\n");
beep(330., .5);
beep(294., .5);
}
//TODO move somewhere else
void beep(double frequency, double durientation) {
double speaker_ms = ((1.0 / frequency) / 2.0) * 1000.0; //TODO clean up
int loop_count = durientation / (1.0 / frequency);
for(unsigned int i = 0; i < loop_count; i++) {
_delay_ms(speaker_ms);
SPEAKER_PORT ^= (1 << SPEAKER_PIN);
}
}