Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
maciejmroz committed Jan 24, 2014
0 parents commit b77e6cd
Show file tree
Hide file tree
Showing 25 changed files with 1,861 additions and 0 deletions.
586 changes: 586 additions & 0 deletions Match3/Block.cpp

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions Match3/Block.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

#ifndef _BLOCK_H_
#define _BLOCK_H_

#include "Renderer.h"

class Block;
typedef std::shared_ptr<Block> BlockPtr;
typedef std::shared_ptr<const Block> ConstBlockPtr;

const int BLOCK_SIZE_X = 42;
const int BLOCK_SIZE_Y = 42;
const int BOARD_POS_X = 330;
const int BOARD_POS_Y = 105;

struct NotImplementedException : public std::exception
{
};

class Block
{
struct impl;
std::unique_ptr<impl> pimpl;
public:
Block(Renderer &r);
~Block();

void init(int boardX, int boardY, TextureID texture);

bool isInside(int x, int y) const;
bool isSelected() const;
bool isDead() const;
bool canMove() const;
bool isNeighbor(BlockPtr block) const;

int getBoardX() const;
int getBoardY() const;
//return some numeric block type or -1 for empty/inactive block
int getType() const;
//return best swap direction given mouse coordinates
//sets (dx, dy) to one of (-1, 0), (1, 0), (0, -1), (0, 1)
void getSwapDirection(const int x, const int y, int &dx, int &dy) const;

void mark(unsigned int currentTime);
void unmark(unsigned int currentTime);
void select(unsigned int currentTime);
void unselect(const unsigned int currentTime);

void swapWith(unsigned int currentTime, BlockPtr block);
void kill(unsigned int currentTime);
void fallTo(unsigned int currentTime, const int targetX, const int targetY);

void simulate(unsigned int currentTime);

void render(unsigned int currentTime) const;
void renderOverlay(unsigned int currentTime) const;
};


#endif
136 changes: 136 additions & 0 deletions Match3/Board.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include "GameImpl.h"
#include <ctime>
#include <memory>

Board::Board(Renderer &r) :
renderer(r)
{
rng.seed((unsigned int)std::time(0));
}

void Board::applyToAllBlocks(const std::function<void (BlockPtr&)> &f)
{
for(int i = 0; i < NUM_BLOCK_ROWS; ++i)
{
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j)
{
if(!blocks[i][j])
{
continue;
}
f(blocks[i][j]);
}
}
}

BlockPtr Board::findBlock(const std::function<bool (BlockPtr)> &predicate)
{
for(int i = 0; i < NUM_BLOCK_ROWS; ++i)
{
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j)
{
if(!blocks[i][j])
{
continue;
}
if(predicate(blocks[i][j]))
{
return blocks[i][j];
}
}
}
return nullptr;
}

void Board::generate()
{
std::uniform_int<> block_dist(TID_BLOCK_1, TID_BLOCK_1 + NUM_BLOCK_TYPES - 1);

for(int i = 0; i < NUM_BLOCK_ROWS; ++i)
{
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j)
{
BlockPtr block = std::make_shared<Block>(renderer);
block->init(j, i, (TextureID)block_dist(rng));
blocks[i][j] = block;
}
}
}

int Board::simulateKills(const unsigned int currentTime)
{
KillCalculator killCalculator(*this);
killCalculator.calculateKills();

int killCount = 0;
applyToAllBlocks([&] (BlockPtr b) {
if(killCalculator.hasKillAt(b->getBoardX(), b->getBoardY()))
{
b->kill(currentTime);
killCount++;
}
});
return killCount;
}

void Board::removeDeadBlocks()
{
applyToAllBlocks([] (BlockPtr &b) {
if(b->isDead())
{
b = nullptr;
}
});
}

