// DescriptionHere - game.cpp
// Created by John Ryland (jryland@xiaofrog.com), 29/10/2017
// Copyright (c) 2017 InvertedLogic
// All rights reserved.
#include <cstdio>
#include <cstdlib>
#include "game.h"
bool createNewGame(Game& a_game, int a_width, int a_height, int a_numTileTypes)
{
bool okay = false;
if (a_width == 0 || a_height == 0 || a_numTileTypes == 0)
okay = createBoard(a_game.m_board, 0, 0);
else
okay = generatePlayableBoard(a_game.m_board, a_width, a_height, a_numTileTypes);
if (okay)
{
printBoard(a_game.m_board);
printf("hasAMatch3 returned %s\n", hasAMatch3(a_game.m_board) ? "true" : "false");
printf("hasMoveAvailable returned %s\n", hasMoveAvailable(a_game.m_board) ? "true" : "false");
a_game.m_time = 0;
a_game.m_score = 0;
a_game.m_tileTypes = a_numTileTypes;
updateTiles(a_game);
}
if (!okay || !loadGameDB(a_game.m_gameDB))
return false;
return true;
}
void destroyGame(Game& a_game)
{
destroyBoard(a_game.m_board);
}
bool processInput(Game& a_game, const Input& a_input)
{
int x1 = a_input.startTileX;
int y1 = a_input.startTileY;
int x2 = a_input.endTileX;
int y2 = a_input.endTileY;
return swapTiles(a_game, x1, y1, x2, y2);
}
// normalize the game state
// directly translates the state of the board in to the tiles state so they are synced
void updateTiles(Game& a_game)
{
a_game.m_boardTileMap.clear();
a_game.m_tiles.clear();
int idx = 0;
for (int j = 0; j < a_game.height(); j++) {
for (int i = 0; i < a_game.width(); i++) {
Tile t;
t.type = BoardEvent::None;
t.userInit = false;
t.newX = t.x = i;
t.newY = t.y = j;
t.tileTypeId = a_game.m_board.m_board[idx];
a_game.m_tiles.push_back(t);
a_game.m_boardTileMap.push_back(idx);
idx++;
}
}
}
void addTile(Game& a_game, int idx, int x1, int y1, int x2, int y2, int value)
{
BoardEvent added;
added.type = BoardEvent::Added;
added.itemIndex = idx;
added.x = x1;
added.y = y1;
added.newX = x2;
added.newY = y2;
added.value = value;
added.userInit = false;
a_game.m_board.m_board[y2*a_game.width() + x2] = value;
a_game.m_events.push_back(added);
}
void removeTile(Game& a_game, int idx, int x, int y, int delay)
{
// printf("remove tile event adding: idx: %i x,y: %i %i\n", idx, x, y);
BoardEvent removed;
removed.type = BoardEvent::Removed;
removed.itemIndex = idx;
removed.x = x;
removed.y = y;
removed.delay = delay;
removed.value = a_game.m_board.m_board[y*a_game.width() + x];
removed.userInit = false;
a_game.m_events.push_back(removed);
}
void moveTile(Game& a_game, int idx, int x, int y, int x2, int y2, int delay)
{
BoardEvent moved;
moved.type = BoardEvent::Moved;
moved.itemIndex = idx;
moved.x = x;
moved.y = y;
moved.newX = x2;
moved.newY = y2;
moved.delay = delay;
moved.value = a_game.m_board.m_board[y*a_game.width() + x];
moved.userInit = false;
a_game.m_events.push_back(moved);
}
void swapTile(Game& a_game, int idx, int idx2, int x1, int y1, int x2, int y2)
{
BoardEvent swapped;
swapped.type = BoardEvent::Swapped;
swapped.itemIndex = idx;
swapped.newItemIndex = idx2;
swapped.x = x1;
swapped.y = y1;
swapped.newX = x2;
swapped.newY = y2;
swapped.value = a_game.m_board.m_board[y1*a_game.width() + x1];
swapped.userInit = false;
a_game.m_events.push_back(swapped);
}
void moveTilesDown(Game& a_game, int idx, int x, int y)
{
for (int i = y; i >= 0; i--) {
int idx = i * a_game.width() + x;
moveTile(a_game, idx, x, i, x, i+1, 0);
a_game.m_board.m_board[(i+1)*a_game.width() + x] = a_game.m_board.m_board[i*a_game.width() + x];
}
}
bool checkForMoreMatches_old(Game& a_game)
{
int x1, y1, x2, y2, x3, y3;
bool hasMatches = getMatch3(a_game.m_board, x1, y1, x2, y2, x3, y3);
int w = a_game.width();
int h = a_game.height();
int newIdx = w*h;
int idx;
if (hasMatches)
{
idx = y1 * w + x1;
removeTile(a_game, idx, x1, y1, 0);
moveTilesDown(a_game, idx, x1, y1-1);
addTile(a_game, newIdx++, x1, -1, x1, 0, rand() % 5);
idx = y2 * w + x2;
removeTile(a_game, idx, x2, y2, 0);
moveTilesDown(a_game, idx, x2, y2-1);
addTile(a_game, newIdx++, x2, -1, x2, 0, rand() % 5);
idx = y3 * w + x3;
removeTile(a_game, idx, x3, y3, 0);
moveTilesDown(a_game, idx, x3, y3-1);
addTile(a_game, newIdx++, x3, -1, x3, 0, rand() % 5);
}
else
{
if (!hasMoveAvailable(a_game.m_board))
{
BoardEvent noMoreMoves;
noMoreMoves.type = BoardEvent::NoMoreMoves;
noMoreMoves.userInit = false;
a_game.m_events.push_back(noMoreMoves);
}
}
return hasMatches;
}
void handleMatch(Game& a_game, const Pattern& a_pattern, int a_boardX, int a_boardY)
{
int w = a_game.width();
int h = a_game.height();
int newIdx = w*h;
const int pw = 5;
uint8_t offsets[pw];
uint8_t lengths[pw];
uint64_t po = a_pattern.m_offsets;
uint64_t pl = a_pattern.m_lengths;
for (int i = pw-1; i >= 0; i--) {
offsets[i] = po & 0xff;
lengths[i] = pl & 0xff;
po >>= 8;
pl >>= 8;
}
int removeDelay = 0;
for (int i = 0; i < pw; i++) {
int x = a_boardX + i;
int len = lengths[i];
int y1 = a_boardY + offsets[i];
int y2 = y1 + len;
for (int y = y1; y < y2; y++)
{
int idx = y * w + x;
removeTile(a_game, idx, x, y, removeDelay++);
}
if (y1 && len) {
for (int i = y1-1; i >= 0; i--) {
int idx = i * w + x;
moveTile(a_game, idx, x, i, x, i+len, -(i-(y1-1)));
a_game.m_board.m_board[(i+len)*w + x] = a_game.m_board.m_board[i*w + x];
}
}
for (int j = 0; j < len; j++) {
addTile(a_game, newIdx++, x, j - len, x, j, rand() % a_game.m_tileTypes);
}
}
}
bool checkForMoreMatches(Game& a_game)
{
int w = a_game.width();
int h = a_game.height();
std::vector<Pattern>& patterns = a_game.m_gameDB.m_patterns;
//foreach(Pattern& p, patterns)
for (int pi = 0; pi < patterns.size(); pi++)
{
const Pattern& p = patterns[pi];
const int pw = 5;
uint8_t offsets[pw];
uint8_t lengths[pw];
uint64_t po = p.m_offsets;
uint64_t pl = p.m_lengths;
for (int i = pw-1; i >= 0; i--) {
offsets[i] = po & 0xff;
lengths[i] = pl & 0xff;
po >>= 8;
pl >>= 8;
}
for (int j = 0; j < h; j++)
for (int i = 0; i < w; i++) {
if (j + offsets[0] >= h)
continue;
int val = a_game.m_board.m_board[(j + offsets[0]) * w + i];
bool foundMatch = true;
for (int x = 0; x < pw; x++) {
int y1 = j + offsets[x];
int len = lengths[x];
if (len) {
int y2 = y1 + len - 1;
if (y2 >= h)
foundMatch = false;
else {
for (int y = y1; y <= y2; y++)
if ((i+x) >= w || val != a_game.m_board.m_board[y * w + i + x])
foundMatch = false;
}
}
}
if (foundMatch) {
//printf("found match\n");
handleMatch(a_game, p, i, j);
a_game.m_score += p.m_score;
printf("new score: %i\n", a_game.m_score);
return true;
}
}
}
if (!hasMoveAvailable(a_game.m_board))
{
BoardEvent noMoreMoves;
noMoreMoves.type = BoardEvent::NoMoreMoves;
noMoreMoves.userInit = false;
a_game.m_events.push_back(noMoreMoves);
}
return false;
}
bool swapTiles(Game& a_game, int x1, int y1, int x2, int y2)
{
Board& a_board = a_game.m_board;
int w = a_game.width();
int h = a_game.height();
int newIdx = w*h;
if (!canSwapTiles(a_board, x1, y1, x2, y2))
return false;
int idx = y1 * w + x1;
int idx2 = y2 * w + x2;
swapTile(a_game, idx, idx2, x1, y1, x2, y2);
// Actually swap them
int tmp = a_board.m_board[y1*w + x1];
a_board.m_board[y1*w + x1] = a_board.m_board[y2*w + x2];
a_board.m_board[y2*w + x2] = tmp;
bool hasMatches = true;
//while (hasMatches)
hasMatches = checkForMoreMatches(a_game);
return true;
}