493 lines
30 KiB
MQL5
493 lines
30 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Main.mqh |
|
|
//| Copyright 2025, Niquel Mendoza. |
|
|
//| https://www.mql5.com/es/users/nique_372/news |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Niquel Mendoza."
|
|
#property link "https://www.mql5.com/es/users/nique_372/news"
|
|
#property strict
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\\Figuras\\Figuras.mqh"
|
|
|
|
#include <OpenCLCts\\CLFast.mqh>
|
|
COpenCL g_cl;
|
|
|
|
#define cl_kernels_total 1
|
|
#define cl_buffers_total 2
|
|
#define cl_kernel_tetris_asingocuped 0
|
|
#define cl_buffer_pxocuped 1
|
|
#define cl_buffer_px_utilizados 0
|
|
|
|
|
|
//---
|
|
#define kernel_tetris_asingocuped_arg_px_utilizados 0
|
|
#define kernel_tetris_asingocuped_arg_pxocuped 1
|
|
|
|
#resource "kernels.cl" as const string cl_program
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CEspacioUtilizable
|
|
{
|
|
private:
|
|
//--- Geeral
|
|
bool m_init;
|
|
CCanvasCustom* m_canvas;
|
|
// Tomaremos en cuenta todo el anchjo de canvas..
|
|
// Los peixles que se le dan no es que esten dentro del tablero son globales
|
|
bool m_pixeles_utilizados[];
|
|
int m_width;
|
|
int m_height;
|
|
uint m_clr_clean;
|
|
|
|
//--- Cordenadas del espacio estas no estan dentro estan dentro
|
|
int m_y_init;
|
|
int m_y_end;
|
|
int m_x_init;
|
|
int m_x_end;
|
|
int m_xsize_util;
|
|
|
|
//---
|
|
void OnDeleteEspacio(int x1, int y1, int x2, int y2);
|
|
|
|
|
|
public:
|
|
CEspacioUtilizable(void);
|
|
// ~CEspacioUtilizable(void);
|
|
|
|
//---
|
|
void Init(CCanvasCustom* c, int yinit, int yend, int xinit, int xend, uint clr_clean);
|
|
|
|
//---
|
|
__forceinline int XInit() const { return m_x_init; }
|
|
__forceinline int XEnd() const { return m_x_end; }
|
|
__forceinline int YInit() const { return m_y_init; }
|
|
__forceinline int YEnd() const { return m_y_end; }
|
|
__forceinline int XSize() const { return m_xsize_util; }
|
|
|
|
//---
|
|
void Resetear();
|
|
|
|
//---
|
|
int AddFigure(CTetrisFigura* figura); // Retonra el numero de espacios eliminados
|
|
|
|
|
|
//---
|
|
// Retorna true si un pixel ha sido utilizado
|
|
__forceinline bool PixelUtilizado(int x, int y) const { return m_pixeles_utilizados[(y * m_width + x)]; }
|
|
int PixelXGetIndexInicioAtras(int x, int y) const;
|
|
int PixelXGetIndexInicioAdelante(int x, int y) const;
|
|
int PixelGetIndexInicioAbajo(int x, int y) const;
|
|
|
|
//---
|
|
__forceinline int MinY(int x) { return m_pixeles_utilizados[x];} // Deviñee el minimo y para un x
|
|
|
|
|
|
|
|
|
|
// Verifica que las cordenas y esten dentro del recutado.. veriiffca pro arriba osea que sean menores o iguales m_y_end
|
|
__forceinline bool YCorDentro(int y) const;
|
|
|
|
//---
|
|
bool XColisionAdelante(const int &x_cordinates[], int xref) const;
|
|
bool XColisionAtras(const int &x_cordinates[], int xref) const;
|
|
|
|
int GetMaxErrorY(int& y_cordinates[], int yref);
|
|
bool YColision(const int& y_cordinates[], int yref) const;
|
|
|
|
int GetMaxErrorXAdelente(int &x_cordinates[], int xref);
|
|
int GetMaxErrorXAtras(int &x_cordinates[], int xref);
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CEspacioUtilizable::CEspacioUtilizable(void)
|
|
: m_canvas(NULL), m_init(false)
|
|
{
|
|
g_cl.AddLogFlags(LOG_ALL);
|
|
g_cl.ContextCreate(CL_USE_ANY);
|
|
g_cl.ProgramCreate(cl_program);
|
|
g_cl.SetBuffersCount(cl_buffers_total);
|
|
g_cl.SetKernelsCount(cl_kernels_total);
|
|
g_cl.KernelCreate(cl_kernel_tetris_asingocuped, "Tetris_AsingOcuped");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CEspacioUtilizable::OnDeleteEspacio(int x1, int y1, int x2, int y2)
|
|
{
|
|
uint pixels[];
|
|
m_canvas.GetPixelsArray(pixels);
|
|
|
|
//---
|
|
const int px_init = m_canvas.GetIndex(x1, y1);
|
|
const int px_end = m_canvas.GetIndex(x2, y2);
|
|
const int offset = (fabs(y2 - y1) + 1) * m_width;
|
|
|
|
|
|
//--- Reduce las cordenas relaes
|
|
for(int px = px_end; px >= px_init; px--)
|
|
{
|
|
pixels[px + offset] = pixels[px];
|
|
m_pixeles_utilizados[px] = false;
|
|
|
|
//---
|
|
pixels[px] = m_clr_clean;
|
|
}
|
|
|
|
//---
|
|
m_canvas.SetPixelsArray(pixels);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CEspacioUtilizable::Init(CCanvasCustom *c, int yinit, int yend, int xinit, int xend, uint clr_clean)
|
|
{
|
|
//---
|
|
if(m_init)
|
|
return;
|
|
|
|
//---
|
|
m_canvas = c;
|
|
m_y_end = yend;
|
|
m_y_init = yinit;
|
|
m_x_init = xinit;
|
|
m_x_end = xend;
|
|
m_clr_clean = clr_clean;
|
|
m_xsize_util = fabs(m_x_end - m_x_init) + 1;
|
|
|
|
//---
|
|
m_width = c.Width();
|
|
m_height = c.Height();
|
|
ArrayResize(m_pixeles_utilizados, c.TotalPixels()); // Pixeles utilizados
|
|
|
|
m_init = true;
|
|
Resetear(); // Arrays
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CEspacioUtilizable::Resetear()
|
|
{
|
|
//---
|
|
for(int i = 0; i < ArraySize(m_pixeles_utilizados); i++)
|
|
m_pixeles_utilizados[i] = false;
|
|
|
|
//---
|
|
for(int x = 0; x < m_width; x++)
|
|
{
|
|
const int idx = ((m_y_end + 1) * m_width) + x;
|
|
m_pixeles_utilizados[idx] = true; // Borde Inferior
|
|
}
|
|
|
|
// m_canvas.LineHorizontal(0, m_width - 1, m_y_end + 1, ColorToARGB(clrAliceBlue));
|
|
|
|
//--- Bordes
|
|
for(int y = 0; y < m_height; y++)
|
|
{
|
|
m_pixeles_utilizados[m_canvas.GetIndex(m_x_init - 1, y)] = true; // Borde incial
|
|
m_pixeles_utilizados[m_canvas.GetIndex(m_x_end + 1, y)] = true; // Borde final
|
|
}
|
|
|
|
//--- Limpiamos el fondo
|
|
m_canvas.FillRectangle(m_x_init, m_y_init, m_x_end, m_y_end, m_clr_clean);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
// -1: Estra dentro de los rangos no hay pixel cercano
|
|
// -2: Fuera de rango
|
|
|
|
#define TET_ESPU_FUERA_NO_COLISION -1
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
int CEspacioUtilizable::PixelXGetIndexInicioAtras(int x, int y) const
|
|
{
|
|
int i = x;
|
|
while(i >= m_x_init)
|
|
{
|
|
//--- Encontrado
|
|
if(PixelUtilizado(i, y))
|
|
return i + 1;
|
|
|
|
//--- Siguiente
|
|
i--;
|
|
}
|
|
return m_x_init;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
int CEspacioUtilizable::PixelXGetIndexInicioAdelante(int x, int y) const
|
|
{
|
|
int i = x;
|
|
while(i <= m_x_end)
|
|
{
|
|
//--- Encontrado
|
|
if(PixelUtilizado(i, y))
|
|
return i - 1;
|
|
|
|
//--- Siguiente
|
|
i++;
|
|
}
|
|
return m_x_end;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
int CEspacioUtilizable::PixelGetIndexInicioAbajo(int x, int y) const
|
|
{
|
|
int i = y;
|
|
while(i <= m_y_end)
|
|
{
|
|
//--- Encontrado
|
|
if(PixelUtilizado(x, i))
|
|
return i - 1;
|
|
|
|
//--- Siguiente
|
|
i++;
|
|
}
|
|
return m_y_end;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CEspacioUtilizable::YColision(const int &y_cordinates[], int yref) const
|
|
{
|
|
const int total = ArraySize(y_cordinates);
|
|
int x, y;
|
|
for(int pos_x = 0; pos_x < total; pos_x++)
|
|
{
|
|
m_canvas.PixelDecompress(y_cordinates[pos_x], x, y);
|
|
const int cordc = PixelGetIndexInicioAbajo(x, yref); // Retorna Y
|
|
if(cordc == TET_ESPU_FUERA_NO_COLISION) // NO hay algo cercano para ete X
|
|
{
|
|
continue;
|
|
}
|
|
// De lo contraio si hay un obejto para colisionar, asi que verifiquemos si la cordanas lo atravisa
|
|
if(y >= cordc) // Colisiona
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
int CEspacioUtilizable::GetMaxErrorY(int &y_cordinates[], int yref)
|
|
{
|
|
const int total = ArraySize(y_cordinates);
|
|
int max_err = INT_MIN;
|
|
int x, y;
|
|
for(int pos_x = 0; pos_x < total; pos_x++)
|
|
{
|
|
m_canvas.PixelDecompress(y_cordinates[pos_x], x, y);
|
|
const int cordc = PixelGetIndexInicioAbajo(x, yref); // Retorna Y
|
|
if(cordc == TET_ESPU_FUERA_NO_COLISION) // NO hay algo cercano para ete X
|
|
{
|
|
continue;
|
|
}
|
|
// De lo contraio si hay un obejto para colisionar, asi que verifiquemos si la cordanas lo atravisa
|
|
const int err = y - cordc;
|
|
if(err > max_err)
|
|
max_err = err;
|
|
}
|
|
|
|
|
|
if(max_err <= 0) // quiere decir que no hay error
|
|
return 0;
|
|
else
|
|
return max_err;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CEspacioUtilizable::XColisionAdelante(const int &x_cordinates[], int xref) const
|
|
{
|
|
const int total = ArraySize(x_cordinates);
|
|
int x, y;
|
|
for(int pos_y = 0; pos_y < total; pos_y++)
|
|
{
|
|
m_canvas.PixelDecompress(x_cordinates[pos_y], x, y);
|
|
const int cordc = PixelXGetIndexInicioAdelante(xref, y); // Codenada del pixel mas cercano, Xref
|
|
if(cordc == TET_ESPU_FUERA_NO_COLISION) // NO hay algo cercano para ete Y
|
|
{
|
|
continue;
|
|
}
|
|
// De lo contraio si hay un obejto para colisionar, asi que verifiquemos si la cordanas lo atravisa
|
|
if(x >= cordc) // Colisiona
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
int CEspacioUtilizable::GetMaxErrorXAdelente(int &x_cordinates[], int xref)
|
|
{
|
|
const int total = ArraySize(x_cordinates);
|
|
int max_err = INT_MIN;
|
|
int x, y;
|
|
for(int pos_y = 0; pos_y < total; pos_y++)
|
|
{
|
|
m_canvas.PixelDecompress(x_cordinates[pos_y], x, y);
|
|
const int cordc = PixelXGetIndexInicioAdelante(xref, y); // Codenada del pixel mas cercano
|
|
if(cordc == TET_ESPU_FUERA_NO_COLISION) // NO hay algo cercano para ete Y, POR LO QUE NO HAY ERROR
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const int err = x - cordc;
|
|
if(err > max_err)
|
|
max_err = err;
|
|
}
|
|
|
|
if(max_err <= 0) // quiere decir que no hay error
|
|
return 0;
|
|
else
|
|
return max_err;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CEspacioUtilizable::XColisionAtras(const int &x_cordinates[], int xref) const
|
|
{
|
|
const int total = ArraySize(x_cordinates);
|
|
int x, y;
|
|
for(int pos_y = 0; pos_y < total; pos_y++)
|
|
{
|
|
m_canvas.PixelDecompress(x_cordinates[pos_y], x, y);
|
|
const int cordc = PixelXGetIndexInicioAtras(x, y); // Codenada del pixel mas cercano
|
|
if(cordc == TET_ESPU_FUERA_NO_COLISION) // NO hay algo cercano para ete Y
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(x <= cordc) // Colisiona
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
int CEspacioUtilizable::GetMaxErrorXAtras(int &x_cordinates[], int xref)
|
|
{
|
|
const int total = ArraySize(x_cordinates);
|
|
int max_err = INT_MIN;
|
|
int x, y;
|
|
for(int pos_y = 0; pos_y < total; pos_y++)
|
|
{
|
|
m_canvas.PixelDecompress(x_cordinates[pos_y], x, y);
|
|
const int cordc = PixelXGetIndexInicioAtras(x, y); // Codenada del pixel mas cercano
|
|
if(cordc == TET_ESPU_FUERA_NO_COLISION) // NO hay algo cercano para ete Y
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const int err = cordc - x;
|
|
if(err > max_err)
|
|
max_err = err;
|
|
}
|
|
|
|
|
|
if(max_err <= 0) // quiere decir que no hay error
|
|
return 0;
|
|
else
|
|
return max_err;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline bool CEspacioUtilizable::YCorDentro(int y) const
|
|
{
|
|
return (m_y_init <= y);
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int CEspacioUtilizable::AddFigure(CTetrisFigura *figura)
|
|
{
|
|
int px_ocuped[];
|
|
|
|
//--- Agregamos
|
|
figura.GetOcupatePixels(px_ocuped);
|
|
const uint total = px_ocuped.Size();
|
|
const uint total_px = m_pixeles_utilizados.Size();
|
|
//Print("Size: ", ArraySize(m_pixeles_utilizados));
|
|
/*
|
|
for(int i = 0; i < total; i++)
|
|
{
|
|
// Print("Index: ", px_ocuped[i]);
|
|
m_pixeles_utilizados[px_ocuped[i]] = true; // Pixel ocupaod
|
|
}
|
|
*/
|
|
//---
|
|
g_cl.BufferFromArray(cl_buffer_px_utilizados, m_pixeles_utilizados, 0, total_px, CL_MEM_ALLOC_HOST_PTR | CL_MEM_WRITE_ONLY);
|
|
g_cl.BufferFromArray(cl_buffer_pxocuped, px_ocuped, 0, total, CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_ONLY);
|
|
g_cl.SetArgumentBuffer(cl_kernel_tetris_asingocuped, kernel_tetris_asingocuped_arg_px_utilizados, cl_buffer_px_utilizados);
|
|
g_cl.SetArgumentBuffer(cl_kernel_tetris_asingocuped, kernel_tetris_asingocuped_arg_pxocuped, cl_buffer_pxocuped);
|
|
static const uint offset[1] = {0};
|
|
const uint worksize[1] = { total };
|
|
g_cl.Execute(cl_kernel_tetris_asingocuped, 1, offset, worksize);
|
|
g_cl.BufferRead(cl_buffer_px_utilizados, m_pixeles_utilizados, 0, 0, total_px);
|
|
|
|
|
|
|
|
//--- Chekaeamos lso espacios si hay uno por eliminar
|
|
// Chekeamos si se creo un nuevo desde el minimo
|
|
const int yinit = figura.Y2();
|
|
const int yend = figura.Y1();
|
|
|
|
int y_to_delete[];
|
|
for(int y = yinit; y <= yend; y--)
|
|
{
|
|
bool lc = true;
|
|
for(int x = m_x_init; x <= m_x_end; x++)
|
|
{
|
|
if(!PixelUtilizado(x, y)) // Si no esta fallo no hay colision en esta linea
|
|
{
|
|
lc = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---
|
|
if(lc)
|
|
{
|
|
y_to_delete.Push(y); // Y al final;
|
|
}
|
|
}
|
|
|
|
// Eliminamos
|
|
if(y_to_delete.Size() > 0)
|
|
{
|
|
//---
|
|
int x1 = m_x_init;
|
|
int y1 = yend;
|
|
int x2 = m_x_end;
|
|
int y2 = yinit;
|
|
|
|
//--- Graficamente
|
|
m_canvas.FillRectangle(x1, y1, x2, y2, m_clr_clean);
|
|
|
|
//--- Internamente
|
|
OnDeleteEspacio(x1, y1, x2, y2);
|
|
return (int)y_to_delete.Size();
|
|
}
|
|
return 0;
|
|
}
|
|
//+------------------------------------------------------------------+
|