Пятнашки электронные

Вот подумалось о пятнашках на сенсорном экране. Но готового проекта не нашёл пока. С визуализацией ясно. Математическая модель понятна - двумерный массив, индекс элемента это положение, значение (0-пусто) это номинал фишки-квадрата. А как алгоритм работы проще реализовать?

Алгоритм работы чего?
Если общефилософски - при таче сразу проверять четыре стороны. Если одна свободна, то смещать картинку только при движении по тому вектору.

есть пятнашки на жава скрипт, но в понедельник
а вот ссылка на гугл диск
пятнашки

Работы с массивом. Образно говоря, если пальцем тронули элемент массива, смотрим нет ли рядом в ряду или столбце элемента в значении 0. Если есть - меняем местами элементы эти. Так?

Спасибо, попробую логику уловить.

Не забудьте проверять разрешима ли комбинация, а то нагенерите неразрешимых задач.

1 лайк

Так там нет неразрешимых комбинаций, если рядом нет пустого поля, то и делать ничего не надо. А если есть, то поменять нажатую с пустым полем, других условий на перемещение нету.

В игре пятнашка? Если высыпать фишки, а потом сложить их в коробку как попало, то там дофига неразрешимых комбинаций, т.е. таких из которых невозможно получить решение никакими правильными ходами.

ни разу в пятнашки не проигрывал.

В принципе да дофига. Вроде половина всех. Но удивительно, и я не припомню проигрышей в 15-ки. Что то в деЦтве я подсел и сыграно немало. Как то везло и все комбинации получались из первой “правильной” половины (число перестановок - четное) . В казино бы такую везучесть.

Это потом надо будет подумать как автоматически тасовать фишки. А пока планирую ручную тасовку на такой исходник:
01
Читал вроде в википедии, что такая комбинация не собираема.

в пятнашках все автоматом на random

Было несколько исполнений. У меня была с “нерассыпными” фишками - они входили пазами друг в друга и перемешивались только правильными движениями. В такой невозможно сделать неразрешимую комбинацию. А вот в такой, где фишки просто лежат в коробочке и их можно высыпать, а потом по одной сложить - там сколько угодно.

Совершенно верно. И обратно тоже - из такой комбинации невозможно получить нормальную.

Тогда рандомная тусовка элементов массива не пройдёт и нужно функцию более хитрую выдумывать.

Из «правильно собранного набора» за рандомное число от n до m (где n минимально необходимое значение) количества шагов рандомной выборкой «направления» движения «замиксовать». ))

Или так не получится?

Почему не пройдёт? Просто контролировать, чтобы не получилась неразрешима комбинация. Кстати, любую неразрешимую можно превратить в разрешимую перестановкой пары фишек между собой. Это надо предусмотреть в программе - делов то!

Значит самый простой способ получить разрешимую комбинацию - менять соседние фишки между собой четное количество раз.


VID_20240608_190030
Сделал пока без старта-перетусовывания, надо над темами-дизайном задуматься.

//пятнашки
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <XPT2046_Touchscreen.h>// Библиотека для работы с сенсорным экраном
#include <SPI.h>
#include "ris_.h"//файл хранения массивов фотокартинок
#define TFT_CS     17
#define TFT_DC     20
#define CS_PIN  14
//#define TFT_RST -1            // Пин подключения вывода RESET (ПРИ -1 СОЕДИНЯЕМ С +3,3В)
//#define TFT_MISO 16           // Пин подключения вывода дисплея SDO(MISO)
//#define TFT_MOSI 19           // Пин подключения вывода дисплея SDI(MOSI)
//#define TFT_CLK 18            // Пин подключения вывода дисплея SCK
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS,  TFT_DC);//
XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts

byte massiv_[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};//массив для хранения положения фишек и их отрисовки на экране
 int x, y;                         // Переменные для работы с координатами нажатий
 
void setup() {
  tft.begin();
  tft.setRotation(2);
 tft.fillScreen(tft.color565(0,0,0)); 

  ts.begin();
  ts.setRotation(2);
 drawFoto(0,0,ris_0,240,320);// заставка игрушки

  }
