/*
* Brick a bottle or three
* Based on "Brick a Bottle or Three" by Palingenesis
* (https://www.instructables.com/Brick-a-Bottle-or-Three/)
*
* 230516 John Bradnam (jbrad2089@gial.com)
* - Coverted project to use a ATtiny1614 processor
*
*-------------------------------------------------------------------------
Arduino IDE:
--------------------------------------------------------------------------
BOARD: ATtiny1614/1604/814/804/414/404/214/204
Chip: ATtiny1614
Clock Speed: 20MHz
millis()/micros(): "Enabled (default timer)"
Programmer: jtag2updi (megaTinyCore)
ATTiny1614 Pins mapped to Ardunio Pins
+--------+
VCC + 1 14 + GND
(SS) 0 PA4 + 2 13 + PA3 10 (SCK)
1 PA5 + 3 12 + PA2 9 (MISO)
(DAC) 2 PA6 + 4 11 + PA1 8 (MOSI)
3 PA7 + 5 10 + PA0 11 (UPDI)
(RXD) 4 PB3 + 6 9 + PB0 7 (SCL)
(TXD) 5 PB2 + 7 8 + PB1 6 (SDA)
+--------+
**************************************************************************/
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#define LIGHT 0 //PA4
#define SCLK 1 //PA5
#define DIN 2 //PA6
#define DC 3 //PA7
#define CS_LCD 4 //PB3
#define RST 5 //PB2
#define PIEZO 7 //PB0
#define SWITCHES 10 //PA3
Adafruit_PCD8544 display = Adafruit_PCD8544(SCLK,DIN,DC,CS_LCD,RST);
enum SWITCH { NONE, ONE, TWO, THREE, FOUR };
struct SWITCH_VALUES
{
SWITCH name;
int low;
int high;
};
#define SWITCH_COUNT 4
SWITCH_VALUES switches[SWITCH_COUNT] = {{ONE,600,700},{TWO,450,600},{THREE,300,450},{FOUR,0,100}};
SWITCH lastButtonPressed = NONE;
enum MODES {MENU, HELP, QUERY, TAKE, WIN};
MODES mode = MENU;
bool backlight;
int bottleNumber;
int youTake;
int iTake;
//---------------------------------------------------------------
// Bottle graphivs
// brick 14x6 (Use Rectangle)
// bottle 6x16
//---------------------------------------------------------------
const uint8_t bottle_img[] PROGMEM =
{
B00110000,
B00110000,
B00110000,
B00110000,
B01111000,
B11111100,
B11111100,
B11111100,
B11111100,
B11111100,
B11111100,
B11111100,
B11111100,
B11111100,
B01111000
};
//Smashed bottle 6x16
const uint8_t smash_bottle_img[] PROGMEM =
{
B01001000,
B10000100,
B00100000,
B01001000,
B10000100,
B00110000,
B00100100,
B10000000,
B10001000,
B11001100,
B01000100,
B11010100,
B10010100,
B10110100,
B00101100
};
//------------------------------------------------------------
// Hardware setup
//------------------------------------------------------------
void setup()
{
//Encoder
pinMode(PIEZO,OUTPUT);
pinMode(SWITCHES,INPUT);
pinMode(LIGHT,OUTPUT);
analogWrite(LIGHT, 0);
backlight = false;
display.begin(60, 4);
//display.setContrast(50);
display.display(); // show splashscreen
delay(2000);
writeTitleText();
display.clearDisplay();
drawBrickWall();
for (size_t i = 1; i < 10; i++)
{
drawBottle(i + bottleNumber);
}
display.display();
delay(500);
for (size_t i = 1; i < 10; i++) {
smashBottle(i + bottleNumber);
delay(100);
}
//delay(2000);
display.setTextSize(1);
display.setTextColor(BLACK);
mode = MENU;
}
//------------------------------------------------------------
// Main loop
//------------------------------------------------------------
void loop()
{
switch (mode)
{
case MENU: writeMenuText(); break;
case HELP: writeHelpText(); break;
case QUERY: writeQuestionText(); break;
case TAKE: writeITakeText(); break;
case WIN: writeIWinText(); break;
}
}
//-------------------------------------------------------------
// Graphic routines
//-------------------------------------------------------------
void drawBrickWall(void) {
byte FirstBrickLeft = 0;
byte FirstBrickTop = 0;
for (size_t i = 0; i < 3; i++)
{
if (i == 1)
{
FirstBrickLeft = 10;
}
else
{
FirstBrickLeft = 3;
}
for (int16_t ii = 0; ii < 100; ii += 15)
{
display.fillRect(ii - FirstBrickLeft, 31 + FirstBrickTop, 14, 6, 1);
}
FirstBrickTop += 7;
}
display.display();
}
void drawBottle(byte position)
{
display.drawBitmap(position * 7, 16, bottle_img, 6, 15, 1);
display.display();
}
void smashBottle(byte position)
{
display.fillRect(position * 7, 16, 6, 15, 0);
display.drawBitmap(position * 7, 16, smash_bottle_img, 6, 15, 1);
display.display();
playBottleSmashSound();
delay(500);
display.fillRect(position * 7, 16, 6, 15, 0);
display.display();
}
//--------------------------------------------------
// Sound routines
//--------------------------------------------------
void playBottleSmashSound()
{
tone(PIEZO, 2000);
delay(100);
tone(PIEZO, 500);
delay(200);
for (size_t i = 400; i > 0; i-=10)
{
tone(PIEZO, i);
delay(15);
}
noTone(PIEZO);
}
void playStartSound()
{
for (size_t i = 0; i < 4; i++)
{
tone(PIEZO, 500);
delay(100);
tone(PIEZO, 1000);
delay(100);
tone(PIEZO, 1500);
delay(100);
tone(PIEZO, 2000);
delay(100);
tone(PIEZO, 2500);
delay(100);
}
noTone(PIEZO);
}
//----------------------------------------------------
// Display Text routines
//----------------------------------------------------
void writeTitleText()
{
display.clearDisplay();
display.setCursor(27, 10);
display.print("BRICK");
display.setCursor(18, 20);
display.print("A BOTTLE");
display.setCursor(18, 30);
display.print("OR THREE");
display.display();
playStartSound();
}
void writeMenuText()
{
display.clearDisplay();
display.setCursor(0, 0);
display.print("");
display.setCursor(0, 9);
display.print("1 = NEW GAME");
display.setCursor(0, 18);
display.print("2 = Help");
display.setCursor(0, 27);
display.print("3 = Exit");
display.setCursor(0, 36);
display.print("4 = LED");
display.display();
bottleNumber = 3;
SWITCH button = readSwitches(true);
while (button == NONE)
{
button = readSwitches(true);
}
switch (button)
{
case ONE:
//Start a new game
display.clearDisplay();
drawBrickWall();
for (size_t i = 1; i < 10; i++) {
drawBottle(i + 2);
}
mode = QUERY;
break;
case TWO:
//Help
mode = HELP;
break;
case THREE:
//Exit
display.clearDisplay();
display.setCursor(0, 0);
display.print("");
display.setCursor(0, 9);
display.print("BYE");
display.setCursor(0, 18);
display.print("TRY AGAIN");
display.setCursor(0, 27);
display.print("ANOTHER TIME");
display.setCursor(0, 41);
display.print("");
display.display();
delay(5000);
mode = MENU;
break;
case FOUR:
backlight = !backlight;
analogWrite(LIGHT, (backlight) ? 192 : 0);
break;
case NONE:
break;
}
}
void writeHelpText()
{
display.clearDisplay();
display.setCursor(0, 0);
display.print("== THE GAME ==");
display.setCursor(0, 9);
display.print("THERE ARE");
display.setCursor(0, 18);
display.print("9 BOTTLES");
display.setCursor(0, 27);
display.print("ON A WALL.");
display.setCursor(0, 41);
display.print("(Press Button)");
display.display();
while (readSwitches(true) == NONE);
display.clearDisplay();
display.setCursor(0, 0);
display.print("YOU ARE");
display.setCursor(0, 9);
display.print("EXPERT");
display.setCursor(0, 18);
display.print("AT THROWING");
display.setCursor(0, 27);
display.print("STONES.");
display.setCursor(0, 41);
display.print("(Press Button)");
display.display();
while (readSwitches(true) == NONE);
display.clearDisplay();
display.setCursor(0, 0);
display.print("YOU ALWAYS");
display.setCursor(0, 9);
display.print("HIT A BOTTLE.");
display.setCursor(0, 18);
display.print("I'M");
display.setCursor(0, 27);
display.print("JUST AS GOOD.");
display.setCursor(0, 41);
display.print("(Press Button)");
display.display();
while (readSwitches(true) == NONE);
display.clearDisplay();
display.setCursor(0, 0);
display.print("WE MAY TAKE");
display.setCursor(0, 9);
display.print("1, 2 OR 3");
display.setCursor(0, 18);
display.print("STONES");
display.setCursor(0, 27);
display.print("EACH TURN.");
display.setCursor(0, 41);
display.print("(Press Button)");
display.display();
while (readSwitches(true) == NONE);
display.clearDisplay();
display.setCursor(0, 0);
display.print("ONE WITH THE");
display.setCursor(0, 9);
display.print("LAST BOTTLE,");
display.setCursor(0, 18);
display.print("LOSES");
display.setCursor(0, 27);
display.print("THE GAME.");
display.setCursor(0, 41);
display.print("(Press Button)");
display.display();
while (readSwitches(true) == NONE);
mode = MENU;
}
void writeQuestionText()
{
display.fillRect(0, 0, 83, 14, 0);
display.setCursor(0, 3);
display.print(" 1, 2 or 3?");
display.display();
SWITCH button = readSwitches(true);
while (button == NONE || button == FOUR)
{
button = readSwitches(true);
}
youTake = (int)button;
for (int i = 0; i < youTake; i++)
{
smashBottle(i + bottleNumber);
delay(100);
}
bottleNumber += youTake;
mode = TAKE;
}
void writeITakeText()
{
iTake = 4 - youTake;
display.fillRect(0, 0, 83, 14, 0);
display.setCursor(0, 3);
display.print(" I TAKE " + String(iTake));
display.display();
delay(2000);
for (int i = 0; i < iTake; i++)
{
smashBottle(i + bottleNumber);
delay(100);
}
bottleNumber += iTake;
mode = (bottleNumber < 9) ? QUERY : WIN;
}
void writeIWinText()
{
display.fillRect(0, 0, 83, 14, 0);
display.setCursor(0, 3);
display.println("Only 1 left.");
display.print("I WIN");
display.display();
delay(500);
playStartSound();
mode = MENU;
}
//----------------------------------------------------
// Buttons
// - Returns NONE, ONE, TWO, THREE or FOUR
//----------------------------------------------------
SWITCH readSwitches(bool waitForRelease)
{
SWITCH sw = NONE;
int value = analogRead(SWITCHES);
if (value < 1000)
{
delay(10); //debounce
if (analogRead(SWITCHES) < 1000)
{
for(int i = 0; i < SWITCH_COUNT; i++)
{
if (value >= switches[i].low && value < switches[i].high)
{
sw = switches[i].name;
tone(PIEZO, 500);
delay(10);
noTone(PIEZO);
if (waitForRelease)
{
while (analogRead(SWITCHES) < 1000)
{
yield();
}
}
break;
}
}
}
}
return sw;
}
Comments
Please log in or sign up to comment.