#include <Arduino.h>
#include <Wire.h>
#include <SSD1306Ascii.h>
#include <SSD1306AsciiWire.h>
SSD1306AsciiWire o;
#define X A0
#define Y A1
#define SW D2
#define BZ D3
#define L1 D4
#define L2 D5
#define W 16
#define H 5
#define N 25
uint8_t sx[N];
uint8_t sy[N];
uint8_t len;
uint8_t fx;
uint8_t fy;
int8_t dx = 1;
int8_t dy = 0;
uint8_t score = 0;
bool game = false;
unsigned long tm = 0;
uint16_t speed = 300;
// =====================================================
// FOOD
// =====================================================
bool snakeHere(uint8_t x, uint8_t y)
{
for (uint8_t i = 0; i < len; i++)
{
if (sx[i] == x && sy[i] == y)
return true;
}
return false;
}
void placeFood()
{
uint8_t start = (score * 7 + 3) % (W * H);
for (uint8_t k = 0; k < W * H; k++)
{
uint8_t p = (start + k) % (W * H);
uint8_t x = p % W;
uint8_t y = p / W;
if (!snakeHere(x, y))
{
fx = x;
fy = y;
return;
}
}
}
// =====================================================
// GAME SCREEN
// =====================================================
void screen()
{
o.clear();
// -----------------------------
// SCORE
// -----------------------------
o.print("SCORE:");
if (score < 10)
o.print("0");
o.println(score);
// -----------------------------
// TOP BORDER
// -----------------------------
o.println("----------------");
// -----------------------------
// FOOD
// -----------------------------
o.setCursor(fx, fy + 2);
o.print("*");
// -----------------------------
// SNAKE
// -----------------------------
for (int i = len - 1; i >= 0; i--)
{
o.setCursor(sx[i], sy[i] + 2);
if (i == 0)
o.print("@");
else
o.print("o");
}
// -----------------------------
// BOTTOM BORDER
// -----------------------------
o.setCursor(0, 7);
o.print("----------------");
}
// =====================================================
// START GAME
// =====================================================
void start()
{
sx[0] = 7;
sy[0] = 2;
sx[1] = 6;
sy[1] = 2;
sx[2] = 5;
sy[2] = 2;
len = 3;
score = 0;
dx = 1;
dy = 0;
speed = 300;
placeFood();
game = true;
digitalWrite(L1, HIGH);
digitalWrite(L2, LOW);
tone(BZ, 1000, 60);
screen();
}
// =====================================================
// JOYSTICK
// =====================================================
void joy()
{
int x = analogRead(X);
int y = analogRead(Y);
// LEFT
if (x > 700 && dx == 0)
{
dx = -1;
dy = 0;
}
// RIGHT
if (x < 300 && dx == 0)
{
dx = 1;
dy = 0;
}
// UP
if (y > 700 && dy == 0)
{
dx = 0;
dy = -1;
}
// DOWN
if (y < 300 && dy == 0)
{
dx = 0;
dy = 1;
}
}
// =====================================================
// MOVE
// =====================================================
void moveSnake()
{
int nx = sx[0] + dx;
int ny = sy[0] + dy;
// Wall collision
if (nx < 0 || nx >= W ||
ny < 0 || ny >= H)
{
game = false;
return;
}
// Self collision
for (uint8_t i = 0; i < len; i++)
{
if (sx[i] == nx && sy[i] == ny)
{
game = false;
return;
}
}
// Food
bool eat = (nx == fx && ny == fy);
if (eat)
{
if (len < N)
len++;
score++;
if (speed > 120)
speed -= 15;
tone(BZ, 1500, 50);
}
// Move body
for (int i = len - 1; i > 0; i--)
{
sx[i] = sx[i - 1];
sy[i] = sy[i - 1];
}
sx[0] = nx;
sy[0] = ny;
if (eat)
placeFood();
}
// =====================================================
// GAME OVER
// =====================================================
void gameOver()
{
digitalWrite(L1, LOW);
digitalWrite(L2, HIGH);
tone(BZ, 300, 300);
o.clear();
o.println();
o.println(" GAME OVER");
o.println();
o.print(" SCORE:");
if (score < 10)
o.print("0");
o.println(score);
o.println();
o.println(" PRESS BUTTON");
o.println(" TO RETRY");
}
// =====================================================
// SETUP
// =====================================================
void setup()
{
Wire.setSDA(PB7);
Wire.setSCL(PB6);
Wire.begin();
Wire.setClock(400000);
pinMode(X, INPUT);
pinMode(Y, INPUT);
pinMode(SW, INPUT_PULLUP);
pinMode(BZ, OUTPUT);
pinMode(L1, OUTPUT);
pinMode(L2, OUTPUT);
o.begin(&Adafruit128x64, 0x3C);
o.setFont(System5x7);
o.clear();
// -----------------------------
// NOKIA START SCREEN
// -----------------------------
o.println(" NOKIA");
o.println();
o.println(" SNAKE GAME");
o.println();
o.println(" @oo *");
o.println();
o.println(" PRESS BUTTON");
o.println(" TO START");
digitalWrite(L1, LOW);
digitalWrite(L2, LOW);
}
// =====================================================
// LOOP
// =====================================================
void loop()
{
// -----------------------------
// WAIT / RESTART
// -----------------------------
if (!game)
{
if (digitalRead(SW) == LOW)
{
delay(200);
start();
tm = millis();
}
return;
}
// -----------------------------
// JOYSTICK
// -----------------------------
joy();
// -----------------------------
// GAME TICK
// -----------------------------
if (millis() - tm >= speed)
{
tm = millis();
moveSnake();
if (game)
{
screen();
}
else
{
gameOver();
}
}
}