2020年6月4日木曜日

XIAOで解くペントミノの動画・スケッチ

今朝、たまたま銀行の通帳の記帳をしたら、10万円の給付金が振り込まれていました。その後、郵便で振り込んだ旨の通知書も届きました。でも、2~3日前に申請用紙も郵送されてきていて、なんか無駄遣いの気がする。オンライン申請した人を除外する手間の方がかかるのでしょうか? オンラインと紙申請を二重に出した人をチェックするのにも手間がかかると思うけど。

給付金を当てにして、テレワーク用の椅子を注文してしまっていました。明日には届く予定。アーロンチェアがよかったけど、20万円くらいするので(見た目は)似たような感じの中国製です。それでも2万5千円ほどでした。しばらくテレワークが続くようなので腰痛対策への投資です。

さて、XIAOで解くペントミノの動画を作りました。iPhone6sのカメラですが、液晶パネルの偏光板との相性がよくないのか、画面はあまり綺麗に撮れません。微妙な色の違いが分からない。肉眼ではもっと綺麗に見えます。


スケッチです。無保証です。
//------------------------------------------------------------
//                                               2020.6.4 naka
//
//  Pentomino puzzle solver by seeeduino XIAO with ST7735 LCD
//
//  Board size : 10x6, 12x5, 15x4, 20x3、8x8(center 4 cells are blank)
//  Note       : Except for 10x6, the number of solutions is double
//               because of the algorithm.
//
//------------------------------------------------------------
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>
//-----------------------------------------
//  define constant for XIAO port
//-----------------------------------------
#define TFT_CS   4
#define TFT_DC   6
#define TFT_SDA 10
#define TFT_SCL  8
#define TFT_RST  5
#define SelectPin 2   // Select Switch (active low)
#define StartPin  3   // Start Switch  (active low)

//-----------------------------------------
//  define constant for LCD ST7735
//-----------------------------------------
#define INITR_BLACKTAB  INITR_MINI160x80
#define SelectMenuX 80
#define SelectMenuY 15
#define SelectMenuH 12
#define ColorNum  12
#define DARKGREEN 0x02E0
#define DARKBLUE  0x0017
#define PARPLE    0x991F
#define GLAY      0x7BEF

//-----------------------------------------
//  define gloval variables for Display
//-----------------------------------------
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_SDA, TFT_SCL, TFT_RST);
uint16_t color_map[ColorNum] = {ST77XX_RED, ST77XX_WHITE, ST77XX_GREEN, DARKGREEN,
                                ST77XX_BLUE, DARKBLUE, ST77XX_CYAN, ST77XX_MAGENTA,ST77XX_YELLOW,
                                ST77XX_ORANGE,PARPLE,GLAY,};  
uint16_t disp_offset_x = 0;
uint16_t disp_offset_y = 0;
uint16_t disp_cellsize = 10;
uint16_t select_board_size = 0;
int      Continue = 0;

//-----------------------------------------
//  define constant for pentomino solver
//-----------------------------------------
#define PIECE_NO        12
#define PIECE_CELL_NO    5
#define PIECE_DIRECTION  8
#define UNUSE            0
#define USE              1
#define INHIBIT         -1
#define EMPTY            0
#define EMPTY_FLAG    9999
#define MAX_X           22
#define MAX_Y           15
#define GOOD             0
#define NG               1

//-----------------------------------------
//  define structure and variable for Solver
//-----------------------------------------
int16_t  board[MAX_X][MAX_Y];
int16_t  use_piece[PIECE_NO];
int16_t  seq_no;
int16_t  size_x;
int16_t  size_y;
int16_t  hsize_x;
int16_t  hsize_y;
int16_t  blank_no;

struct piece_s {
 int16_t x;
 int16_t y;
};

struct piece_org_s {
  struct piece_s piece[PIECE_CELL_NO];
};

struct piece_x {
 int no;
  struct {
    int16_t x[PIECE_CELL_NO-1];
    int16_t y[PIECE_CELL_NO-1];
  } type[PIECE_DIRECTION];
} piece[PIECE_NO];

//-----------------------------------------
//  Arduino(seeeduino) setup()
//-----------------------------------------
void setup() {
  pinMode(SelectPin, INPUT_PULLUP);
  pinMode(StartPin,  INPUT_PULLUP);

  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
  tft.setRotation(3);

  while(1) {
    tft.fillScreen(ST77XX_BLACK);  // Erace display
    select_board();
  
    Continue = 0;                  // execution mode 0:step
    init_piece();
    init_board(select_board_size);
    tft.fillScreen(ST77XX_BLACK);  // Erace display

    search_start();
  
    while (digitalRead(SelectPin)==HIGH && digitalRead(StartPin)==HIGH) {}
  }
}

