Start Elkretssimulator Karnaughdiagram Quine McCluskey


Luffarschack (5 i rad) på Arduino

5 i rad eller luffarschack

Kärt barn har många namn. 5 i rad eller luffarschack eller fritt luffarschack. I professionella sammanhang är spelet modifierat lite och kallas gomoku eller renju. Vi ska inte grotta ner oss i detta och komplicera något här. Det gäller att få 5 i rad först! Typ.



Nya varianten med TM1638 -display

Vi kopplar in tm1638 -displayen. Mer om hur en tm1638 -display fungerar och hur du installerar biblioteket till den.



Förutsatt att du laddat in nedan program ser det då ut såhär när man startar programmet.



Så, datorn sätter ett kryss på 10,10.



Du kan nu mata in ditt motdrag genom att klicka på ovan knappar och när du är klar bekräftar du ditt drag.



Den som får 5 ringar eller kryss i rad först vinner.

Nedan är koden. Observera att denna kod är ett "hack". Du kan säkert göra ett luffarschack som spelar bättre än mitt. Gör det och hör av dig!

#include <TM1638.h>

#define DIO 8 
#define CLK 9
#define STB 10

#define HUMAN 1
#define COMPUTER 2

TM1638 module(DIO, CLK, STB);
byte buttons=0, lastbutton=0;

int x=10,y=10;
char str[32];
char points[15][15];
int ux,uy,pmax=0;
char sp[24][24];
int p[81]={
  0, 10, 20, 5,  100,  0,  10,  0,  200,
  3, 15,  0,15,  500,  0,   0,  0,    0,
  0,  0,100, 0,    0,  0, 100,  0, 2500,
  0,  0,  0, 0,    0,  0,   0,  0,    0,
  0,  0,  0, 0, 5000,  0,   0,  0,    0,
  0,  0,  0, 0,    0,  0,   0,  0,    0,
  0,  0, 70, 0,    0,  0,  70,  0,  200,
  0,  0,  0, 0,    0,  0,   0,  0,    0,
  0,  0,  0, 0,    0,  0, 500,  0,20000
  };

struct calcRet
{
  int winner;
  int cmx;
  int cmy;
};

void reset()
{
  for(int i=0;i<15;i++)
  for(int j=0;j<15;j++)
  {
    points[i][j] = 0;
  }
  for(int i=0;i<24;i++)
  for(int j=0;j<24;j++)
  {
    sp[i][j] = 0;
  }
  pmax=-1;
  x=10;
  y=10;
}

struct calcRet calc()
{
  int dx,dy,a,b,cmx=0,cmy=0,pnt,i,j,winner=0;
  struct calcRet cRet;
  pmax=-1;
  for(a=4;a<19;a++)
  for(b=4;b<19;b++)
  {
    if(sp[a][b]==0)
    {
      pnt=0;
      for(dx=-1;dx<2;dx++)
      for(dy=-1;dy<2;dy++)
      {
        if((dy!=0)||(dx!=0))
        {
          i=sp[a+dx*4][b+dy*4]*27+sp[a+dx*3][b+dy*3]*9+sp[a+dx*2][b+dy*2]*3+sp[a+dx][b+dy];
          if(p[i]==20000){winner=COMPUTER;};
          j=sp[a-dx*2][b-dy*2]+sp[a-dx][b-dy]*3;
          pnt=pnt+p[i];
          if((j==6)&&((i==53)||(i==26))) {pnt=pnt+90000;};
          if((j==8)&&((i==8)||(i==17)||(i==35)||(i==44)||(i==62)||(i==71))) {pnt=pnt+90000;};
          if(((j==3)||(j==4))&&((i==13)||(i==67))) {pnt=pnt+5000;};
          if((j==4)&&((i==4)||(i==22)||(i==49))) {pnt=pnt+5000;};
          if((i==53)&&(j==0)){pnt=pnt+500;};
          if((i==67)&&(j==0)){pnt=pnt+200;};
        }
      }
      pnt = (pnt+5)/5;
      if(pnt>255) pnt = 255;
      points[a-4][b-4]=pnt;
      if(pnt>pmax)
      {
        pmax=pnt;
        cmx=a;
        cmy=b;
      }
    }
    
    if(sp[a][b]==HUMAN)
    {
      for(dx=-1;dx<2;dx++)
      for(dy=-1;dy<2;dy++)
      {
        if((dy!=0)||(dx!=0))
        {
          i=sp[a+dx*4][b+dy*4]*27+sp[a+dx*3][b+dy*3]*9+sp[a+dx*2][b+dy*2]*3+sp[a+dx][b+dy];
          if(i==40){winner=HUMAN;};
        }
      }      
    }
  }

