tiistai 13. huhtikuuta 2021

SHAKKIKELLO

 

Onkin ollut aikaa ajatella mitä sitä keksisi. Uutisista on tullut runsaasti ohjeita miten varoa, väistää, suojautua ja siivota. Kaikkea kertyy vuosien mittaan ja laatikoita siivotessa eteen sattui shakkilauta. En tosin enää pelaa, enkä ole koskaan ollutkaan kovin hyvä pelaaja, mutta ajattelin, että shakkikellon tekeminen Arduinolle olisi ehkä mielekäs haaste.

 Shakissa ja ohjelmoinnissa on se selkeä ero, että pelatessa jokainen virhe johtaa häviön suuntaan, mutta ohjelmoinnissa oppimiseen (kunhan onnistuu korjaamaan). Niin tämäkin pienin askelin ja virheiden kautta lähti ilokseni toimimaan suunnitellulla tavalla.

 Kotelo voisi olla hienompikin. On siinä kuitenkin se hyvä puoli, että se on kierrätyskamaa. Käyttöenergiansa kello saa 9 V:n neppariparistosta. LCD-näyttö saa syöttönsä Arduinon 5 V:n lähdöstä.

  Kello käynnistyy virtakytkimestä. Painamalla painiketta, lähtee vastapelaajan tikutus käyntiin. Kun vastapelaaja saa siirtonsa tehtyä ja painaa omaa nappiaan, pysähtyy hänen kellonsa ja toinen käynnistyy. Kellot laskevat sekunteja, minuutteja ja tunteja. Tunnit on rajoitettu yhdeksään (9). Maksimi peliaika on siis 2 * 9 tuntia, 59 minuuttia ja 59 sekuntia. Minuutit ja sekunnit kiertävät (59 => 0), niitä ei pysäytetä, mutta tuon jälkeen pitää kirjata käsin.


 OHJELMA 61

 /************************************************
 *  Ohjelman nimi: ShakkiKello61_v6
 *  11.04.2021
 *  Shakkikello LCD-näytöllä
 *  A-painike käynnistää B:n ajan laskun
 *  ja B-painike A:n ajanlaskun
 *  Molemmat painikkeet lyhyesti, pysäyttää ajan
 *  Molemmat yli 2s nollaa ajat.
 ***********************************************/

// MÄÄRITTELYT:
// LCD-näyttö
#include <LiquidCrystal.h>
LiquidCrystal lcd(3, 2, 7,6,5,4);

// Tekstit
    char tx1[] = "PELAAJA B";
    char tx2[] = "PELAAJA A";   

// Liityntöjen määrittelyt
    // Pelaajan A määrittelyt
    const int Con_PelA = 8; // Pelaajan A painike
    boolean Bol_PelA = false;
    boolean Bol_ValintaA = false;
    boolean Kep_PelA = false;
    int Seq_PelA = 1;
    int Int_SekA = 0;
    int Int_MinA = 0;
    int Int_TunA = 0;
    int Int_PainA = 0;
    unsigned long Ulo_PelA  = 0;

   // Pelaajan B määrittelyt
    const int Con_PelB = 9;// Pelaajan B painike
    boolean Bol_PelB = false;    
    boolean Bol_ValintaB = false;
    boolean Kep_PelB = false;    
    int Seq_PelB = 1;
    int Int_SekB = 0;
    int Int_MinB = 0;
    int Int_TunB = 0;
    int Int_PainB = 0;
    unsigned long Ulo_PelB  = 0;     

    // Pelaajien yhteiset määrittelyt
    boolean Bol_Tauko = false;
    unsigned long Ulo_Nollaus = 0;

// Kellon ja tahdistuksen määrittelyt
    unsigned long Ulo_MilliSek = 0;
    unsigned long Ulo_Tulostus = 0;
    int Int_Viive = 100;

// ALIOHJELMAT
// Tekstin päivitys
void Fun_Teksti(int kohta, int rivi, char teksti[]){
  lcd.setCursor(kohta, rivi);
  lcd.print(teksti);
}// Teksti_ali loppu

// Ajan päivitys
void Fun_Aika(int kohta, int rivi, int lukema){
  lcd.setCursor(kohta, rivi);
  lcd.print(lukema);
}// Aika_ali loppu

// ASETUKSET:
void setup(){                  
 Serial.begin(9600);    
  lcd.begin(20,2);
  lcd.clear();     
  Fun_Teksti(0, 0, tx1);
  Fun_Teksti(11, 0, tx2);
  pinMode(Con_PelA, INPUT_PULLUP);
  pinMode(Con_PelB, INPUT_PULLUP);  
}// Asetuksen loppu


