#include <U8g2lib.h>
#include <Wire.h>
#include <math.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define NUM_COUNT 5
#define NUM_MIN 1
#define NUM_MAX 45
#define ANIMATION_TIME 500 // ms (3배 빠르게)
#define FONT_HEIGHT 11
#define FONT u8g2_font_fub11_tr
#define SWING_AMPLITUDE 5 // 흔들림 진폭(픽셀)
#define GROUP_SIZE 5
#define TOTAL_NUM NUM_MAX
#define GROUP_COUNT ((TOTAL_NUM + GROUP_SIZE - 1) / GROUP_SIZE)
struct RollingNumber
{
int value;
int x;
int y;
int dir; // -1: right->left, 1: left->right
int speed;
unsigned long startTime;
unsigned long duration;
bool active;
};
RollingNumber numbers[NUM_COUNT];
int selected[NUM_COUNT];
int allNumbers[TOTAL_NUM]; // 1~45 섞인 배열
int groupIndex = 0; // 현재 장면(그룹) 인덱스
unsigned long sceneStart = 0;
void shuffleAllNumbers()
{
for (int i = 0; i < TOTAL_NUM; ++i)
allNumbers[i] = i + 1;
for (int i = TOTAL_NUM - 1; i > 0; --i)
{
int j = random(i + 1);
int t = allNumbers[i];
allNumbers[i] = allNumbers[j];
allNumbers[j] = t;
}
}
void setupNumbers()
{
int lineHeight = SCREEN_HEIGHT / GROUP_SIZE;
int base = groupIndex * GROUP_SIZE;
for (int i = 0; i < GROUP_SIZE; ++i)
{
int idx = base + i;
numbers[i].value = (idx < TOTAL_NUM) ? allNumbers[idx] : -1; // -1이면 빈칸
numbers[i].y = (i * lineHeight) + (lineHeight + FONT_HEIGHT) / 2 - 1;
numbers[i].dir = (i % 2 == 0) ? 1 : -1;
numbers[i].speed = random(3, 6);
numbers[i].duration = ANIMATION_TIME;
numbers[i].startTime = sceneStart;
numbers[i].active = false;
if (numbers[i].dir == 1)
numbers[i].x = -40;
else
numbers[i].x = SCREEN_WIDTH + 10;
}
}
void setup()
{
u8g2.begin();
u8g2.setFont(FONT);
randomSeed(analogRead(0));
shuffleAllNumbers();
groupIndex = 0;
sceneStart = millis();
setupNumbers();
}
void drawNumber(RollingNumber &num, float progress)
{
if (num.value < 0)
return;
char buf[4];
sprintf(buf, "%d", num.value);
float swing = sin(progress * 3.14159 * 2) * SWING_AMPLITUDE;
int y = num.y + (int)swing;
u8g2.setFontDirection(0);
u8g2.drawStr(num.x, y, buf);
}
void drawSixCirclesWithNumbers()
{
// 원 위치 계산 (128x64 기준, 겹치지 않게)
const int r = 15; // 반지름
const int cx[6] = {24, 64, 104, 24, 64, 104};
const int cy[6] = {15, 15, 15, 48, 48, 48}; // 위쪽 3개만 20->15로 -5 이동
const int nums[6] = {11, 22, 33, 44, 55, 66}; // 2자리 숫자
u8g2.clearBuffer();
u8g2.setFont(FONT);
for (int i = 0; i < 6; ++i)
{
u8g2.drawCircle(cx[i], cy[i], r, U8G2_DRAW_ALL);
// 숫자 중앙 정렬, 전체 -y축 1픽셀 이동 (기존 +4에서 +3으로)
char buf[4];
sprintf(buf, "%d", nums[i]);
int tw = u8g2.getStrWidth(buf);
int th = FONT_HEIGHT;
u8g2.drawStr(cx[i] - tw / 2, cy[i] + th / 2 - 2 + 3, buf);
}
u8g2.sendBuffer();
}
void drawSixCirclesWithNumbersAnimated() {
const int r = 15;
const int cx[6] = {24, 64, 104, 24, 64, 104};
const int cy[6] = {15, 15, 15, 48, 48, 48};
const int nums[6] = {11, 22, 33, 44, 55, 66};
// 방향: 0=오른쪽->왼쪽(왼쪽위/아래), 1=아래->위(가운데위), 2=위->아래(가운데아래), 3=왼쪽->오른쪽(오른쪽위/아래)
const int dir[6] = {0, 1, 3, 0, 2, 3};
const int animTime = 400; // ms
unsigned long start = millis();
unsigned long now;
bool done = false;
while (!done) {
now = millis();
u8g2.clearBuffer();
done = true;
for (int i = 0; i < 6; ++i) {
u8g2.drawCircle(cx[i], cy[i], r, U8G2_DRAW_ALL);
float t = (float)(now - start) / animTime;
if (t > 1) t = 1;
int x = cx[i], y = cy[i];
if (dir[i] == 0) { // 오른쪽->왼쪽
x = cx[i] + (int)((1-t) * (SCREEN_WIDTH - cx[i]));
} else if (dir[i] == 1) { // 아래->위
y = cy[i] + (int)((1-t) * (SCREEN_HEIGHT - cy[i]));
} else if (dir[i] == 2) { // 위->아래
y = cy[i] - (int)((1-t) * (cy[i]));
} else if (dir[i] == 3) { // 왼쪽->오른쪽
x = cx[i] - (int)((1-t) * (cx[i]));
}
char buf[4];
sprintf(buf, "%d", nums[i]);
int tw = u8g2.getStrWidth(buf);
int th = FONT_HEIGHT;
u8g2.drawStr(x - tw/2, y + th/2 - 2 + 3, buf);
if (t < 1) done = false;
}
u8g2.sendBuffer();
delay(16);
}
}
void loop()
{
unsigned long now = millis();
u8g2.clearBuffer();
bool anyActive = false;
for (int i = 0; i < GROUP_SIZE; ++i)
{
RollingNumber &num = numbers[i];
if (num.value < 0)
continue;
if (now >= num.startTime && now < num.startTime + num.duration)
{
num.active = true;
int totalMove = SCREEN_WIDTH + 50;
float progress = (float)(now - num.startTime) / num.duration;
if (num.dir == 1)
num.x = -40 + progress * totalMove;
else
num.x = SCREEN_WIDTH + 10 - progress * totalMove;
drawNumber(num, progress);
anyActive = true;
}
else
{
num.active = false;
}
}
u8g2.sendBuffer();
if (now > sceneStart + ANIMATION_TIME)
{
groupIndex++;
if (groupIndex < GROUP_COUNT)
{
sceneStart = millis();
setupNumbers();
}
else
{
// 모든 장면 끝: 6개 원과 1~6 숫자 애니메이션으로 표시
delay(500);
drawSixCirclesWithNumbersAnimated();
while (1)
;
}
}
delay(20);
}