  cRet.winner = winner;
  cRet.cmy = cmy;
  cRet.cmx = cmx;
  return cRet;
}

void showXY(String mess, int x,int y)
{
  char num[10] = {'0','1','2','3','4','5','6','7','8','9'};
  char* str = (char *)"    ";
  str[0] = num[round(x/10)];
  str[1] = num[x-(round(x/10)*10)];
  str[2] = num[round(y/10)];
  str[3] = num[y-(round(y/10)*10)];
  module.setDisplayToString(mess, 0);
  module.setDisplayToString(str, 0, 4); 
}

void setup() 
{
  reset();
  showXY("data",x,y);
  sp[x+4][y+4]=COMPUTER; 
}

void loop()
{
  struct calcRet cRet;
  buttons=module.getButtons();
  if(lastbutton != buttons)
  {
    switch(buttons)
    {
      case 32:
      {
          if(cRet.winner == HUMAN)
          {
            module.setDisplayToString("du vann", 0);
            break;
          }
          if(sp[x+4][y+4]==0)
          {
            sp[ux+4][uy+4]=HUMAN;          
            cRet = calc();
            sp[cRet.cmx][cRet.cmy]=COMPUTER;
            x=cRet.cmx-4;
            y=cRet.cmy-4;
            showXY("data",x,y);
            if(cRet.winner == COMPUTER)
            {
              for(int i=0;i<10;i++)
              {              
                module.setDisplayToString("jag vann", 0);  
                delay(500);
                showXY("data",x,y);
                delay(500);
              }
              reset();
              x=10;
              y=10;
              module.setDisplayToString("--nytt--", 0);
              delay(1000);
              showXY("data",x,y);
            }
          }
          else
          {
            module.setDisplayToString("upptagen", 0);
            delay(2000);
            showXY("ditt",x,y);
          }
      }
      break;      
      case 64:
      {
        x++;
        x%=15;
        showXY("ditt",x,y);
      }
      break;
      case 128:
      {
        y++;
        y%=15;
        showXY("ditt",x,y);
      }
      break;    
    }
  }
  lastbutton = buttons;
}





Gamla varianten

Denna variant är ovan spel fast använder enbart 4 stycken 7-segmentdisplayer som output.

Följande behövs

- Arduino
- Kopplingsbräda
- Ett gäng sladdar
- 4 st. 7-segmentdisplayer
- 3 st. pushbuttons
- Resistanser

7-segment-displayer

Jag har på annat ställe beskrivit hur man kopplar in och får koden att fungera med ett flertal 7-segmentdisplayer om du vill förstå detaljerna här.

Ett annat problem är att vi behöver lite knappar (input) till vårt luffarschack. Minst 3 knappar behövs och det finns inga digitala in/ut-gångar kvar att använda. Men det finns ett antal analoga ingångar och det duger lika bra. Hur vi kan använda en analog ingång till ett flertal knappar är beskrivet här.

Koppla upp brädet

Tryck i 4 stycken displayer enligt nedan. Dessa 4 stycken displayer skall sedan i allt väsentligt parallell-kopplas enligt nedan, sånär som den gemensamma katoden.



Om man tar det systematiskt går det att få rätt. Det är tyvärr ofrånkomligt att det blir ett sladdinferno.







Vi behöver också lite knappar. Eftersom de digitala in/ut -gångarna är slut fixar vi detta genom att använda de analoga ingångarna för knapparna.





Funktion

Datorn börjar alltid i denna version. När datorn lägger sitt drag så blinkar draget. Första draget kommer bli 10, 10.

För att mata in ditt drag trycker du på knapp 1. Du ändrar x-värde med knapp 2 (upp) och 3 (ner). Sen trycker du på knapp 1 igen och ändrar y-värde på samma sätt. Sen trycker du på knapp 1 igen och datorn gör då sitt drag. Dvs;

1. Mata in ditt drag genom att först trycka #1.
2. Justera X upp och ner med knapp #2 och #3.
3. Tryck #1.
4. Justera Y upp och ner med knapp #2 och #3.
5. Tryck #1.

Datorn gör nu sitt drag och allt börjar om.

Om någon har vunnit så kommer displyerna blinka med fyra streck. För att börja om måste man dra ut strömmen och stoppa in den igen - eller ladda över programmet på nytt.

Sådana detaljer behöver förbättras, så du har har göra här! Kan du förbättra programmet, berätta vad du gjorde!