// PÄÄLOOPPI                   
void loop(){
// Sisäisen kellon päivitys
Ulo_MilliSek = millis();

// Pelaajat A & B
Bol_PelA = !digitalRead(Con_PelA);
Bol_PelB = !digitalRead(Con_PelB);
Bol_ValintaA = Bol_PelA == 1 && Bol_PelB == 0;
Bol_ValintaB = Bol_PelA == 0 && Bol_PelB == 1;
Bol_Tauko = Bol_PelA == 1 && Bol_PelB == 1;
if(Bol_Tauko == true){ Kep_PelA = false; Kep_PelB = false;}
if(Bol_Tauko == false){Ulo_Nollaus = Ulo_MilliSek;}
if(Bol_Tauko == true && Ulo_MilliSek > (Ulo_Nollaus + 1000)){
    Int_SekA = 0; Int_MinA = 0;  Int_TunA = 0;
    Int_SekB = 0; Int_MinB = 0;  Int_TunB = 0;  
}

// Pelaajan B valinta painikkeella A
switch (Seq_PelA) {
  case 1:
    if(Bol_ValintaA == false) {Int_PainA = 0;
    }else{Int_PainA++;}
    if(Bol_ValintaA == true &&  Int_PainA > Int_Viive){
      Kep_PelB = false; Kep_PelA = true;
      Ulo_PelB = Ulo_MilliSek;
      Seq_PelA = 2;}
    break;
  case 2:
    if(Bol_ValintaA == false){Seq_PelA = 1;}
    break;
}// Sekvenssin A loppu

// Pelaajan A valinta painikkeella B
switch (Seq_PelB) {
  case 1:
     if(Bol_ValintaB == false){Int_PainB = 0;
    }else{Int_PainB++;}     
    if(Bol_ValintaB == true &&  Int_PainB > Int_Viive){
      Kep_PelA = false; Kep_PelB = true;
      Ulo_PelA = Ulo_MilliSek;      
      Seq_PelB = 2;}
    break;
  case 2:
    if(Bol_ValintaB == false){Seq_PelB = 1;}
    break;
}// Sekvenssin B loppu

//A-pelaajan laskuri
if(Ulo_MilliSek > Ulo_PelA + 999 && Kep_PelB == true){
   Int_SekA++;
   Ulo_PelA = Ulo_MilliSek;}
   if(Int_SekA > 59){Int_SekA = 0; Int_MinA++;}
   if(Int_MinA > 59){Int_MinA = 0; Int_TunA++;}
   if (Int_TunA > 9){Int_TunA = 9;}

// B-pelaajan laskuri
if(Ulo_MilliSek > Ulo_PelB + 999 && Kep_PelA == true){
   Int_SekB++;
   Ulo_PelB = Ulo_MilliSek;}
   if(Int_SekB > 59){Int_SekB = 0; Int_MinB++;}
   if(Int_MinB > 59){Int_MinB = 0; Int_TunB++;}
   if (Int_TunB > 9){Int_TunB = 9;}

// Pelaajien ajan tulostus
if(Ulo_MilliSek > Ulo_Tulostus + 499){

  if(Int_TunB < 1){Fun_Teksti(1,1,"0");
  }else{Fun_Aika(1,1,Int_TunB);}
  Fun_Teksti(2,1,"t");
  if(Int_MinB < 10){Fun_Teksti(3,1,"0"); Fun_Aika(4,1,Int_MinB);
  }else{Fun_Aika(3,1,Int_MinB);}
  Fun_Teksti(5,1,"m");
  if(Int_SekB < 10){Fun_Teksti(6,1,"0"); Fun_Aika(7,1,Int_SekB);
  }else{Fun_Aika(6,1,Int_SekB);}
  Fun_Teksti(8,1,"s");

 if(Int_TunA < 1){Fun_Teksti(12,1,"0");
  }else{Fun_Aika(12,1,Int_TunA);}
  Fun_Teksti(13,1,"t");
  if(Int_MinA < 10){Fun_Teksti(14,1,"0"); Fun_Aika(15,1,Int_MinA);
  }else{Fun_Aika(14,1,Int_MinA);}
  Fun_Teksti(16,1,"m");
  if(Int_SekA < 10){Fun_Teksti(17,1,"0"); Fun_Aika(18,1,Int_SekA);
  }else{Fun_Aika(17,1,Int_SekA);}
  Fun_Teksti(19,1,"s");
 
  Ulo_Tulostus = Ulo_MilliSek;
}// Aikatulostuksen loppu
 delay(1);
} // Pääohjelma LOPPU