// Match3 Board - Version 1.0
// Created: 28/10/2017 11:46:51
// John Ryland (jryland@xiaofrog.com)
// InvertedLogic, (C) Copyright 2017
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include "board.h"
#include "common.h"
#include "gameDB.h"
bool createBoard(Board& a_board, int a_width, int a_height)
{
const size_t allocatedBytes = a_width*a_height*sizeof(int);
a_board.m_width = a_width;
a_board.m_height = a_height;
a_board.m_board = new int[allocatedBytes];
if (!a_board.m_board)
return false;
memset(a_board.m_board, 0, allocatedBytes);
return true;
}
bool generateRandomBoard(Board& a_board, int a_width, int a_height, int a_numTileTypes)
{
if (!createBoard(a_board, a_width, a_height))
return false;
for (int j = 0; j < a_height; j++)
for (int i = 0; i < a_width; i++)
a_board.m_board[j*a_width + i] = rand() % a_numTileTypes;
return true;
}
bool generateBoardWithNoMatch3s(Board& a_board, int a_width, int a_height, int a_numTileTypes)
{
int iter = 0;
while (iter < 100)
{
iter++;
if (!generateRandomBoard(a_board, a_width, a_height, a_numTileTypes))
continue;
if (!hasAMatch3(a_board)) {
printf("iterated %i times in generateBoardWithNoMatch3s\n", iter);
return true;
}
destroyBoard(a_board);
}
return false;
}
bool generatePlayableBoard(Board& a_board, int a_width, int a_height, int a_numTileTypes)
{
int iter = 0;
while (iter < 100)
{
iter++;
if (!generateBoardWithNoMatch3s(a_board, a_width, a_height, a_numTileTypes))
continue;
if (hasMoveAvailable(a_board)) {
printf("iterated %i times in generatePlayableBoard\n", iter);
return true;
}
destroyBoard(a_board);
}
return false;
}
void destroyBoard(Board& a_board)
{
delete[] a_board.m_board;
}
void printBoard(const Board& a_board)
{
for (int i = 0; i < a_board.m_width+2; i++)
printf("-");
printf("\n");
for (int j = 0; j < a_board.m_height; j++)
{
printf("|");
for (int i = 0; i < a_board.m_width; i++)
{
printf("%i", a_board.m_board[j*a_board.m_width + i]);
}
printf("|\n");
}
for (int i = 0; i < a_board.m_width+2; i++)
printf("-");
printf("\n");
}
bool getMatch3(const Board& a_board, int& x1, int& y1, int& x2, int& y2, int& x3, int& y3)
{
for (int j = 0; j < a_board.m_height; j++)
{
int countSame = 0;
int prev = -1;
for (int i = 0; i < a_board.m_width; i++)
{
int cur = a_board.m_board[j*a_board.m_width + i];
if (prev == cur) {
countSame++;
if (countSame >= 3) {
x1 = i - 2; x2 = i - 1; x3 = i;
y1 = y2 = y3 = j;
return true;
}
} else {
countSame = 1;
prev = cur;
}
}
}
for (int i = 0; i < a_board.m_width; i++)
{
int countSame = 0;
int prev = -1;
for (int j = 0; j < a_board.m_height; j++)
{
int cur = a_board.m_board[j*a_board.m_width + i];
if (prev == cur) {
countSame++;
if (countSame >= 3) {
x1 = x2 = x3 = i;
y1 = j - 2; y2 = j - 1; y3 = j;
return true;
}
} else {
countSame = 1;
prev = cur;
}
}
}
return false;
}
bool getMatches(const Board& a_board, BoardMatch& a_matches)
{
// TODO
return false;
}
bool hasAMatch3(const Board& a_board)
{
int x1, y1, x2, y2, x3, y3;
return getMatch3(a_board, x1, y1, x2, y2, x3, y3);
}
bool trySwapCheck(int x1, int y1, int x2, int y2, const Board& a_board)
{
int w = a_board.m_width;
int h = a_board.m_height;
// some pre-condition checking
if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0 || x1 >= w || y1 >= h || x2 >= w || y2 >= h)
{
printf("trySwap called with tile position out of range: %i,%i -> %i,%i dims: %i,%i\n",
x1, y1, x2, y2, w, h);
return false;
}
return true;
}
int trySwapH(int x1, int y1, int x2, int y2, const Board& a_board)
{
if (y1 != y2) { printf("non-horizontal swap %i %i\n", y1, y2); return 0; }
if (!trySwapCheck(x1, y1, x2, y2, a_board)) return 0;
int _x1 = std::min(x1,x2);
int _x2 = std::max(x1,x2);
if (_x2 - _x1 != 1) { printf("non-single line swap %i %i\n", x1, x2); return 0; }
/*
// optimization so we just do a faster check
// checkRange from _x1 - 2 -> _x2 + 2 y1 - 2 -> y1 + 2
int cx1 = std::max(_x1 - 2, 0);
int cx2 = std::min(_x2 + 2, a_board.m_width - 1);
int cy1 = std::max(y1 - 2, 0);
int cy2 = std::min(y1 + 2, a_board.m_height - 1);
*/
int tmp = a_board.m_board[y1*a_board.m_width + _x1];
a_board.m_board[y1*a_board.m_width + _x1] = a_board.m_board[y1*a_board.m_width + _x2];
a_board.m_board[y1*a_board.m_width + _x2] = tmp;
bool ret = hasAMatch3(a_board);
tmp = a_board.m_board[y1*a_board.m_width + _x1];
a_board.m_board[y1*a_board.m_width + _x1] = a_board.m_board[y1*a_board.m_width + _x2];
a_board.m_board[y1*a_board.m_width + _x2] = tmp;
return (ret) ? 1 : 0;
}
int trySwapV(int x1, int y1, int x2, int y2, const Board& a_board)
{
if (x1 != x2) { printf("non-vertical swap %i %i\n", x1, x2); return 0; }
if (!trySwapCheck(x1, y1, x2, y2, a_board)) return 0;
int _y1 = std::min(y1,y2);
int _y2 = std::max(y1,y2);
if (_y2 - _y1 != 1) { printf("non-single line swap %i %i\n", y1, y2); return 0; }
int tmp = a_board.m_board[_y1*a_board.m_width + x1];
a_board.m_board[_y1*a_board.m_width + x1] = a_board.m_board[_y2*a_board.m_width + x1];
a_board.m_board[_y2*a_board.m_width + x1] = tmp;
bool ret = hasAMatch3(a_board);
tmp = a_board.m_board[_y1*a_board.m_width + x1];
a_board.m_board[_y1*a_board.m_width + x1] = a_board.m_board[_y2*a_board.m_width + x1];
a_board.m_board[_y2*a_board.m_width + x1] = tmp;
return (ret) ? 1 : 0;
}
bool hasMoveAvailable(const Board& a_board)
{
int moves = 0;
for (int j = 0; j < a_board.m_height/2; j++)
{
for (int i = 0; i < a_board.m_width/2; i++)
{
moves += trySwapH( i,j, i+1,j, a_board);
if (moves) { printf("move avail: %i %i\n", i, j); return true; }
moves += trySwapV( i,j, i,j+1, a_board);
if (moves) { printf("move avail: %i %i\n", i, j); return true; }
}
for (int i = a_board.m_width/2; i < a_board.m_width; i++)
{
moves += trySwapH( i,j, i-1,j, a_board);
if (moves) { printf("move avail: %i %i\n", i, j); return true; }
moves += trySwapV( i,j, i,j+1, a_board);
if (moves) { printf("move avail: %i %i\n", i, j); return true; }
}
if (moves)
return true;
}
for (int j = a_board.m_height/2; j < a_board.m_height; j++)
{
for (int i = 0; i < a_board.m_width/2; i++)
{
moves += trySwapH( i,j, i+1,j, a_board);
if (moves) { printf("move avail: %i %i\n", i, j); return true; }
moves += trySwapV( i,j, i,j-1, a_board);
if (moves) { printf("move avail: %i %i\n", i, j); return true; }
}
for (int i = a_board.m_width/2; i < a_board.m_width; i++)
{
moves += trySwapH( i,j, i-1,j, a_board);
if (moves) { printf("move avail: %i %i\n", i, j); return true; }
moves += trySwapV( i,j, i,j-1, a_board);
if (moves) { printf("move avail: %i %i\n", i, j); return true; }
}
if (moves)
return true;
}
if (moves)
return true;
return false;
}
bool canSwapTiles(const Board& a_board, int x1, int y1, int x2, int y2)
{
return trySwapH(x1, y1, x2, y2, a_board) || trySwapV(x1, y1, x2, y2, a_board);
}