void loop() {
  // nothing
}

//-----------------------------------------
//  function to make pieces (12 tyes)
//-----------------------------------------
void copy_piece(struct piece_org_s *target, struct piece_org_s *source)
{
  int i;
  for (i=0; i<PIECE_CELL_NO; i++) {
    target->piece[i].x = source->piece[i].x;
    target->piece[i].y = source->piece[i].y;
  }
}

void mirror_piece(struct piece_org_s *target,
                  struct piece_org_s *source)
{
  int i;
  for (i=0; i<PIECE_CELL_NO; i++) {
    target->piece[i].x = source->piece[i].x;
    target->piece[i].y = -(source->piece[i].y);
  }
}

void rotate_piece(struct piece_org_s *target)
{
  int i;
  int tmp;
  for (i=0; i<PIECE_CELL_NO; i++) {
    tmp = target->piece[i].x;
    target->piece[i].x = -(target->piece[i].y);
    target->piece[i].y = tmp;
  }
}

int sort_piece(struct piece_s *a, struct piece_s *b)
{
  if (a->x > b->x) return(1);
  else if (a->x == b->x) {
    if (a->y > b->y) return(1);
  }
  return(-1);
}

void origin_piece(struct piece_org_s *target)
{
  int i;
  qsort(&(target->piece[0]),PIECE_CELL_NO,sizeof(struct piece_s),
        (__compar_fn_t)sort_piece);
  for (i=PIECE_CELL_NO-1; i>=0; i--) {
    target->piece[i].x -= target->piece[0].x;
    target->piece[i].y -= target->piece[0].y;
  }
}

void entry_piece(int piece_no,struct piece_org_s *target)
{
  int i;
  int same;
  int no;

  origin_piece(target);

  same = 0;
  for (i=0; i<piece[piece_no].no; i++) {
    if (piece[piece_no].type[i].x[0] == target->piece[1].x &&
        piece[piece_no].type[i].y[0] == target->piece[1].y &&
        piece[piece_no].type[i].x[1] == target->piece[2].x &&
        piece[piece_no].type[i].y[1] == target->piece[2].y &&
        piece[piece_no].type[i].x[2] == target->piece[3].x &&
        piece[piece_no].type[i].y[2] == target->piece[3].y &&
        piece[piece_no].type[i].x[3] == target->piece[4].x &&
        piece[piece_no].type[i].y[3] == target->piece[4].y) {
       same = 1;
       break;
     }
  }

  if (same == 0) {
    no = piece[piece_no].no++;
    for (i=0; i<PIECE_CELL_NO-1; i++) {
      piece[piece_no].type[no].x[i] = target->piece[1+i].x;
      piece[piece_no].type[no].y[i] = target->piece[1+i].y;
    }
  }
}

void init_piece()
{
  int i,j,k;
  int no;
  struct piece_org_s piece_tmp;

  static struct piece_org_s piece_org[PIECE_NO] = {
     1,0,  0,1,  1,1,  2,1,  1,2,   /*  0.   X      */
                                    /*      XXX     */
                                    /*       X      */
     0,0,  1,0,  2,0,  3,0,  4,0,   /*  1.  XXXXX   */

     0,0,  1,0,  2,0,  3,0,  0,1,   /*  2.  XXXX    */
                                    /*      X       */

     0,0,  1,0,  2,0,  3,0,  1,1,   /*  3.  XXXX    */
                                    /*       X      */

     0,0,  1,0,  2,0,  0,1,  2,1,   /*  4.  XXX     */
                                    /*      X X     */

     0,0,  1,0,  2,0,  0,1,  1,1,   /*  5.  XXX     */
                                    /*      XX      */

     0,0,  1,0,  2,0,  2,1,  3,1,   /*  6.  XXX     */
                                    /*        XX    */

     0,0,  0,1,  1,1,  2,1,  1,2,   /*  7.  X       */
                                    /*      XXX     */
                                    /*       X      */

     0,0,  0,1,  1,1,  2,1,  2,2,   /*  8.  X       */
                                    /*      XXX     */
                                    /*        X     */

     0,0,  1,0,  1,1,  2,1,  2,2,   /*  9.  XX      */
                                    /*       XX     */
                                    /*        X     */

     0,0,  1,0,  2,0,  0,1,  0,2,   /* 10.  XXX     */
                                    /*      X       */
                                    /*      X       */

     0,0,  1,0,  2,0,  1,1,  1,2,   /* 12.  XXX     */
                                    /*       X      */
                                    /*       X      */
  };

  /*** Init ***/
  for (i=0; i<PIECE_NO; i++) {
    piece[i].no = 0;
    for (j=0; j<PIECE_DIRECTION; j++) {
      for (k=0; k<PIECE_CELL_NO-1; k++) {
        piece[i].type[j].x[k] = 0;
        piece[i].type[j].y[k] = 0;
      }
    }
  }

  /*** Main ***/
  for (i=0; i<PIECE_NO; i++) {
    for (j=0; j<2; j++) {    /*** normal and mirror   ***/
      if (j==0) copy_piece  (&piece_tmp,&piece_org[i]);
      else      mirror_piece(&piece_tmp,&piece_org[i]);
      for (k=0; k<4; k++) {  /*** 4 rotate directions ***/
        if (k>0) rotate_piece(&piece_tmp);
        entry_piece(i,&piece_tmp);
      }
    }
  }

}

