#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <avr/pgmspace.h>
#include "sprites.h" // all sprites are here
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define LEFT 3
#define RIGHT 5
#define ENTER 7
byte PR_INPUT = 0;
static const uint8_t width = 16;
static const uint8_t height = 32;
uint16_t board[height];
uint8_t plX = 6;
uint8_t plY = 28;
uint8_t shape_id = 0;
uint8_t shape_rot = 0;
uint8_t next_shape_id = 0;
const uint16_t period = 200;
unsigned long prev = 0;
uint16_t score = 0;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
int freeRAM() {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
bool is_pressed(const uint8_t &KEY){
if ((~PIND & (1<<KEY)) != 0) {
if ((PR_INPUT & (1<<KEY)) == 0){
PR_INPUT |= (1<<KEY);
return true;
}
else{ return false; }
}
else {
PR_INPUT &= ~(1<<KEY);
return false;
}
}
bool is_down(const uint8_t &KEY){
return ((~PIND & (1<<KEY)) != 0);
}
bool is_insert(const uint8_t &X, const uint8_t &Y, const uint8_t &rot){
// uint16_t line = ((currentFg & 0x0F00) << 1*4) >> plX;
for (uint8_t i=0; i<4; i++){
uint16_t line = ((pgm_read_word((uint16_t*)pgm_read_word(shapes+shape_id)+rot)
& (0xF000 >> i*4)) << i*4) >> X;
//Serial.println(line, BIN);
if (Y-i < 0) {break;}
//Serial.print(board[Y-i] ^ line, BIN);
if ((board[Y-i] & line) > 0){
return true;
}
}
return false;
}
void make_insert(){
for (uint8_t i=0; i<4; i++){
uint16_t line = ((pgm_read_word((uint16_t*)pgm_read_word(shapes+shape_id)+shape_rot)
& (0xF000 >> i*4)) << i*4) >> plX;
if (plY-i < 0) {break;}
board[plY-i] |= line;
}
}
void new_shape(){
plX = 6;
plY = 28;
shape_id = next_shape_id;
next_shape_id = random(0,7);
shape_rot = 0;
}
void death(){
board[0] = 0xFFFF;
board[height-1] = 0xFFFF;
for (uint8_t i=1; i<height-1; i++){
board[i] = 0x8001;
}
next_shape_id = random(0,7);
new_shape();
score = 0;
}
void setup() {
//Serial.begin(9600);
DDRD = 0b00000000;
PORTD = 0b11111111;
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setTextSize(1);
display.setTextColor(WHITE);
death();
}
void loop() {
display.clearDisplay();
//Serial.println(freeRAM());
unsigned long current = millis();
if (current - prev > period){
prev = current;
plY--;
if (is_insert(plX, plY-1, shape_rot)){
if (plY < 24){
make_insert();
new_shape();
score+=10;
}
else{
death();
return;
}
}
}
if (is_pressed(ENTER)){
uint8_t rot = shape_rot;
rot++;
if (rot > 3){
rot = 0;
}
if (!is_insert(plX-1, plY, rot)){
shape_rot = rot;
}
}
if (is_pressed(LEFT) && (plX>0) && !is_insert(plX-1, plY, shape_rot)){
plX--;
}
if (is_pressed(RIGHT) && (plX<13) && !is_insert(plX+1, plY, shape_rot)){
plX++;
}
//display.fillRect(plY*4, plX*4, 4, 4, WHITE);
for (uint8_t i=0; i<16; i++){
if ((pgm_read_word((uint16_t*)pgm_read_word(shapes+shape_id)+shape_rot)
& (0x8000 >> i)) > 0)
{
display.fillRect((plY-i/4)*4, (plX+i%4)*4, 4, 4, WHITE);
}
}
for (uint8_t y=0; y<height; y++){
if ((board[y] == 0xFFFF) && (y>0) && (y < height-1)){
board[y] = board[y+1];
if (board[y+1] != 0x8001) {
board[y+1] = 0xFFFF;
}
else {score+=100;}
}
for (uint8_t x=0; x<width; x++){
if ((board[y] & (0x8000>>x)) > 0){
display.drawRect(y*4, x*4, 4, 4, WHITE);
}
}
}
for (uint8_t i=0; i<16; i++){
if ((pgm_read_word((uint16_t*)pgm_read_word(shapes+next_shape_id))
& (0x8000 >> i)) > 0)
{
display.fillRect((60-i/4)*2, (3+i%4)*2, 2, 2, WHITE);
}
}
display.setCursor(100, 52);
display.print(score);
display.display();
}