// magic eight ball
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET 4
#define OLED_I2C_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
byte buttonpin = 2;
int center;
int count;
const char response[] PROGMEM = {
"\0It is certain" // 0 start 1 end 14
"\0Reply hazy, try again" // 1 start 15 end 36
"\0Don't count on it" // 2 start 37 end 54
"\0It is decidedly so" // 3 start 55 end 73
"\0Ask again later" // 4 start 74 end 89
"\0My reply is no" // 5 start 90 end 104
"\0Without a doubt" // 6 start 105 end 120
"\0Better not tell you now" // 7 start 121 end 144
"\0My sources say no" // 8 start 145 end 162
"\0Yes definitely" // 9 start 163 end 177
"\0Cannot predict now" // 10 start 178 end 196
"\0Outlook not so good" // 11 start 197 end 216
"\0You may rely on it" // 12 start 217 end 235
"\0Concentrate and ask again" // 13 start 236 end 261
"\0Very doubtful" // 14 start 262 end 275
"\0As I see it, yes" // 15 start 276 end 292
"\0Most likely" // 16 start 293 end 304
"\0Outlook good" // 17 start 205 end 317
"\0Yes" // 18 start 318 end 321
"\0Signs point to yes" // 19 start 322 end 340
};
#define BITMAP_WIDTH 30
#define BITMAP_HEIGHT 30
#define CHAR_HEIGHT 9 // 8 pixels + 1 kern
#define CHAR_WIDTH 6 // 5 pixels + 1 kern
const unsigned char eightbitmap [] PROGMEM = { // 'eight', 30x30px
0x00, 0x1f, 0xe0, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0x80,
0x07, 0xe0, 0x1f, 0xc0, 0x0f, 0xc0, 0x0f, 0xe0, 0x1f, 0x80, 0x07, 0xe0, 0x3f, 0x87, 0xc3, 0xf0,
0x3f, 0x0f, 0xe1, 0xf0, 0x7f, 0x1f, 0xf1, 0xf8, 0x7f, 0x1f, 0xf1, 0xf8, 0xff, 0x0f, 0xe1, 0xfc,
0xff, 0x87, 0xc3, 0xfc, 0xff, 0xc0, 0x07, 0xfc, 0xff, 0xc0, 0x07, 0xfc, 0xff, 0x80, 0x03, 0xfc,
0xff, 0x07, 0xc1, 0xfc, 0xff, 0x0f, 0xe1, 0xfc, 0xff, 0x1f, 0xf1, 0xfc, 0x7f, 0x1f, 0xf1, 0xf8,
0x7f, 0x1f, 0xf1, 0xf8, 0x3f, 0x0f, 0xe1, 0xf0, 0x3f, 0x07, 0xc1, 0xf0, 0x1f, 0x80, 0x03, 0xe0,
0x1f, 0xc0, 0x07, 0xe0, 0x0f, 0xe0, 0x0f, 0xc0, 0x07, 0xff, 0xff, 0x80, 0x01, 0xff, 0xfe, 0x00,
0x00, 0x7f, 0xfc, 0x00, 0x00, 0x1f, 0xf0, 0x00
};
void setup() {
Serial.begin(115200); // start serial comms
configureOLED();
randomSeed(analogRead(A0)); // start pseudo-randomness
pinMode(buttonpin, INPUT_PULLUP); // button is LOW when pressed, HIGH when released
place();
while (1) {};
}
void place() {
int n = random(20); // pickrandom response
Serial.print("r=");
Serial.print(n);
Serial.print(" ");
for (int i = 0; i < sizeof(response); i++) { // count through 341 characters in responses
if (pgm_read_byte(response + i) == '\0') {
count++;
Serial.print(i);
Serial.print(" ");
if (count == n) {
while (pgm_read_byte(response + i + count) != '\0') {
// Serial.print(pgm_read_byte(response + i));
}
}
}
}
}
void loop() {
magic8ball();
staticBall(WHITE);
ask();
readbutton();
shake();
answer();
}
void shake() {
int rx, ry;
display.setTextColor(BLACK);
display.setCursor(15, 113);
display.print(F("Press\nthe button."));
display.display();
staticBall(BLACK);
for (int i = 0; i < 15; i++) {
rx = random(-2, 2), ry = random(-3, 3);
display.drawBitmap(center - 15 + rx, center + ry, eightbitmap, BITMAP_WIDTH, BITMAP_HEIGHT, WHITE);
display.drawCircle(center + rx, center + (2 * CHAR_HEIGHT) + ry, 30, WHITE);
display.display();
delay(50);
display.drawBitmap(center - 15 + rx, center + ry, eightbitmap, BITMAP_WIDTH, BITMAP_HEIGHT, BLACK);
display.drawCircle(center + rx, center + (2 * CHAR_HEIGHT) + ry, 30, BLACK);
}
staticBall(WHITE);
}
void ask() {
fillbuffer(WHITE, 15, 89, "Ask a\n question");
// display.setTextColor(WHITE);
// display.setCursor(15, 89);
// display.print(F("Ask a\n question"));
display.display();
delay(1500);
fillbuffer(BLACK, 15, 89, "Ask a\n question");
// display.setTextColor(BLACK);
// display.setCursor(15, 89);
// display.print(F("Ask a\n question"));
fillbuffer(WHITE, 18, 105, "then");
// display.setTextColor(WHITE);
// display.setCursor(18, 105);
// display.print(F("then"));
display.display();
delay(500);
fillbuffer(BLACK, 18, 105, "then");
// display.setTextColor(BLACK);
// display.setCursor(18, 105);
// display.print(F("then"));
display.display();
fillbuffer(WHITE, 15, 113, "Press\nthe button");
// display.setTextColor(WHITE);
// display.setCursor(15, 113);
// display.print(F("Press\nthe button."));
display.display();
}
void fillbuffer(int color, int x, int y, char text[]) {
display.setTextColor(color);
display.setCursor(x, y);
display.print(text);
}
void answer() {
display.fillCircle(center, center + (2 * CHAR_HEIGHT), 29, BLACK);
display.drawCircle(center, center + (2 * CHAR_HEIGHT), 30, WHITE);
display.setCursor(0, 24);
display.print(random(20));
}
void serialMonitorOutput() { // show flags in serial monitor, side by side
int count;
for (int i = 0; i < sizeof(response); i++) {
if (pgm_read_byte(response + i) == '\0') {
count++;
Serial.println();
}
Serial.write(pgm_read_byte(response + i));
}
Serial.println(count);
}
void magic8ball() {
display.setTextColor(WHITE);
display.setCursor(3, 1);
display.print("MAGIC8BALL\n SAYS");
display.display();
}
void ball() {
display.drawCircle(center, center + (2 * CHAR_HEIGHT), 30, WHITE);
}
void staticBall(int color) {
display.drawBitmap(center - 15, center, eightbitmap, BITMAP_WIDTH, BITMAP_HEIGHT, color);
display.drawCircle(center, center + (2 * CHAR_HEIGHT), 30, color);
}
void configureOLED() {
display.begin(SSD1306_SWITCHCAPVCC, OLED_I2C_ADDRESS); // start OLED object
display.clearDisplay();
display.setRotation(1); // pins left
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.clearDisplay();
display.display();
center = display.width() / 2;
}
void readbutton() {
while (digitalRead(buttonpin) == 1) {}; // do nothing until button is pressed.
}