//+------------------------------------------------------------------+ //| 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 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; } //+------------------------------------------------------------------+