void Board::simulateFalling(const unsigned int currentTime)
{
std::uniform_int<> block_dist(TID_BLOCK_1, TID_BLOCK_1 + NUM_BLOCK_TYPES - 1);
int numBlocksGenerated[NUM_BLOCK_COLUMNS];
for(int i = 0; i < NUM_BLOCK_COLUMNS; ++i)
{
numBlocksGenerated[i] = 0;
}
for(int i = 0; i < NUM_BLOCK_ROWS; ++i)
{
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j)
{

int reverseRowIndex = NUM_BLOCK_ROWS - i - 1;
if(blocks[reverseRowIndex][j])
{
continue;
}
//search for block that can fall to this position
bool blockFound = false;
int testRow;
for(testRow = reverseRowIndex - 1; testRow >= 0; --testRow)
{
if(!blocks[testRow][j])
{
continue;
}
if(blocks[testRow][j]->canMove())
{
blockFound = true;
break;
}
}
if(blockFound)
{
blocks[testRow][j]->fallTo(currentTime, j, reverseRowIndex);
blocks[reverseRowIndex][j] = blocks[testRow][j];
blocks[testRow][j] = nullptr;
}
else if(testRow == -1)
{
//generate new
BlockPtr block(new Block(renderer));
block->init(j, -(numBlocksGenerated[j] + 1), (TextureID)block_dist(rng));
numBlocksGenerated[j]++;
block->fallTo(currentTime, j, reverseRowIndex);
blocks[reverseRowIndex][j] = block;
}
}
}
}
49 changes: 49 additions & 0 deletions Match3/Board.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef _BOARD_H_
#define _BOARD_H_

template<typename SrcT, typename DstT>
void mapTable(SrcT mapFrom[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS],
DstT mapTo[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS],
const std::function<DstT (const SrcT&)> &f)
{
for(int i = 0; i < NUM_BLOCK_ROWS; ++i)
{
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j)
{
mapTo[i][j] = f(mapFrom[i][j]);
}
}
}

struct Board
{
Renderer &renderer;
std::mt19937 rng;

BlockPtr blocks[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS];
BlockPtr mouseDownBlock;

Board(Renderer &renderer);

void applyToAllBlocks(const std::function<void (BlockPtr&)> &f);
BlockPtr findBlock(const std::function<bool (BlockPtr)> &predicate);

template<typename T>
void mapBlocks(T mapTo[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS],
const std::function<T (const BlockPtr&)> &f) const
{
mapTable<const BlockPtr, T>(blocks, mapTo, f);
}

//board logic
void generate();
//return number of blocks killed
int simulateKills(unsigned int currentTime);
void removeDeadBlocks();
//check for falling blocks/new blocks
void simulateFalling(unsigned int currentTime);
};

typedef std::shared_ptr<Board> BoardPtr;

#endif
84 changes: 84 additions & 0 deletions Match3/Game.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include "GameImpl.h"
#include "SDL.h"
#include <sstream>

Game::impl::impl(Renderer &r) :
renderer(r),
board(new Board(r)),
gameStarted(false),
gameStartTime(0),
gameStopTime(0),
timeLeftSeconds(TIME_LIMIT),
score(0),
firstGame(true)
{
}

Game::impl::~impl()
{
}

void Game::impl::render(const unsigned int currentTime)
{
renderer.clear();
renderer.drawBackground(TID_BACKGROUND);

renderer.setClipRect(BOARD_POS_X, BOARD_POS_Y, NUM_BLOCK_COLUMNS * BLOCK_SIZE_X, NUM_BLOCK_ROWS * BLOCK_SIZE_Y);

board->applyToAllBlocks([&] (BlockPtr b) {
b->simulate(currentTime);
b->render(currentTime);
});


board->applyToAllBlocks([&] (BlockPtr b) {
b->renderOverlay(currentTime);
});

renderer.resetClipRect();

std::ostringstream timeStream;
timeStream << "Time: " << timeLeftSeconds;
renderer.drawText(timeStream.str().c_str(), 25, 125);

std::ostringstream scoreStream;
scoreStream << "Score: " << score;
renderer.drawText(scoreStream.str().c_str(), 25, 175);

renderer.present();
}

void Game::impl::runEventLoop()
{
board->generate();

bool quit = false;

while(!quit)
{
unsigned int currentTime = SDL_GetTicks();

if(pollEvents(currentTime))
{
quit = true;
}

simulate(currentTime);

render(currentTime);
}
}

Game::Game(Renderer &r)
{
pimpl = std::unique_ptr<impl>(new impl(r));
}

Game::~Game()
{
}

void Game::runEventLoop()
{
pimpl->runEventLoop();
}
22 changes: 22 additions & 0 deletions Match3/Game.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

#ifndef _GAME_H_
#define _GAME_H_

#include "Block.h"

const int NUM_BLOCK_TYPES = 5;
const int NUM_BLOCK_COLUMNS = 8;
const int NUM_BLOCK_ROWS = 8;

class Game
{
struct impl;
std::unique_ptr<impl> pimpl;
public:
Game(Renderer &r);
~Game();

void runEventLoop();
};

#endif
Loading

0 comments on commit b77e6cd

Please sign in to comment.