//-----------------------------------------
// Display answer
//-----------------------------------------
int display()
{
  int x,y,i;

  char buff[16];
  sprintf(buff,"no:%4d",seq_no);              // answer number

  tft.fillRect(132, 10, 25, 8, ST77XX_BLACK); // Erase
  tft.setCursor(115, 10);
  tft.setTextColor(ST77XX_WHITE);             // Display answer number
  tft.print(buff);

  for (y=1; y<=size_y; y++) {
    uint16_t ypos = disp_offset_y + (y-1) * disp_cellsize;
    for (x=1; x<=size_x; x++) {
      uint16_t color = color_map[board[x][y]-1];
      uint16_t xpos  = disp_offset_x + (x-1) * disp_cellsize;
      tft.fillRect(xpos, ypos, disp_cellsize, disp_cellsize, color); // Display cell
    }
  }

  return(check_sw()); // check select,start switch to Start/Stop/Continue
    
  return(0);
}

/*------------------------*/
/*  check_blank_area      */
/*------------------------*/
void search_blank(int x,int y) {
    board[x][y] = EMPTY_FLAG;
    blank_no++;
    if (board[x][y+1]==EMPTY) search_blank(x,y+1);
    if (board[x+1][y]==EMPTY) search_blank(x+1,y);
    if (board[x-1][y]==EMPTY) search_blank(x-1,y);
    if (board[x][y-1]==EMPTY) search_blank(x,y-1);
  }

void search_blank_clear(int x,int y) {
    while(x<=size_x) {
      while(y<=size_y) {
        if (board[x][y]==EMPTY_FLAG) board[x][y] = EMPTY;
        y++;
      }
      y = 1;
      x++;
    }
  }

/*------------------------*/
/*  check_board           */
/*------------------------*/
int check_board(int x,int y)
{

  if (board[x+1][y]  !=EMPTY &&
      board[x][y+1]  !=EMPTY) return NG;

  if (board[x][y+2]  !=EMPTY &&
      board[x+1][y+1]!=EMPTY &&
      board[x+1][y]  !=EMPTY) return NG;

  if (board[x][y+1]  !=EMPTY &&
      board[x+1][y+1]!=EMPTY &&
      board[x+2][y]  !=EMPTY &&
      board[x+1][y-1]!=EMPTY) return NG;

  blank_no =0;
  search_blank(x,y);
  search_blank_clear(x,y);
  if (blank_no%PIECE_CELL_NO!=0) return NG;

  return GOOD;
}