// Beroende på om du anv. gemensam anod (+) eller katod (-) så
// vänder du på nedan. #define _HIGH HIGH ger gemensam katod.
// funktion se http://el.st?5_i_rad

#define _HIGH HIGH
#define _LOW LOW

#define HUMAN 1
#define COMPUTER 2

#define STATE_CHANGE_X 2
#define STATE_CHANGE_Y 3
#define STATE_NEW_MOVE 4

#define BUTTON_UP 1
#define BUTTON_DOWN 2
#define BUTTON_OK 3

int state = STATE_NEW_MOVE;
int x=10,y=10;

int pval = 0;
int val = 0;
int keyPressed = 0;
int countNopress = 0;

bool flash = true;
int timeCtr = 0;
int win=0;

int segPins[8] = {2,3,4,5,6,7,8,9};    
int comPins[4] = {10,11,12,13};
int num[4] = {11,11,11,11};

int segLEDs[12][7]=
{
{1,1,1,1,1,1,0},
{0,1,1,0,0,0,0},
{1,1,0,1,1,0,1},
{1,1,1,1,0,0,1},
{0,1,1,0,0,1,1},
{1,0,1,1,0,1,1},
{1,0,1,1,1,1,1},
{1,1,1,0,0,0,0},
{1,1,1,1,1,1,1},
{1,1,1,0,0,1,1},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,1}
};

char str[32];
char points[15][15];
int ux,uy,pmax=0,uv=0;
char sp[24][24];
int p[81]={
  0, 10, 20, 5,  100,  0,  10,  0,  200,
  3, 15,  0,15,  500,  0,   0,  0,    0,
  0,  0,100, 0,    0,  0, 100,  0, 2500,
  0,  0,  0, 0,    0,  0,   0,  0,    0,
  0,  0,  0, 0, 5000,  0,   0,  0,    0,
  0,  0,  0, 0,    0,  0,   0,  0,    0,
  0,  0, 70, 0,    0,  0,  70,  0,  200,
  0,  0,  0, 0,    0,  0,   0,  0,    0,
  0,  0,  0, 0,    0,  0, 500,  0,20000
  };

int a,b,n=0;

struct calcRet
{
  int winner;
  int cmx;
  int cmy;
};

struct calcRet calc()
{
  int dx,dy,a,b,cmx=0,cmy=0,pnt,i,j,winner=0;
  struct calcRet cRet;
  pmax=-1;
  for(a=4;a<19;a++)
  for(b=4;b<19;b++)
  {
    if(sp[a][b]==0)
    {
      pnt=0;
      for(dx=-1;dx<2;dx++)
      for(dy=-1;dy<2;dy++)
      {
        if((dy!=0)||(dx!=0))
        {
          i=sp[a+dx*4][b+dy*4]*27+sp[a+dx*3][b+dy*3]*9+sp[a+dx*2][b+dy*2]*3+sp[a+dx][b+dy];
          if(p[i]==20000){winner=COMPUTER;};
          j=sp[a-dx*2][b-dy*2]+sp[a-dx][b-dy]*3;
          pnt=pnt+p[i];
          if((j==6)&&((i==53)||(i==26))) {pnt=pnt+90000;};
          if((j==8)&&((i==8)||(i==17)||(i==35)||(i==44)||(i==62)||(i==71))) {pnt=pnt+90000;};
          if(((j==3)||(j==4))&&((i==13)||(i==67))) {pnt=pnt+5000;};
          if((j==4)&&((i==4)||(i==22)||(i==49))) {pnt=pnt+5000;};
          if((i==53)&&(j==0)){pnt=pnt+500;};
          if((i==67)&&(j==0)){pnt=pnt+200;};
        }
      }
      pnt = (pnt+5)/5;
      if(pnt>255) pnt = 255;
      points[a-4][b-4]=pnt;
      if(pnt>pmax)
      {
        pmax=pnt;
        cmx=a;
        cmy=b;
      }
    }
    
    if(sp[a][b]==HUMAN)
    {
      for(dx=-1;dx<2;dx++)
      for(dy=-1;dy<2;dy++)
      {
        if((dy!=0)||(dx!=0))
        {
          i=sp[a+dx*4][b+dy*4]*27+sp[a+dx*3][b+dy*3]*9+sp[a+dx*2][b+dy*2]*3+sp[a+dx][b+dy];
          if(i==40){winner=HUMAN;};
        }
      }      
    }
    
  }

  cRet.winner = winner;
  cRet.cmy = cmy;
  cRet.cmx = cmx;
  return cRet;
}

