// ##### ###### # # ##### # # ###### # # ######## ####### # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # #
// # # ### # # ##### # ###### # # # # # # # # # # # # # #
// # # # # # # # # # # # ## # # # # ## # # ## #
// #### ##### # ##### # # # # # # ####### # # # # # #
#include <Servo.h>
#include <LiquidCrystal.h>
const int rs = 7, en = 6, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
Servo s_base;
Servo s_brc;
Servo s_avb;
#define pin_sbase 9
#define pin_sbrc 10
#define pin_savb 11
#define pin_rele 8
#define btn_f1 A0
#define btn_f2 A1
#define btn_f3 A2
#define btn_str 12
#define btn_stp 13
#define btn_rst 19
float puls[9] = {};
String s_string;
int turno = 7;
const int iterazioni = 10000;
float w[9] = {0.8, 0.1, 0.34, 0.97, 0.78, 0.65, 0.24, 0.45, 0.86};
float b = 0.44;
const float learning_rate = 0.1;
const int max_db = 20;
int partite = 0;
int win_x = 0;
int win_o = 0;
int p_win = 0;
int ms_x = 0;
int ms_o = 0;
int database[max_db][10] = {};
int p_caselle[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
int pos_c[9][3] = {
{90,100,200},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0}
};
int pos_x[5][3] = {
{70,50,10},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
};
int pos_o[5][3] = {
{70,50,10},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
};
float sigmoide(float x)
{
return 1/(1+exp(-x));
}
float sigmoide_d(float x)
{
return sigmoide(x) * (1 - sigmoide(x));
}
void train()
{
for (int i = 0 ; i <iterazioni; i ++){
int rd = random(0,partite + 2);
int target = database[rd][9];
if (target != -1 && target != 2){
Serial.println("--------------------------------");
Serial.println("Epoca " + String(i));
Serial.println("--------------------------------");
float prev = RN(database[rd]);
int z;
float errore = (target - prev);
for (int g =0; g<9; g ++){
w[g] += learning_rate * errore * database[rd][g] * sigmoide_d(target);
z += w[g];
}
b += (learning_rate * errore) * sigmoide_d(z);
Serial.println("target: " + String(target));
Serial.println("prev: " + String(prev));
Serial.println("errore:" + String(errore));
Serial.println("b:" + String(b));
Serial.println("--------------------------------");
}
}
}
float RN(int x[9])
{
float t;
for (int i =0; i<9; i ++){
t+= w[i] * x[i];
}
t+=b;
return sigmoide(t);
}
bool mossa(int player,int c){
if (player != 1){
if(p_caselle[c] == -1){
if (c >= 0 && c <= 8){
p_caselle[c] = 0;
tabellone(p_caselle);
ms_o ++;
//move_b(player,c);
return true;
}else
{
return false;
}
}else
{
return false;
}
}else{
if(p_caselle[c] == -1){
p_caselle[c] = 1;
tabellone(p_caselle);
ms_x ++;
lcd.print(String() + "Casella : " + (c +1)) ;
//move_b(player,c);
return true;
}else
{
return false;
}
}
}
void setup() {
Serial.begin(2000000);
def_pin();
set_servo();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("AI-TAC MASTER");
delay(3000);
lcd.setCursor(0, 1);
lcd.print("Premere start...");
}
void def_pin(){
s_base.attach(pin_sbase);
s_brc.attach(pin_sbrc);
s_avb.attach(pin_savb);
lcd.begin(16, 2);
pinMode(pin_rele,OUTPUT);
pinMode(btn_f1,INPUT);
pinMode(btn_f2,INPUT);
pinMode(btn_f3,INPUT);
pinMode(btn_str,INPUT_PULLUP);
pinMode(btn_stp,INPUT_PULLUP);
pinMode(btn_rst,INPUT_PULLUP);
}
void set_servo(){
s_base.write(0);
s_brc.write(0);
s_avb.write(0);
}
void _init(){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Caricamento...");
Serial.println();
Serial.println("Caricamento...");
if (partite == 0){
for (int db = partite ; db<max_db ; db ++){
for (int y =0; y<10 ; y ++){
database[db][y] = -1;
}
}
}
lcd.clear();
lcd.print(String() + "Partita: " + (partite + 1) );
delay(1000);
lcd.clear();
/*Serial.println("-------------------------------------");
Serial.println(String() + "/ Partita: " + (partite + 1) + " /");
Serial.println(String() + " - Win O: " + win_o);
Serial.println(String() + " - Win X: " + win_x);
Serial.println(String() + " - Pareggi X: " + p_win);
Serial.println("-------------------------------------");*/
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Turno O") ;
tabellone(p_caselle);
Serial.println("Turno di o");
turno = 0;
}
void loop(){
win();
int bt = getBtn();
Serial.println(bt);
if(c_win() == -1){
if ( turno == 0 ){
if(bt != -1 ){
if (mossa(0,bt - 1) !=false){
//Serial.println("Giocatore O ha scelto la casella " + String(bt));
lcd.setCursor(0,1);
lcd.print(String() + "Casella : " + bt) ;
turno = 1;
delay(1000);
}else
{
//Serial.println("Casella non disponibile");
lcd.setCursor(0,1);
lcd.print("Casella non disponibile") ;
}
}
}
win();
if (turno == 1) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Turno di X") ;
lcd.setCursor(0,1);
float p[9];
float max_predizione = -1;
int miglior_mossa = -1;
if (partite > 5){
for (int i = 0; i < 9; i++) {
if (p_caselle[i] == -1) {
p_caselle[i] = 1;
p[i] = RN(p_caselle);
p_caselle[i] = -1;
if (p[i] > max_predizione) {
max_predizione = p[i];
miglior_mossa = i;
}
}
}
}
if (miglior_mossa != -1) {
if (mossa(1, miglior_mossa)) {
int prossima_mossa = -1;
if (partite > 0){
for (int i = 0; i < 9; i++) {
if (p_caselle[i] == -1) {
p_caselle[i] = 0;
if (c_win() == 0) {
prossima_mossa = i;
p_caselle[i] = -1;
break;
}
p_caselle[i] = -1;
}
}
}
int prossima_mossa_x = -1;
if (partite > 0){
for (int i = 0; i < 9; i++) {
if (p_caselle[i] == -1) {
p_caselle[i] = 1;
if (c_win() == 1) {
prossima_mossa_x = i;
p_caselle[i] = -1;
break;
}
p_caselle[i] = -1;
}
}
}
if (prossima_mossa != -1 && c_win() != 1 && prossima_mossa_x == -1) {
p_caselle[prossima_mossa] = -1;
if (mossa(1, prossima_mossa)) {
//Serial.println("Giocatore X ha scelto la casella " + String(prossima_mossa + 1));
lcd.print(String() + "Casella : " + (prossima_mossa+1)) ;
delay(3000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Turno O") ;
turno = 0;
delay(1000);
}
}else
{
lcd.print(String() + "Casella : " + (miglior_mossa+1)) ;
//Serial.println("Giocatore X ha scelto la casella " + String(miglior_mossa + 1));
delay(3000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Turno O") ;
turno = 0;
delay(1000);
}
} else {
turno = 1;
}
} else {
int casella_casuale;
do {
casella_casuale = random(0, 9);
} while (!mossa(1, casella_casuale));
lcd.print(String() + "Casella : " + (casella_casuale+1)) ;
//Serial.println("Giocatore X ha scelto la casella " + String(casella_casuale + 1));
delay(3000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Turno O") ;
turno = 0;
delay(1000);
}
}
win();
}
}
void win(){
int winner = -1;
winner = c_win();
if (winner != -1){
save(winner);
turno = 0;
}
}
int c_win(){
int winner = -1;
if(p_caselle[0] == 1 && p_caselle[1] == 1 && p_caselle[2] == 1){winner = 1;}
if(p_caselle[3] == 1 && p_caselle[4] == 1 && p_caselle[5] == 1){winner = 1;}
if(p_caselle[6] == 1 && p_caselle[7] == 1 && p_caselle[8] == 1){winner = 1;}
if(p_caselle[0] == 1 && p_caselle[3] == 1 && p_caselle[6] == 1){winner = 1;}
if(p_caselle[1] == 1 && p_caselle[4] == 1 && p_caselle[7] == 1){winner = 1;}
if(p_caselle[2] == 1 && p_caselle[5] == 1 && p_caselle[8] == 1){winner = 1;}
if(p_caselle[0] == 1 && p_caselle[4] == 1 && p_caselle[8] == 1){winner = 1;}
if(p_caselle[2] == 1 && p_caselle[4] == 1 && p_caselle[6] == 1){winner = 1;}
if(p_caselle[0] == 0 && p_caselle[1] == 0 && p_caselle[2] == 0){winner = 0;}
if(p_caselle[3] == 0 && p_caselle[4] == 0 && p_caselle[5] == 0){winner = 0;}
if(p_caselle[6] == 0 && p_caselle[7] == 0 && p_caselle[8] == 0){winner = 0;}
if(p_caselle[0] == 0 && p_caselle[3] == 0 && p_caselle[6] == 0){winner = 0;}
if(p_caselle[1] == 0 && p_caselle[4] == 0 && p_caselle[7] == 0){winner = 0;}
if(p_caselle[2] == 0 && p_caselle[5] == 0 && p_caselle[8] == 0){winner = 0;}
if(p_caselle[0] == 0 && p_caselle[4] == 0 && p_caselle[8] == 0){winner = 0;}
if(p_caselle[2] == 0 && p_caselle[4] == 0 && p_caselle[6] == 0){winner = 0;}
int _cas = 0;
for (int cas = 0; cas < 9; cas++) {
if (p_caselle[cas] != -1) {
_cas++;
}
}
if (_cas == 9 && winner == -1) {
winner = 2;
}
return winner;
}
void save(int winner){
for(int i = 0;i<9; i++){
if(winner == 0){
database[partite][i] = p_caselle[i];
if (p_caselle[i] == 0){
database[partite + 1][i] = 1;
}else if(p_caselle[i] == 1){
database[partite + 1][i] = 0;
}else{
database[partite + 1][i] = p_caselle[i];
}
}else
{
database[partite][i] = p_caselle[i];
}
p_caselle[i] = -1;
}
database[partite][9] = winner;
if(winner == 0){database[partite + 1][9] = 1;}
if(database[partite][9] == 1){Serial.println("win x"); win_x +=1;}
if(database[partite][9] == 0){Serial.println("win o"); win_o +=1;}
if(database[partite][9] == 2){Serial.println("pareggio"); p_win +=1;}
if (partite > 5){Serial.println("Addestramento..."); train();}
partite+=1;
_init();
}
void tabellone(int p_caselle[9]) {
String p_caselle_convert[9];
for(int i =0;i<9;i++){
if(p_caselle[i] == 1){p_caselle_convert[i] = "x";}
if(p_caselle[i] == 0){p_caselle_convert[i] = "o";}
if(p_caselle[i] == -1){p_caselle_convert[i] = String(i + 1);}
}
Serial.println(" " + p_caselle_convert[0] + " | " + p_caselle_convert[1] + " | " + p_caselle_convert[2]);
Serial.println("-----------");
Serial.println(" " + p_caselle_convert[3] + " | " + p_caselle_convert[4] + " | " + p_caselle_convert[5]);
Serial.println("-----------");
Serial.println(" " + p_caselle_convert[6] + " | " + p_caselle_convert[7] + " | " + p_caselle_convert[8]);
}
int move_b(int player,int pos){
if(player = 0) {
s_base.write(pos_o[ms_o][0]);
delay(1000);
s_brc.write(pos_o[ms_o][1]);
delay(1000);
s_avb.write(pos_o[ms_o][2]);
}else{
s_base.write(pos_x[ms_x][0]);
delay(1000);
s_brc.write(pos_x[ms_x][1]);
delay(1000);
s_avb.write(pos_x[ms_x][2]);
}
delay(500);
digitalWrite(pin_rele, HIGH);
set_servo();
delay(1000);
s_base.write(pos_x[ms_x][0]);
delay(500);
s_brc.write(pos_x[ms_x][1]);
delay(500);
s_avb.write(pos_x[ms_x][2]);
delay(500);
digitalWrite(pin_rele, LOW);
delay(500);
set_servo();
}
void move_servo(int str , int stp,int type){
if (str<stp){
for(int ser = str; ser < stp ;ser++){
if (type = 0){
s_base.write(ser);
}else if (type = 1){
s_brc.write(ser);
}else
{
s_avb.write(ser);
}
}
}
if (str>stp){
for(int ser = str; ser > stp ;ser--){
if (type = 0){
s_base.write(ser);
}else if (type = 1){
s_brc.write(ser);
}else
{
s_avb.write(ser);
}
}
}
}
int getBtn(){
int btn = -1;
if(analogRead(btn_f1) > 600 && analogRead(btn_f1) < 900){btn = 1;}
if(analogRead(btn_f1) < 600 && analogRead(btn_f1) > 100 ){btn = 2;}
if(analogRead(btn_f1) < 70){btn = 3;}
if(analogRead(btn_f2) >200 && analogRead(btn_f2) < 500){btn = 4;}
if(analogRead(btn_f2) < 300 && analogRead(btn_f2) > 100 ){btn = 5;}
if(analogRead(btn_f2) < 70){btn = 6;}
if(analogRead(btn_f3) >200 && analogRead(btn_f3) < 500){btn = 7;}
if(analogRead(btn_f3) < 300 && analogRead(btn_f3) > 100 ){btn = 8;}
if(analogRead(btn_f3) < 70){btn = 9;}
if(digitalRead(btn_str) != 1){_init();}
if(digitalRead(btn_stp) != 1){}
if(digitalRead(btn_rst) != 1){}
return btn;
}
void reset_t(){
}