/*------------------------*/
/*  put_piece             */
/*------------------------*/
int search(int posx,int posy,int put_no)
{
  int i,j;
  int avno;
  int piece_no;

  while(board[posx][posy]!=EMPTY) {
    posy++;
    if (posy>size_y) {
      posy = 1;
      posx++;
    }
  }
  /** check board **/
  if (check_board(posx, posy)) return(0);

  for (i=1; i<PIECE_NO; i++) {

    if (use_piece[i]==UNUSE) {

      for (j=0; j<piece[i].no; j++) {

        /*** area check ***/
        if (board[piece[i].type[j].x[0]+posx]
                 [piece[i].type[j].y[0]+posy]==EMPTY &&
            board[piece[i].type[j].x[1]+posx]
                 [piece[i].type[j].y[1]+posy]==EMPTY &&
            board[piece[i].type[j].x[2]+posx]
                 [piece[i].type[j].y[2]+posy]==EMPTY &&
            board[piece[i].type[j].x[3]+posx]
                 [piece[i].type[j].y[3]+posy]==EMPTY) {
          /*** put ***/
          board[posx][posy] =
          board[piece[i].type[j].x[0]+posx]
               [piece[i].type[j].y[0]+posy] =
          board[piece[i].type[j].x[1]+posx]
               [piece[i].type[j].y[1]+posy] =
          board[piece[i].type[j].x[2]+posx]
               [piece[i].type[j].y[2]+posy] =
          board[piece[i].type[j].x[3]+posx]
               [piece[i].type[j].y[3]+posy] = i+1; // piece no.

          if (put_no!=PIECE_NO) {
            use_piece[i] = put_no;
            /*** search next piece place ***/
            if (search(posx,posy+1,put_no+1)<0) {
              return(-1);
            }
            use_piece[i] = UNUSE;
          }
          else {
            /*** display ***/
            seq_no++;
            if (display()<0) {
              return (-1);
            }
          }

          /*** get last piece ***/
          board[posx][posy] =
          board[piece[i].type[j].x[0]+posx]
               [piece[i].type[j].y[0]+posy] =
          board[piece[i].type[j].x[1]+posx]
               [piece[i].type[j].y[1]+posy] =
          board[piece[i].type[j].x[2]+posx]
               [piece[i].type[j].y[2]+posy] =
          board[piece[i].type[j].x[3]+posx]
               [piece[i].type[j].y[3]+posy] = EMPTY;
        }

      } /* end of for-j loop */

    }  /* end of unuse if (unuse piece) */

  }  /* end of for-i loop */

  return(0);

} /* end of search */

/*------------------------*/
/*  initialize            */
/*------------------------*/
void init_board(uint16_t size)
{
  int i,j;

  /*** set area type ***/
  size_x = 10;
  size_y =  6;
  hsize_x = 5;
  hsize_y = 3;

    if (size==0) {     // 10x6 size
      size_x = 10;
      size_y =  6;
      hsize_x = 5;
      hsize_y = 3;
      disp_offset_x = 0;
      disp_offset_y = 10;
      disp_cellsize = 10;
    }
    else if (size==1) { // 12x5 size
      size_x = 12;
      size_y =  5;
      hsize_x = 6;
      hsize_y = 4;
      disp_offset_x = 10;
      disp_offset_y = 20;
      disp_cellsize = 10;
    }
    else if (size==2) { // 15x4 size
      size_x = 15;
      size_y =  4;
      hsize_x = 13;
      hsize_y = 2;
      disp_offset_x = 5;
      disp_offset_y = 30;
      disp_cellsize = 10;
    }
    else if (size==3) {  // 20x3 size
      size_x = 20;
      size_y =  3;
      hsize_x = 10;
      hsize_y = 2;
      disp_offset_x = 0;
      disp_offset_y = 30;
      disp_cellsize = 8;
    }
    else if (size==4) { // 8x8 size
      size_x =  8;
      size_y =  8;
      hsize_x = 4;
      hsize_y = 4;
      disp_offset_x = 10;
      disp_offset_y = 0;
      disp_cellsize = 10;
    }
    
  /*** init counter ***/
  seq_no = 0;

  /*** init board ***/
  for (i=0; i<MAX_X; i++)
    for (j=0; j<MAX_Y; j++)
      board[i][j] = INHIBIT;

  for (i=1; i<=size_x; i++)
    for (j=1; j<=size_y; j++)
      board[i][j] = EMPTY;

  if (size_x==8 && size_y==8) {
    board[4][4] = INHIBIT;
    board[4][5] = INHIBIT;
    board[5][4] = INHIBIT;
    board[5][5] = INHIBIT;
  }

  /*** init use_piece ***/
  for (i=0; i<PIECE_NO; i++)
    use_piece[i] = UNUSE;

} /*** end of init ***/

