Projekt zrealizowany w ramach przedmiotu "Techniki mikroprocesorowe" na 4 semestrze Automatyki i Robotyki na wydziale MEiL Politechniki Warszawskiej. Projekt został zrealizowany z pomocą sztucznej inteligencji tj. chatGPT 3.5
Autorzy projektu: Stanisław Walczak Hubert Przybysz
1. Płytka Arduino UNO
2. wyświetlacz oled 64x128 pikseli
3. "Game Console v0.2 beta"
4. kabel usb do arduino
Laptop lub komputer
Projekt realizuje uproszczoną wersję sapera. W ramach gry można wybierać pole, którego stan chce się zmienić lub podejrzeć. Po najechaniu na pole można zobaczyć jego stan tj. pole niezaznaczone, pole zaznaczone wraz z ilością bomb dookoła, pole oflagowane. Można to robić za pomocą 4 przycisków poruszając się między polami w górę, dół, lewo i w prawo. Pola można edytować na dwa sposoby: poprzez postawienie flagi, lub poprzez odkrycie pola.
W przeciwieństwie do zwykłego sapera pola nie odkrywają się same, to znaczy, że każde pole z osobna trzeba kliknąć, by odkryć wszystkie. Bomby generują się przed pierwszym ruchem gracza, więc można w pierwszym ruchu trafić na bombę. Bomby generują się w losowej ilości 25 do 35 na mapie 16 na 10 pól.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int t[16][10];
unsigned long lastMoveTime = 0;
int miny = 0;
int activeAreaX = 0;
int activeAreaY = 0;
void placeMines() {
randomSeed(analogRead(0)); // Inicjalizacja generatora liczb pseudolosowych
miny = random(25, 35); // Losowa liczba min w zakresie od 25 do 35
int minesPlaced = 0;
while (minesPlaced < miny) {
int x = random(10);
int y = random(16);
if (t[y][x] != 9) { // Sprawdzenie, czy na tym polu nie ma już miny
t[y][x] = 9; // Umieszczenie miny
minesPlaced++;
}
}
}
void calculateNumbers() {
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 10; j++) {
if (t[i][j] == 9) {
continue; // Pomijamy pola z minami
}
int count = 0;
// Sprawdzenie sąsiedztwa (8 pól dookoła)
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
int nx = j + dx;
int ny = i + dy;
if (nx >= 0 && nx < 10 && ny >= 0 && ny < 16 && t[ny][nx] == 9) {
count++;
}
}
}
t[i][j] = count; // Zapisujemy liczbę min w sąsiedztwie
}
}
}
void setup() {
Serial.begin(9600);
// Inicjalizacja ekranu OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("Nie udało się zainicjować wyświetlacza OLED"));
for(;;);
}
// Inicjalizacja tablicy
for (int i = 0; i < 16;i++) {
for (int j = 0; j < 10; j++) {
// Przykładowe wartości dla zmiennych typu int w tablicy
t[i][j] = 0; // Przykładowa wartość dla pierwszej zmiennej int
}
}
pinMode(8, INPUT_PULLUP); // Pin 8 - ruch w prawo
pinMode(7, INPUT_PULLUP); // Pin 7 - ruch w górę
pinMode(9, INPUT_PULLUP); // Pin 9 - ruch w dół
pinMode(10, INPUT_PULLUP); // Pin 10 - ruch w lewo
pinMode(4, INPUT_PULLUP); // Pin 4 - kliknięcie
pinMode(5, INPUT_PULLUP); // Pin 5 - flaga
// Odwrócenie wyświetlacza o 180 stopni
display.setRotation(2);
// Wyczyszczenie ekranu
display.clearDisplay();
// Rysowanie siatki
for (int i = 0; i < 17; i++) {
display.drawFastVLine(i *6, 0,10*6+1, WHITE); //linie pionowe
}
for (int j = 0; j < 11; j++) {
display.drawFastHLine(0, j * 6, 16*6+1, WHITE); //linie poziome
}
display.fillRect(0, 0, 7, 7, BLACK); //// pierwsze aktywne pole
// Wyświetlenie siatki
placeMines();
// Obliczenie liczby min w sąsiedztwie każdego pola
calculateNumbers();
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 16; j++) {
Serial.print(t[j][i]); // Wyświetl wartość elementu tablicy
Serial.print("\t"); // Dodaj tabulator po każdym elemencie
}
Serial.println(); // Przejdź do nowej linii po zakończeniu wiersza
}
moje(113,19,0);
displayTwoDigitNumber(112, 30, miny);
display.setCursor(112, 1);
// Wyświetl znak zapytania na ekranie
display.println('?');
display.display();
}
void loop() {
// Sprawdzenie ruchu w górę
if (millis() - lastMoveTime >= 250) {
if (digitalRead(8) == LOW) {
moveActiveArea(6, 0);
} else if (digitalRead(7) == LOW) {
moveActiveArea(0, -6);
} else if (digitalRead(9) == LOW) {
moveActiveArea(0, 6);
} else if (digitalRead(10) == LOW) {
moveActiveArea(-6, 0);
}else if (digitalRead(4) == LOW) {
if(t[activeAreaX/6][activeAreaY/6]<10)
{
t[activeAreaX/6][activeAreaY/6]+=10;
if(t[activeAreaX/6][activeAreaY/6]==19)
{
display.clearDisplay(); // Wyczyść ekran
display.setTextSize(2); // Ustaw rozmiar tekstu
display.setTextColor(WHITE); // Ustaw kolor tekstu (biały)
int x = 27;
int y = 20;
display.setCursor(x, y);
display.println("BOOM!!!");
display.display();
delay(3000000);
}
int xx = activeAreaX/6;
int yy = activeAreaY/6;
int zz = t[xx][yy];
displayOnesDigit(112,1,zz);
moje(113,19,1);
/*
}
*/
delay(50);
}
}else if (digitalRead(5) == LOW) {
if(t[activeAreaX/6][activeAreaY/6]<10)
{
t[activeAreaX/6][activeAreaY/6]+=20;
delay(50);
moje(113,19,2);
miny-=1;
displayTwoDigitNumber(112, 30, miny);
} else if (t[activeAreaX/6][activeAreaY/6]>19)
{
t[activeAreaX/6][activeAreaY/6]-=20;
moje(113,19,0);
miny+=1;
displayTwoDigitNumber(112, 30, miny);
delay(50);
}
}
}
/*
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 10; j++) {
Serial.print(t[i][j]); // Wyświetl wartość elementu tablicy
Serial.print("\t"); // Dodaj tabulator po każdym elemencie
}
Serial.println(); // Przejdź do nowej linii po zakończeniu wiersza
}
*/
delay(50);
}
void moveActiveArea(int deltaX, int deltaY) {
int xx = activeAreaX/6;
int yy = activeAreaY/6;
int zz = t[xx][yy];
Serial.println(xx);
Serial.println(yy);
Serial.println(zz);
int w = 0;
if(zz < 10)
{
w=0;
}
else if (zz<20)
{
w=1;
}
else
{
w=2;
}
moje(activeAreaX,activeAreaY,w);
// Clear previous active area
//Serial.println(activeAreaX);
activeAreaX += deltaX;
activeAreaY += deltaY;
activeAreaX = constrain(activeAreaX, 0, 90);
activeAreaY = constrain(activeAreaY, 0, 54);
// Draw new active area
display.fillRect(activeAreaX, activeAreaY, 7, 7, BLACK);
display.display();
xx = activeAreaX/6;
yy = activeAreaY/6;
zz = t[xx][yy];
if(zz < 10)
{
w=0;
}
else if (zz<20)
{
w=1;
}
else
{
w=2;
}
moje(113,19,w);
displayOnesDigit(112,1,zz);
lastMoveTime = millis();
}
void moje(int x, int y, int w)
{
display.drawRect(x, y, 7, 7, WHITE);
display.fillRect(x+1, y+1, 5, 5, BLACK);
if(w == 2)
{
display.fillRect(x+1, y+1, 1, 1, WHITE);
display.fillRect(x+2, y+2, 1, 1, WHITE);
display.fillRect(x+3, y+3, 1, 1, WHITE);
display.fillRect(x+4, y+4, 1, 1, WHITE);
display.fillRect(x+5, y+5, 1, 1, WHITE);
display.fillRect(x+2, y+5, 1, 1, WHITE);
display.fillRect(x+3, y+4, 1, 1, WHITE);
display.fillRect(x+4, y+2, 1, 1, WHITE);
display.fillRect(x+5, y+1, 1, 1, WHITE);
}
else if (w == 1)
{
display.drawRect(x+2, y+2, 3, 3, WHITE);
}
display.display();
}
void displayOnesDigit(int x, int y, int number) {
display.fillRect(x, y, 10, 18, BLACK);
if (number > 9 && number < 20) {
int onesDigit = number % 10; // Cyfra jedności danej liczby
// Ustaw rozmiar tekstu i kolor
display.setTextSize(2); // Rozmiar tekstu
display.setTextColor(WHITE); // Kolor tekstu
// Ustaw kursor tekstu na zadanych współrzędnych
display.setCursor(x, y);
// Wyświetl cyfrę jedności na ekranie
//display.println(String(onesDigit));
char buffer[1]; // Bufor na ciąg znaków
sprintf(buffer, "%d", onesDigit); // Formatuj liczbę do ciągu znaków
display.println(buffer); // Wyświetl bufor na ekranie OLED
} else {
// Ustaw rozmiar tekstu i kolor
display.setTextSize(2); // Rozmiar tekstu
display.setTextColor(WHITE); // Kolor tekstu
// Ustaw kursor tekstu na zadanych współrzędnych
display.setCursor(x, y);
// Wyświetl znak zapytania na ekranie
display.println('?');
}
display.display();
}
void displayTwoDigitNumber(int x, int y, int number) {
// Sprawdź czy liczba jest dwucyfrowa (od 10 do 99)
display.fillRect(x, y, 10, 50, BLACK);
if (number >= 10 && number <= 99) {
// Podziel liczbę na cyfry dziesiątek i jedności
int tens = number / 10;
int ones = number % 10;
// Ustaw rozmiar tekstu i kolor
display.setTextSize(2); // Rozmiar tekstu
display.setTextColor(WHITE); // Kolor tekstu
// Wyświetl cyfrę dziesiątek na górze
display.setCursor(x, y); // Ustaw kursor na pierwszej pozycji
char buffer[1]; // Bufor na ciąg znaków
sprintf(buffer, "%d", tens); // Formatuj liczbę do ciągu znaków
display.println(buffer); // Wyświetl bufor na ekranie OLED
// Wyświetl cyfrę jedności poniżej
display.setCursor(x, y + 20); // Ustaw kursor poniżej cyfry dziesiątek
sprintf(buffer, "%d", ones);
display.println(buffer); // Wyświetl bufor na ekranie OLED
}
else
{
int tens = 0;
int ones = number ;
// Ustaw rozmiar tekstu i kolor
display.setTextSize(2); // Rozmiar tekstu
display.setTextColor(WHITE); // Kolor tekstu
// Wyświetl cyfrę dziesiątek na górze
display.setCursor(x, y); // Ustaw kursor na pierwszej pozycji
char buffer[3]; // Bufor na ciąg znaków
sprintf(buffer, "%d", tens); // Formatuj liczbę do ciągu znaków
display.println(buffer); // Wyświetl bufor na ekranie OLED
// Wyświetl cyfrę jedności poniżej
display.setCursor(x, y + 20); // Ustaw kursor poniżej cyfry dziesiątek
sprintf(buffer, "%d", ones);
display.println(buffer); // Wyświetl bufor na ekranie OLED
}
display.display();
}