int button(int v)
{
  if(v>450&&v<550) return BUTTON_UP;
  if(v>600&&v<700) return BUTTON_DOWN;
  if(v>850&&v<950) return  BUTTON_OK;
  return 0;
}

void showXY(int x, int y)
{
  num[3] = 0;
  num[1] = 0;
  if(x>9)
  {
    num[3] = 1;
    x -= 10;
  }
  num[2] = x;

  if(y>9)
  {
    num[1] = 1;
    y -= 10;
  }
  num[0] = y;  
}

int buttonPush(int k)
{
  struct calcRet cRet;
  switch(state)
  {
    case STATE_CHANGE_X:
      if(k == BUTTON_UP)
      {
        x++;
        if(x>15)
          x=1;        
        showXY(x,y);        
      }
      if(k == BUTTON_DOWN)
      {
        x--;  
        if(x<1)
          x=15;      
        showXY(x,y);          
      }
      if(k == BUTTON_OK)
      {
        num[0] = 11;
        num[1] = 11;
        state = STATE_CHANGE_Y;
      }
      break;

    case STATE_CHANGE_Y:
      if(k == BUTTON_UP)
      {
        y++;
        if(y>15)
          y=1;      
        showXY(x,y);
      }
      if(k == BUTTON_DOWN)
      {
        y--;  
        if(y<1)
          y=15;      
        showXY(x,y);
      }
     
      if(k == BUTTON_OK)
      {
        if(sp[x+4][y+4]==0)
        {
          ux=x;
          uy=y;
          sp[ux+4][uy+4]=HUMAN;          
          cRet = calc();
          if(cRet.winner == HUMAN)
          {
            flash = true;
            win = 1;            
          }
          else
          {
            //cRet = calc();
            sp[cRet.cmx][cRet.cmy]=COMPUTER;
            x=cRet.cmx-4;
            y=cRet.cmy-4;
            showXY(x,y);
            flash = true;
            if(cRet.winner == COMPUTER)
              win = 1;            
            else
            {
              state = STATE_NEW_MOVE;
            }
          }
        }
        else
        {
          state = STATE_NEW_MOVE;          
        }
      }      
      break;

    case STATE_NEW_MOVE:    
      if(k == BUTTON_OK)
      {      
        num[2] = 11;
        num[3] = 11;     
        flash = false;
        state = STATE_CHANGE_X;      
      }    
      break;
  }
}

void setup() 
{
  for (int i=0; i<8;i++)
    pinMode(segPins[i],OUTPUT);
    
  for (int i=0; i < 4;i++)
    pinMode(comPins[i],OUTPUT);  
  
  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  OCR1A =  100;
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS12) | (1 << CS10);
  TIMSK1 |= (1 << OCIE1A);
  sei();     

  showXY(x,y);
  sp[x+4][y+4]=COMPUTER;
}

ISR(TIMER1_COMPA_vect)
{
  clear();

  if(flash && timeCtr > 150)
  {
    digit(0,(win==1)?11:10);
    digit(1,(win==1)?11:10);
    digit(2,(win==1)?11:10);
    digit(3,(win==1)?11:10);    
  }
  else
  {
    digit(0,num[0]);
    digit(1,num[1]);
    digit(2,num[2]);
    digit(3,num[3]);
  }

  timeCtr++;
  if(timeCtr > 300)
    timeCtr = 0;

  pval = button(analogRead(0));
    
  if(pval == 0)
  {
    countNopress++;
    if(countNopress > 1)
      val = 0;    
  }
  else
  {
    if(val != pval)
    {
      val = pval;
      countNopress = 0;      
      buttonPush(val);
    }
  }
}

void digit(int d, int num)
{
  for (int d=0; d < 4;d++)
    digitalWrite(comPins[d], _HIGH);

  digitalWrite(comPins[d], _LOW);
  for (int i=0; i<7; i++)
    digitalWrite(segPins[i],segLEDs[num][i]?_HIGH:_LOW);

  delay(50);
}

void clear()
{
  for (int d=0; d < 4;d++)
  {
    digitalWrite(comPins[d], _HIGH);
      for (int i=0; i<7; i++)
        digitalWrite(segPins[i],_LOW);     
  }
}

void loop() 
{
  
}










Disclaimer: The sole purpose of this site is recreational and entertainment. This information and the circuits are provided as is without any express or implied warranties. While effort has been taken to ensure the accuracy of the information contained in this text, the authors/maintainers/contributors assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein. The contents of the articles above might be totally inaccurate, inappropriate, or misguided. There is no guarantee as to the suitability of said circuits and information for any purpose.
Sponsor webbhotell Karla Hosting