//==========================================================
// ARDUINO MASTERMIND BRUTE FORCE RESOLVER
//==========================================================
#include <LiquidCrystal.h>
//==========================================================
const uint8_t PIN_START = A0;
const uint8_t PIN_BLACK_INC = A2;
const uint8_t PIN_BLACK_DEC = A1;
const uint8_t PIN_WHITE_INC = A4;
const uint8_t PIN_WHITE_DEC = A3;
const uint8_t PIN_CONFIRM = A5;
//==========================================================
bool onStart;
bool onBlackInc;
bool onBlackDec;
bool onWhiteInc;
bool onWhiteDec;
bool onConfirm;
uint8_t data[9][6]; // tabella max 9 tentativi
uint8_t tent; // indice tentativi 0..8
uint8_t code[4]; // tentativo corrente
//==========================================================
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
//==========================================================
void setup()
{
lcd.begin(16, 2);
lcd.setCursor(3, 0);
lcd.print(F("MASTERMIND"));
lcd.setCursor(4, 1);
lcd.print(F("RESOLVER"));
pinMode(PIN_START, INPUT_PULLUP);
pinMode(PIN_BLACK_INC, INPUT_PULLUP);
pinMode(PIN_BLACK_DEC, INPUT_PULLUP);
pinMode(PIN_WHITE_INC, INPUT_PULLUP);
pinMode(PIN_WHITE_DEC, INPUT_PULLUP);
pinMode(PIN_CONFIRM, INPUT_PULLUP);
pinMode(13, OUTPUT);
}
//==========================================================
void loop()
{
readPuls();
elabora();
}
//==========================================================
void readPuls()
{
uint8_t rd;
static uint32_t t = millis();
static uint8_t preRd = 0b00111111;
onStart = onConfirm = 0;
onBlackInc = onBlackDec = 0;
onWhiteInc = onWhiteDec = 0;
rd = digitalRead(PIN_START) << 5;
rd |= digitalRead(PIN_BLACK_INC) << 4;
rd |= digitalRead(PIN_BLACK_DEC) << 3;
rd |= digitalRead(PIN_WHITE_INC) << 2;
rd |= digitalRead(PIN_WHITE_DEC) << 1;
rd |= digitalRead(PIN_CONFIRM);
if (rd == preRd) t = millis();
else if (millis() - t >= 50) // debounce 50 ms
{
preRd = rd;
onStart = rd == 0b00011111;
onBlackInc = rd == 0b00101111;
onBlackDec = rd == 0b00110111;
onWhiteInc = rd == 0b00111011;
onWhiteDec = rd == 0b00111101;
onConfirm = rd == 0b00111110;
}
}
//==========================================================
void elabora()
{
static uint8_t s = 0;
static uint8_t black;
static uint8_t white;
if (onStart)
{
black = white = tent = 0;
randomSeed(millis() & 0x7FFFFFFF);
code[0] = random(1, 7);
code[1] = random(1, 7);
code[2] = random(1, 7);
code[3] = random(1, 7);
lcd.clear();
printTent(tent);
printCode(code);
printBlack(black);
printWhite(white);
s = 1;
}
if (1 == s)
{
if (onBlackInc) black += black < 4;
if (onBlackDec) black -= black > 0;
if (onBlackInc || onBlackDec) printBlack(black);
if (onWhiteInc) white += white < 4;
if (onWhiteDec) white -= white > 0;
if (onWhiteInc || onWhiteDec) printWhite(white);
if (onConfirm)
{
if (4 == black && 0 == white) { printWon(); s = 0; return; }
if (9 == tent) { printLost(); s = 0; return; }
data[tent][0] = code[0]; // salva tentativo attuale
data[tent][1] = code[1];
data[tent][2] = code[2];
data[tent][3] = code[3];
data[tent][4] = black;
data[tent][5] = white;
tent++;
digitalWrite(13, 1); // blink elaborazione
bruteForce(); // cerca una combinazione compatibile
digitalWrite(13, 0);
if (0 == code[0]) { printError(); s = 0; return; }
black = white = 0;
lcd.clear();
printTent(tent);
printCode(code);
printBlack(black);
printWhite(white);
}
}
}
//==========================================================
void printTent(uint8_t tent)
{
lcd.setCursor(0, 0);
lcd.print(F("Tent:"));
lcd.print(tent + 1);
}
void printCode(uint8_t code[])
{
lcd.setCursor(7, 0);
lcd.print(F("Code:"));
lcd.print(code[0]);
lcd.print(code[1]);
lcd.print(code[2]);
lcd.print(code[3]);
}
void printBlack(uint8_t black)
{
lcd.setCursor(0, 1);
lcd.print(F("Neri:"));
lcd.print(black);
}
void printWhite(uint8_t white)
{
lcd.setCursor(7, 1);
lcd.print(F("Bianchi:"));
lcd.print(white);
}
void printError()
{
lcd.clear();
lcd.print(F("ERRORE"));
lcd.setCursor(0, 1);
lcd.print(F("NO SOLUZIONI"));
}
void printWon()
{
lcd.setCursor(0, 1);
lcd.print(F("****HO VINTO!***"));
}
void printLost()
{
lcd.setCursor(0, 1);
lcd.print(F("****HO PERSO!***"));
}
//==========================================================
void bruteForce()
{
uint8_t a = 1;
uint8_t b = 1;
uint8_t c = 1;
uint8_t d = 1;
while (d < 7)
{
if (compatibile(a, b, c, d))
{
code[0] = a;
code[1] = b;
code[2] = c;
code[3] = d;
return;
}
a++;
if (7 == a) { a = 1; b++; }
if (7 == b) { b = 1; c++; }
if (7 == c) { c = 1; d++; }
}
code[0] = 0; // nessuna comb.compatibile, ritorna zero
code[1] = 0;
code[2] = 0;
code[3] = 0;
}
//==========================================================
bool compatibile(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
uint8_t i;
uint8_t rn;
uint8_t rb;
uint8_t comb[4] = {a, b, c, d};
for (i=0; i<tent; i++)
{
code[0] = data[i][0];
code[1] = data[i][1];
code[2] = data[i][2];
code[3] = data[i][3];
rn = test(comb, code);
rb = rn & 0b00000111;
rn >>= 3;
if (rn != data[i][4] || rb != data[i][5]) return 0;
}
return 1;
}
//==========================================================
uint8_t test(const uint8_t a[], uint8_t b[])
{
uint8_t neri = 0;
uint8_t bianchi = 0;
uint8_t i;
uint8_t j;
for (i=0; i<4; i++)
{
if (a[i] == b[i])
{
neri++;
b[i] = 0;
}
else
for (j=0; j<4; j++)
if (a[i] == b[j] && b[j] != a[j])
{
bianchi++;
b[j] = 0;
break;
}
}
return (neri << 3) | bianchi;
}
//==========================================================