void loop() {
 // 
  if(ts.touched()) { // Если имеются данные с сенсорного модуля
 TS_Point p = ts.getPoint();                      // Считываем с него данные
    y = map(p.y,220,3720,0,319);                  // Считываем и преобразуем координату нажатия Y
    x =map(p.x,275,3830,0,240);                   // Считываем и преобразуем  координату нажатия X           
    if((x!=-1) && (y!=-1))          // Если обе координаты в положительном диапазоне (т.е. если есть нажатие) 
     {
      x += 0;                      // Корректируем координату с учетом калибровочных данных
      y += 0;                       // Корректируем координату с учетом калибровочных данных

      hod_();   
      otrisovka_();
  
     }
  delay(20);   
 }
// 

}
//
void drawFoto(uint16_t x,uint16_t y, const uint8_t *bitmap,uint16_t w,uint16_t h) {//функция вывода фотокартинки
if(x<0||x+w>240||y<0||y+h>320){return;} 
// tft.setAddrWindow(x,y,w,h);
 SPI.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));
  digitalWrite(TFT_DC, HIGH);
  digitalWrite(TFT_CS, LOW);
  tft.setAddrWindow(x,y,w,h); 
 for(int j=0; j<h; j++) {
    for(int i=0; i<2*w; i=i+2) {
    SPI.transfer(bitmap[i+1+j*2*w]);SPI.transfer(bitmap[i+j*2*w]);
    }
  }
  digitalWrite(TFT_CS, HIGH);
  SPI.endTransaction();
 ///  
}
//
//функция вывода фрагмента фотокартинки размером w*h,x,y - положение фрагмента на экране, x1,y1,w1,h1 - выбор фрагмента из массива
void drawFoto_fragment(int x,int y, const uint8_t *bitmap,int w,int h,int x1,int y1,int w1,int h1) {
if(x<0||x+w1>240||y<0||y+h1>320){return;} 
// tft.setAddrWindow(x,y,w1,h1);
 SPI.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));
  digitalWrite(TFT_DC, HIGH);
  digitalWrite(TFT_CS, LOW);
  tft.setAddrWindow(x,y,w1,h1); 
 for(int j=0; j<h; j++) {
    for(int i=0; i<2*w; i=i+2) {
      if(i>=2*x1&&i<2*(x1+w1)&&j>=y1&&j<y1+h1){
       SPI.transfer(bitmap[i+1+j*2*w]);SPI.transfer(bitmap[i+j*2*w]);
      }  
   }
  }
  digitalWrite(TFT_CS, HIGH);
  SPI.endTransaction();
 //  
}
////////////////////////////////////////////////////////////////////
void otrisovka_(){
 for(int i=0;i<4;i++){ 
  for(int j=0;j<4;j++){
 int i1=(massiv_[i][j]-1)/4;int j1=(massiv_[i][j]-1)%4;   
drawFoto_fragment(60*i,60*j,ris_0,240,320,60*i1,60*j1,60,60);// 
 }
 } 
}
//
void hod_(){
 int i,j;
 byte C; 
if(x<240&&y<240){
i=(x-0)/60;j=(y-0)/60;
if(i+1<4&&massiv_[i+1][j]==16){
C=massiv_[i][j];massiv_[i][j]=16;massiv_[i+1][j]=C;
}
if(i-1>=0&&massiv_[i-1][j]==16){
C=massiv_[i][j];massiv_[i][j]=16;massiv_[i-1][j]=C;
}
if(j+1<4&&massiv_[i][j+1]==16){
C=massiv_[i][j];massiv_[i][j]=16;massiv_[i][j+1]=C;
}
if(j-1>=0&&massiv_[i][j-1]==16){
C=massiv_[i][j];massiv_[i][j]=16;massiv_[i][j-1]=C;
}  
  }  
}
//

Самый надёжный способ это имитировать перестановки фишек соответствующей перестановкой элементов массива… Может проще смотреть на него как на одномерный?

2 лайка

Самое простое, думаю, это взять “собранный” массив и пойти рандомайзом “взад” по геймплею. Взял рандом, как направление, и переставил в массиве элементы. Раз сто переставишь и все нормально перемешается. Главное - чтобы по кругу не пошло.

А, это уже предложили, смотрю.

2 лайка