/*------------------------*/
/*  put X piece           */
/*------------------------*/
void search_start() {
  int posy = 3;
  int posx = 1;
  int put_no = 1;
  use_piece[0] = put_no;

  while(posx<hsize_x) {
    /*** put ***/
    if (board[piece[0].type[0].x[0]+posx]
             [piece[0].type[0].y[0]+posy]==EMPTY &&
        board[piece[0].type[0].x[1]+posx]
             [piece[0].type[0].y[1]+posy]==EMPTY &&
        board[piece[0].type[0].x[2]+posx]
             [piece[0].type[0].y[2]+posy]==EMPTY &&
        board[piece[0].type[0].x[3]+posx]
             [piece[0].type[0].y[3]+posy]==EMPTY) {
    board[posx][posy] =
    board[piece[0].type[0].x[0]+posx]
         [piece[0].type[0].y[0]+posy] =
    board[piece[0].type[0].x[1]+posx]
         [piece[0].type[0].y[1]+posy] =
    board[piece[0].type[0].x[2]+posx]
         [piece[0].type[0].y[2]+posy] =
    board[piece[0].type[0].x[3]+posx]
         [piece[0].type[0].y[3]+posy] = put_no;

    if (search(1,1,put_no+1)<0) {
      return;
    }

    /*** get ***/
    board[posx][posy] =
    board[piece[0].type[0].x[0]+posx]
         [piece[0].type[0].y[0]+posy] =
    board[piece[0].type[0].x[1]+posx]
         [piece[0].type[0].y[1]+posy] =
    board[piece[0].type[0].x[2]+posx]
         [piece[0].type[0].y[2]+posy] =
    board[piece[0].type[0].x[3]+posx]
         [piece[0].type[0].y[3]+posy] = EMPTY;

    }
    posy++;
    if (posy>hsize_y) {
      posy = 2;
      posx++;
    }
  }

  return;
}

//-----------------------------------------
//  Display 1st menu (select board menu)
//-----------------------------------------
void disp_selectmenu() {
  char* mode_tbl[5] = {"10x6","12x5","15x4","20x3"," 8x8"};
  
  tft.setTextColor(ST77XX_MAGENTA);
  tft.setTextSize(0);
  tft.setCursor(0, 0);
  tft.print("*** Pentomino Solver ***");
  tft.setTextSize(0);
  tft.setTextColor(ST77XX_WHITE);
  tft.setCursor(20, 24);
  tft.print("Select");
  tft.setCursor(20, 36);
  tft.print(" board");
  tft.setCursor(20, 48);
  tft.print("  size");

  for (int i=0;i<5;i++) {
    uint16_t x = SelectMenuX;
    uint16_t y = SelectMenuY + i * SelectMenuH;
    tft.setCursor(x, y);
    tft.setTextColor(ST77XX_WHITE);
    tft.print(mode_tbl[i]);
  }  
}

void disp_select_triangle(uint16_t mode) {
  uint16_t x1 = SelectMenuX-10, y1 = SelectMenuY + mode * SelectMenuH;
  uint16_t x2 = x1+3, y2 = y1 + SelectMenuH/4;
  uint16_t x3 = x1,   y3 = y1 + SelectMenuH/2;
  tft.fillRect(x1,15,7,80,ST77XX_BLACK);  // clear previous triangle
  tft.fillTriangle(x1,y1,x2,y2,x3,y3,ST77XX_RED);
}

//-----------------------------------------
//  Select board by Select Switch
//-----------------------------------------
void select_board() {
    disp_selectmenu();

    // Wait release Select,Start switch
    while(digitalRead(StartPin)==LOW || digitalRead(SelectPin)==LOW) {};

    // Move triangle mark each time the select switch
    disp_select_triangle(select_board_size);
    int select_sw = HIGH;
    int start_sw  = HIGH;
    while (1) {
      select_sw = digitalRead(SelectPin);
      start_sw  = digitalRead(StartPin); 
      if (select_sw==LOW) {
        select_board_size++;
        if (select_board_size>4) {
          select_board_size = 0;
        }
        disp_select_triangle(select_board_size);
        while (!digitalRead(SelectPin)) {} // wait release Serect SW
        delay(10);
      }
      else if (start_sw==LOW) {
        return;
      }
    }
}

//-----------------------------------------
// check SW status
//-----------------------------------------
int check_sw() {

  if (Continue==1) { // Continuas mode
    // Check stop of continuous mode
    if (digitalRead(StartPin)==LOW) {
      Continue = 0;  
      while (digitalRead(StartPin)==LOW) {
        if (digitalRead(SelectPin)==LOW) {
            return (-1); // Press Start and Select at the same time to end
        }
      }
    }
  }

  if (Continue==0) {  // Stepping mode
    while (digitalRead(SelectPin)==HIGH and digitalRead(StartPin)==HIGH) {}
    if (digitalRead(SelectPin)==LOW) {
      Continue = 1; // Continuas mode
    }
  }

  return(0);
}

//------------------------------------------------------------
//  end of file
//------------------------------------------------------------

0 件のコメント:

コメントを投稿