// slot machine
//
// led matrix:
// 0_0, 0_1, 0_2
// 1_0, 1_1, 1_2
// 2_0, 2_1, 2_2
#define SLOT_MACHINE_ROWS 3
#define SLOT_MACHINE_COLUMNS 3
#define SLOT_MACHINE_STATUS_INIT_RUN 0
#define SLOT_MACHINE_STATUS_RUNNING 1
#define SLOT_MACHINE_STATUS_STOPPED 2
int globalStatus;
unsigned long startRunningTime;
const long maxRunningPhaseDuration = 7000L;
const int ledPin[SLOT_MACHINE_ROWS][SLOT_MACHINE_COLUMNS] = {{2, 3, 4},
{5, 6, 7},
{8, 9, 10}};
int ledState[SLOT_MACHINE_ROWS][SLOT_MACHINE_COLUMNS] = {{LOW, LOW, LOW},
{LOW, LOW, LOW},
{LOW, LOW, LOW}};
long ledStateLastWentHigh[SLOT_MACHINE_ROWS][SLOT_MACHINE_COLUMNS] = {{0L, 0L, 0L},
{0L, 0L, 0L},
{0L, 0L, 0L}};
long singleLedHighTimePerColumn[SLOT_MACHINE_COLUMNS] = {600L, 300L, 600L};
const long maxSingleLedHighTimePerColumn[SLOT_MACHINE_COLUMNS] = {1000L, 1000L, 1000L};
const long singleLedHighTimeIncrement = 100L;
void setup()
{
for (int i = 0; i < SLOT_MACHINE_ROWS; ++i)
{
for (int j = 0; j < SLOT_MACHINE_COLUMNS; ++j)
{
pinMode(ledState[i][j], OUTPUT);
}
}
globalStatus = SLOT_MACHINE_STATUS_INIT_RUN;
}
void loop()
{
switch (globalStatus)
{
case SLOT_MACHINE_STATUS_INIT_RUN:
initRunPhase();
break;
case SLOT_MACHINE_STATUS_RUNNING:
runningPhase();
break;
default: // SLOT_MACHINE_STATUS_STOPPED
stoppedPhase();
break;
}
}
// runtime phases
void initRunPhase()
{
// turn on first row
for (int j = 0; j < SLOT_MACHINE_COLUMNS; ++j)
{
ledState[0][j] = HIGH;
}
digitalWriteAllLeds();
startRunningTime = millis();
for (int j = 0; j < SLOT_MACHINE_COLUMNS; ++j)
{
ledStateLastWentHigh[0][j] = startRunningTime;
}
globalStatus = SLOT_MACHINE_STATUS_RUNNING;
}
void runningPhase()
{
bool needDigitalWriteAllLeds = false;
unsigned long runningTime = millis() - startRunningTime;
if (runningTime < maxRunningPhaseDuration)
{
for (int j = 0; j < SLOT_MACHINE_COLUMNS; ++j)
{
int highLedIndex = firstHighLedIndexInColumn(j);
long ledStateTimeSinceLastWentHigh = millis() - ledStateLastWentHigh[highLedIndex][j];
if (ledStateTimeSinceLastWentHigh > singleLedHighTimePerColumn[j])
{
int nextHighLedIndex = (highLedIndex + 1) % SLOT_MACHINE_COLUMNS;
ledState[highLedIndex][j] = LOW;
ledState[nextHighLedIndex][j] = HIGH;
ledStateLastWentHigh[nextHighLedIndex][j] = millis();
needDigitalWriteAllLeds = true;
}
}
// update output pins if needed
if (needDigitalWriteAllLeds)
{
digitalWriteAllLeds();
}
needDigitalWriteAllLeds = false;
}
else
{
globalStatus = SLOT_MACHINE_STATUS_STOPPED;
}
}
void stoppedPhase()
{
// do nothing
}
void digitalWriteAllLeds()
{
for (int i = 0; i < SLOT_MACHINE_ROWS; ++i)
{
for (int j = 0; j < SLOT_MACHINE_COLUMNS; ++j)
{
digitalWrite(ledPin[i][j], ledState[i][j]);
}
}
}
int firstHighLedIndexInColumn(int columnIndex)
{
int rowIndex = -1;
int i = 0;
while (rowIndex == -1 && i < SLOT_MACHINE_ROWS)
{
if (ledState[i][columnIndex] == HIGH)
{
rowIndex = i;
}
else
{
++i;
}
}
return rowIndex;
}
// shift register functions
int numberToDisplay(short bit7, short bit6, short bit5, short bit4,
short bit3, short bit2, short bit1, short bit0)
{
int res = 0;
short input[] = {bit0, bit1, bit2, bit3, bit4, bit5, bit6, bit7};
for (int i = 0; i < 8; ++i)
{
if (input[i])
{
res += ipow(2, i);
}
}
return res;
}
int ipow(int base, int exp)
{
int res = 1;
while (exp)
{
if (exp & 1)
{
res *= base;
}
exp >>= 1;
base *= base;
}
return res;
}