#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define WIDTH 64 // OLED display width, in pixels
#define HEIGHT 128 // OLED display height, in pixels
Adafruit_SSD1306 display(128, 64, &Wire, -1);
static const unsigned char PROGMEM mantex_logo [] = {
0x00, 0x00, 0x18, 0x06, 0x01, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3c, 0x0f, 0x03, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x03, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x3f, 0x80, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x3e, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x7c, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x78, 0x7f, 0xff, 0xff, 0xe1, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf8, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xff, 0xff, 0xff, 0xf8, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xff, 0xff, 0xff, 0xfc, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x7f, 0xf1, 0xff, 0x0f, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf1, 0xfc, 0x01, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf1, 0xf0, 0x00, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x7f, 0xf1, 0xf0, 0x00, 0x7f, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x01, 0xf1, 0xe0, 0x70, 0x3f, 0xfc, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xe1, 0xf8, 0x3f, 0xfc, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xe1, 0xff, 0xff, 0xfc, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xe1, 0xff, 0xff, 0xfc, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xc1, 0xff, 0xff, 0xfc, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xe1, 0xe0, 0x07, 0xfc, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x7f, 0xf1, 0xe1, 0xe0, 0x01, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf1, 0xe1, 0xe0, 0x00, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf1, 0xe0, 0xe3, 0xf8, 0x7c, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x7f, 0xf1, 0xe0, 0x63, 0xfc, 0x7c, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x3f, 0xf1, 0xf0, 0x23, 0xfc, 0x3c, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xf8, 0x23, 0xfc, 0x3c, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xff, 0x63, 0xfc, 0x3c, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xff, 0xe3, 0xfc, 0x3c, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xff, 0xe3, 0xfc, 0x7c, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xff, 0xe3, 0xf8, 0x7c, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x7f, 0xf1, 0xff, 0xe1, 0xf0, 0x7c, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf1, 0xff, 0xe0, 0x00, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf1, 0xff, 0xe0, 0x03, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf1, 0xff, 0xe0, 0x1f, 0xfc, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x7f, 0xf1, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf1, 0xff, 0xff, 0xff, 0xf8, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf0, 0xff, 0xff, 0xff, 0xf8, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x78, 0x7f, 0xff, 0xff, 0xf0, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x7c, 0x1f, 0xff, 0xff, 0xc1, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x3c, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x3f, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x1f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3e, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3c, 0x0f, 0x83, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x3c, 0x0f, 0x01, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
const char pieces_S_l[2][2][4] = {{
{0, 0, 1, 1}, {0, 1, 1, 2}
},
{
{0, 1, 1, 2}, {1, 1, 0, 0}
}};
const char pieces_S_r[2][2][4]{{
{1, 1, 0, 0}, {0, 1, 1, 2}
},
{
{0, 1, 1, 2}, {0, 0, 1, 1}
}};
const char pieces_L_l[4][2][4] = {{
{0, 0, 0, 1}, {0, 1, 2, 2}
},
{
{0, 1, 2, 2}, {1, 1, 1, 0}
},
{
{0, 1, 1, 1}, {0, 0, 1, 2}
},
{
{0, 0, 1, 2}, {1, 0, 0, 0}
}};
const char pieces_Sq[1][2][4] = {{
{0, 1, 0, 1}, {0, 0, 1, 1}
}};
const char pieces_T[4][2][4] = {{
{0, 0, 1, 0},{0, 1, 1, 2}
},
{
{0, 1, 1, 2},{1, 0, 1, 1}
},
{
{1, 0, 1, 1},{0, 1, 1, 2}
},
{
{0, 1, 1, 2},{0, 0, 1, 0}
}};
const char pieces_l[2][2][4] = {{
{0, 1, 2, 3}, {0, 0, 0, 0}
},
{
{0, 0, 0, 0}, {0, 1, 2, 3}
}};
const short MARGIN_TOP = 19;
const short MARGIN_LEFT = 3;
const short SIZE = 5;
const short TYPES = 6;
#define SPEAKER_PIN 2
const int MELODY_LENGTH = 10;
const int MELODY_NOTES[MELODY_LENGTH] = {262, 294, 330, 262};
const int MELODY_DURATIONS[MELODY_LENGTH] = {500, 500, 500, 500};
int click[] = { 1047 };
int click_duration[] = { 100 };
int erase[] = { 2093 };
int erase_duration[] = { 100 };
word currentType, nextType, rotation;
short pieceX, pieceY;
short piece[2][4];
int interval = 20, score;
long timer, delayer;
boolean grid[10][18];
boolean b1, b2, b3;
int left=11;
int right=9;
int change=12;
int speed=10;
void checkLines(){
boolean full;
for(short y = 17; y >= 0; y--){
full = true;
for(short x = 0; x < 10; x++){
full = full && grid[x][y];
}
if(full){
breakLine(y);
y++;
}
}
}
void breakLine(short line){
tone(SPEAKER_PIN, erase[0], 1000 / erase_duration[0]);
delay(100);
noTone(SPEAKER_PIN);
for(short y = line; y >= 0; y--){
for(short x = 0; x < 10; x++){
grid[x][y] = grid[x][y-1];
}
}
for(short x = 0; x < 10; x++){
grid[x][0] = 0;
}
display.invertDisplay(true);
delay(50);
display.invertDisplay(false);
score += 10;
}
void refresh(){
display.clearDisplay();
drawLayout();
drawGrid();
drawPiece(currentType, 0, pieceX, pieceY);
display.display();
}
void drawGrid(){
for(short x = 0; x < 10; x++)
for(short y = 0; y < 18; y++)
if(grid[x][y])
display.fillRect(MARGIN_LEFT + (SIZE + 1)*x, MARGIN_TOP + (SIZE + 1)*y, SIZE, SIZE, WHITE);
}
boolean nextHorizontalCollision(short piece[2][4], int amount){
for(short i = 0; i < 4; i++){
short newX = pieceX + piece[0][i] + amount;
if(newX > 9 || newX < 0 || grid[newX][pieceY + piece[1][i]])
return true;
}
return false;
}
boolean nextCollision(){
for(short i = 0; i < 4; i++){
short y = pieceY + piece[1][i] + 1;
short x = pieceX + piece[0][i];
if(y > 17 || grid[x][y])
return true;
}
return false;
}
void generate(){
currentType = nextType;
nextType = random(TYPES);
if(currentType != 5)
pieceX = random(9);
else
pieceX = random(7);
pieceY = 0;
rotation = 0;
copyPiece(piece, currentType, rotation);
}
void drawPiece(short type, short rotation, short x, short y){
for(short i = 0; i < 4; i++)
display.fillRect(MARGIN_LEFT + (SIZE + 1)*(x + piece[0][i]), MARGIN_TOP + (SIZE + 1)*(y + piece[1][i]), SIZE, SIZE, WHITE);
}
void drawNextPiece(){
short nPiece[2][4];
copyPiece(nPiece, nextType, 0);
for(short i = 0; i < 4; i++)
display.fillRect(50 + 3*nPiece[0][i], 4 + 3*nPiece[1][i], 2, 2, WHITE);
}
void copyPiece(short piece[2][4], short type, short rotation){
switch(type){
case 0: //L_l
for(short i = 0; i < 4; i++){
piece[0][i] = pieces_L_l[rotation][0][i];
piece[1][i] = pieces_L_l[rotation][1][i];
}
break;
case 1: //S_l
for(short i = 0; i < 4; i++){
piece[0][i] = pieces_S_l[rotation][0][i];
piece[1][i] = pieces_S_l[rotation][1][i];
}
break;
case 2: //S_r
for(short i = 0; i < 4; i++){
piece[0][i] = pieces_S_r[rotation][0][i];
piece[1][i] = pieces_S_r[rotation][1][i];
}
break;
case 3: //Sq
for(short i = 0; i < 4; i++){
piece[0][i] = pieces_Sq[0][0][i];
piece[1][i] = pieces_Sq[0][1][i];
}
break;
case 4: //T
for(short i = 0; i < 4; i++){
piece[0][i] = pieces_T[rotation][0][i];
piece[1][i] = pieces_T[rotation][1][i];
}
break;
case 5: //l
for(short i = 0; i < 4; i++){
piece[0][i] = pieces_l[rotation][0][i];
piece[1][i] = pieces_l[rotation][1][i];
}
break;
}
}
short getMaxRotation(short type){
if(type == 1 || type == 2 || type == 5)
return 2;
else if(type == 0 || type == 4)
return 4;
else if(type == 3)
return 1;
else
return 0;
}
boolean canRotate(short rotation){
short piece[2][4];
copyPiece(piece, currentType, rotation);
return !nextHorizontalCollision(piece, 0);
}
void drawLayout(){
display.drawLine(0, 18, WIDTH, 18, WHITE);
display.drawRect(0, 0, WIDTH, HEIGHT, WHITE);
drawNextPiece();
char text[6];
itoa(score, text, 10);
drawText(text, getNumberLength(score), 7, 4);
}
short getNumberLength(int n){
short counter = 1;
while(n >= 10){
n /= 10;
counter++;
}
return counter;
}
void drawText(char text[], short length, int x, int y){
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw white text
display.setCursor(x, y); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
for(short i = 0; i < length; i++)
display.write(text[i]);
}
void bruh() {
pinMode(left, INPUT_PULLUP);
pinMode(right, INPUT_PULLUP);
pinMode(change, INPUT_PULLUP);
pinMode(speed, INPUT_PULLUP);
pinMode(SPEAKER_PIN, OUTPUT);
Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.setRotation(1);
display.clearDisplay();
display.drawBitmap(0, 0, mantex_logo, 64, 128, WHITE);
display.display();
delay(2000);
display.clearDisplay();
drawLayout();
display.display();
randomSeed(analogRead(0));
nextType = random(TYPES);
generate();
timer = millis();
}
boolean checkGameOver() {
for(short x = 0; x < 10; x++){
if(grid[x][0])
return true;
}
return false;
}
void setup() {
bruh();
}
void loop() {
if(millis() - timer > interval){
checkLines();
refresh();
if(nextCollision()){
for(short i = 0; i < 4; i++)
grid[pieceX + piece[0][i]][pieceY + piece[1][i]] = 1;
generate();
}else
pieceY++;
if(checkGameOver()){
// Game over condition met
// Stop updating game state
while(1) {
// display.clearDisplay();
// drawLayout();
// display.display();
display.setCursor(6, 11); // Start at middle of the screen
display.println(F("Game Over"));
display.display(); // Show initial text
}
return;
}
timer = millis();
}
if(!digitalRead(left)){
tone(SPEAKER_PIN, click[0], 1000 / click_duration[0]);
delay(100);
noTone(SPEAKER_PIN);
if(b1){
if(!nextHorizontalCollision(piece, -1)){
pieceX--;
refresh();
}
b1 = false;
}
}else{
b1 = true;
}
if(!digitalRead(right)){
tone(SPEAKER_PIN, click[0], 1000 / click_duration[0]);
delay(100);
noTone(SPEAKER_PIN);
if(b2){
if(!nextHorizontalCollision(piece, 1)){
pieceX++;
refresh();
}
b2 = false;
}
}else{
b2 = true;
}
if(!digitalRead(speed)){
interval = 20;
}else{
interval = 400;
}
if(!digitalRead(change)){
tone(SPEAKER_PIN, click[0], 1000 / click_duration[0]);
delay(100);
noTone(SPEAKER_PIN);
if(b3){
if(rotation == getMaxRotation(currentType) - 1 && canRotate(0)){
rotation = 0;
}else if(canRotate(rotation + 1)){
rotation++;
}
copyPiece(piece, currentType, rotation);
refresh();
b3 = false;
delayer = millis();
}
} else if(millis() - delayer > 50){
b3 = true;
}
}