Implemented some game feature (mainly the change between phase and player after actions), There are bugs but the game can be 'played'

merge-requests/1/merge
marouault 4 years ago
parent 4e5f963eeb
commit e13b538da0

@ -23,7 +23,8 @@
typedef enum {
PLACEMENT,
MOVE_PIECE,
RM_BRIDGE
RM_BRIDGE,
GAME_ENDED
} Phase;
/**
@ -36,6 +37,7 @@ typedef struct {
//TODO duree
Phase phase; ///< The current state of the game
Player arrPlayers[4]; ///< The array of all the players in this game
size_t nbPlayers;
Board board; ///< The board for this game
} Game;
@ -47,6 +49,13 @@ typedef struct {
Game newGame(const size_t nbPlayers, const char* pseudos[]);
/**
* \brief (Should not be called outside Game.c) Used to change phase or player (or both) after an action
*
* \param [in, out] game The game to mutate
*/
void changePhaseOrPlayerTurn(Game* game);
/**
* \brief Place a piece into the board
*
@ -66,6 +75,16 @@ bool placePiece(Piece* p, const Island island, const Board* b);
*/
bool movePiece(Piece* p, const Island i, const Board* b);
/**
* \brief Test if a movement is possible for a piece to a destination island
*
* \param p The piece to test
* \param i The destination island
* \param b The board
* \return true if the piece p can move to the island i
*/
bool pieceCanMoveTo(const Piece* p, const Island i, const Board* b);
/**
* \brief Check if an island is empty
*
@ -104,6 +123,15 @@ bool isPieceIsolated(const Piece* piece, const Board* board);
*/
bool areAllPlayerPiecesStucked(const size_t idJ, const Piece arrPieces[], const size_t nbPieces);
/**
* \brief Test if one piece of a player can move
*
* \param playerID The player to check
* \param board The board
* \return true if at least one of player's piece can move
*/
bool anyOfPlayersPiecesCanMove(const size_t playerID, const Board* board);
/**
* \brief Check if there is a bridge between two Island.
* \param[in] start On island were the bridge ends

@ -9,6 +9,7 @@
#define ISLAND_H
#include <stdbool.h>
#include <stddef.h>
/**
*\struct Island
@ -48,4 +49,13 @@ bool islandEqual(const Island a, const Island b);
*/
bool islandValid(const Island island);
/**
* \brief Return valid island around the one given
*
* \param [in] island The island for which neighbors are searched
* \param [out] nbIlsandsFound The number of island in the returned array
* \return neighbors Array of neighbors islands (take care to free)
*/
Island* islandsAround(const Island island, size_t* nbIslandsFound);
#endif

@ -3,58 +3,53 @@
#include <assert.h>
// Not defined in header to not pollute inferface
void applySpecificRulesFor2PlayersGame(Game* g) {
void applySpecificRulesFor2PlayersGame(Game* g)
{
g->currentPlayerID = 0;
g->phase = MOVE_PIECE;
g->phase = MOVE_PIECE;
size_t iJ1 = 0;
size_t iJ2 = 0;
const Island startPosJ1[] = {
newIsland(1,0),
newIsland(2,1),
newIsland(3,0)
};
const Island startPosJ1[] = { newIsland(1, 0), newIsland(2, 1), newIsland(3, 0) };
const Island startPosJ2[] = {
newIsland(1,4),
newIsland(2,3),
newIsland(3,4)
};
const Island startPosJ2[] = { newIsland(1, 4), newIsland(2, 3), newIsland(3, 4) };
for (size_t i = 0; i < g->board.nbPieces; ++i) {
if (g->board.arrPieces[i].idJ==0) {
g->board.arrPieces[i].island = startPosJ1[iJ1++]; // Post increment return the value "before" incrementing
for (size_t i = 0; i < g->board.nbPieces; ++i)
{
if (g->board.arrPieces[i].idJ == 0)
{
g->board.arrPieces[i].island =
startPosJ1[iJ1++]; // Post increment return the value "before" incrementing
}
else {
else
{
g->board.arrPieces[i].island = startPosJ2[iJ2++];
}
}
}
Game newGame(const size_t nbPlayers, const char* pseudos[]) {
Game g = {
// In Placement phase, the last player initialized is the 1st to play
Game newGame(const size_t nbPlayers, const char* pseudos[])
{
Game g = { // In Placement phase, the last player initialized is the 1st to play
.currentPlayerID = nbPlayers - 1,
.nb_rounds = 0,
.phase = PLACEMENT,
.board = newBoard(nbPlayers)
.board = newBoard(nbPlayers),
.nbPlayers = nbPlayers
};
// red, green, blue, yellow
// TODO meilleures couleurs (?)
SDL_Color colors[4] = {
{255,0 ,0 ,255},
{0 ,255,0 ,255},
{0 ,0 ,255,255},
{255,255,0 ,255}
};
SDL_Color colors[4] = { { 255, 0, 0, 255 }, { 0, 255, 0, 255 }, { 0, 0, 255, 255 }, { 255, 255, 0, 255 } };
for (size_t player_i = 0; player_i < nbPlayers; player_i++) {
g.arrPlayers[player_i] = newPlayer(pseudos[player_i] ,colors[player_i]);
for (size_t player_i = 0; player_i < nbPlayers; player_i++)
{
g.arrPlayers[player_i] = newPlayer(pseudos[player_i], colors[player_i]);
}
if (nbPlayers == 2) {
if (nbPlayers == 2)
{
applySpecificRulesFor2PlayersGame(&g);
}
@ -62,8 +57,60 @@ Game newGame(const size_t nbPlayers, const char* pseudos[]) {
}
bool placePiece(Piece* p, const Island island, const Board* b) {
if (isIslandEmpty(island, b->arrPieces, b->nbPieces)) {
void changePhaseOrPlayerTurn(Game* game)
{
switch (game->phase)
{
case PLACEMENT:
if (game->currentPlayerID == 0)
{
game->phase = MOVE_PIECE;
}
else
{
game->currentPlayerID--;
}
break;
case MOVE_PIECE:
game->phase = RM_BRIDGE;
break;
case RM_BRIDGE:
{
const size_t lastPlayerId = game->currentPlayerID;
do
{
game->currentPlayerID++;
if (game->currentPlayerID == game->nbPlayers)
{
game->currentPlayerID = 0;
}
if (lastPlayerId == game->currentPlayerID) {
game->phase = GAME_ENDED;
return;
}
} while (areAllPlayerPiecesStucked(game->currentPlayerID, game->board.arrPieces,
game->board.nbPieces));
fprintf(stderr, "Player n°%lld turn\n", game->currentPlayerID);
fflush(stderr);
if (anyOfPlayersPiecesCanMove(game->currentPlayerID, &game->board))
{
game->phase = MOVE_PIECE;
}
break;
}
default:
break;
}
}
bool placePiece(Piece* p, const Island island, const Board* b)
{
if (isIslandEmpty(island, b->arrPieces, b->nbPieces))
{
p->island = island;
return true;
}
@ -73,44 +120,52 @@ bool placePiece(Piece* p, const Island island, const Board* b) {
bool movePiece(Piece* p, const Island i, const Board* b)
{
if (isIslandEmpty(i, b->arrPieces, b->nbPieces) && isPieceAdjacentToIsland(*p, i) && checkBridge(p->island, i, b)) {
if (pieceCanMoveTo(p, i, b))
{
p->island = i;
return true;
}
else {
}
else
{
return false;
}
}
bool isIslandEmpty(const Island island, const Piece arrPieces[], const size_t nbPieces) {
bool pieceCanMoveTo(const Piece* p, const Island i, const Board* b) {
return isIslandEmpty(i, b->arrPieces, b->nbPieces) && isPieceAdjacentToIsland(*p, i) && checkBridge(p->island, i, b);
}
bool isIslandEmpty(const Island island, const Piece arrPieces[], const size_t nbPieces)
{
assert(islandValid(island) && "Pass invalid island to isIslandEmpty");
for (size_t i = 0; i < nbPieces; ++i)
{
if (islandEqual(island, arrPieces[i].island)) {
if (islandEqual(island, arrPieces[i].island))
{
return false;
}
}
return true;
}
bool isPieceAdjacentToIsland(const Piece p, const Island i)
{
//Maybe turn this into an if (with message on stderr)
// Maybe turn this into an if (with message on stderr)
assert(islandValid(i) && "Send invalid island to isPieceAdjacentToIsland");
assert(islandValid(p.island) && "Send invalid piece island to isPieceAdjacentToIsland");
if(p.island.x==i.x) //piece and island are on the same x axis
if (p.island.x == i.x) // piece and island are on the same x axis
{
const int diff=p.island.y-i.y;
return -1==diff || diff==1; //Island is adjacent if the difference is equal -1 or 1 on the y axis
const int diff = p.island.y - i.y;
return -1 == diff || diff == 1; // Island is adjacent if the difference is equal -1 or 1 on the y axis
}
else if (p.island.y==i.y) //piece and island are on the same y axe
else if (p.island.y == i.y) // piece and island are on the same y axe
{
const int diff=p.island.x-i.x;
return -1==diff || diff==1; //Island is adjacent if the difference is equal to -1 or 1 on the x axis
const int diff = p.island.x - i.x;
return -1 == diff || diff == 1; // Island is adjacent if the difference is equal to -1 or 1 on the x axis
}
return false;
@ -118,7 +173,7 @@ bool isPieceAdjacentToIsland(const Piece p, const Island i)
bool checkBridge(const Island start, const Island target, const Board* board)
{
//Maybe turn this into an if (with message on stderr)
// Maybe turn this into an if (with message on stderr)
assert(islandValid(start) && islandValid(target) && "Send invalid island to checkBridge");
// Horizontal difference between start and target.
@ -132,94 +187,132 @@ bool checkBridge(const Island start, const Island target, const Board* board)
const int ydiff = target.y - start.y;
// Vertical bridge
if (xdiff == 0 && abs(ydiff) == 1) {
return board->vBridges[start.y+ydiff][start.x];
if (xdiff == 0 && abs(ydiff) == 1)
{
return board->vBridges[start.y + ydiff][start.x];
}
// Horizontal bridge
else if (abs(xdiff) == 1 && ydiff == 0) {
return board->hBridges[start.y][start.x+xdiff];
else if (abs(xdiff) == 1 && ydiff == 0)
{
return board->hBridges[start.y][start.x + xdiff];
}
// Not a bridge
else {
else
{
return false;
}
}
bool isPieceIsolated(const Piece* piece, const Board* board) {
Island g = piece->island;
g.x-=1;
Island d = piece->island;
g.x+=1;
Island h = piece->island;
g.y-=1;
Island b = piece->island;
g.y+=1;
if (islandValid(g) && checkBridge(piece->island, g, board)) return false;
if (islandValid(d) && checkBridge(piece->island, d, board)) return false;
if (islandValid(h) && checkBridge(piece->island, h, board)) return false;
if (islandValid(b) && checkBridge(piece->island, b, board)) return false;
bool isPieceIsolated(const Piece* piece, const Board* board)
{
size_t nbNeighbors;
Island* neighbors = islandsAround(piece->island, &nbNeighbors);
for (size_t i = 0; i < nbNeighbors; ++i)
{
if (checkBridge(piece->island, neighbors[i], board)) {
free(neighbors);
return false;
}
}
free(neighbors);
return true;
}
bool areAllPlayerPiecesStucked(const size_t idJ, const Piece arrPieces[], const size_t nbPieces) {
for (size_t i = 0; i<nbPieces; ++i) {
if (arrPieces[i].idJ == idJ && !arrPieces[i].stuck) {
bool areAllPlayerPiecesStucked(const size_t idJ, const Piece arrPieces[], const size_t nbPieces)
{
for (size_t i = 0; i < nbPieces; ++i)
{
if (arrPieces[i].idJ == idJ && !arrPieces[i].stuck)
{
return false;
}
}
return true;
}
bool anyOfPlayersPiecesCanMove(const size_t playerID, const Board* board) {
for (size_t i = 0; i < board->nbPieces; ++i)
{
size_t nbNeighbors;
Island* neighbors = islandsAround(board->arrPieces[i].island, &nbNeighbors);
for (size_t n = 0; n < nbNeighbors; ++n)
{
if (board->arrPieces[i].idJ == playerID && pieceCanMoveTo(&board->arrPieces[i], neighbors[n], board)) {
return true;
}
}
free(neighbors);
}
return false;
}
/*
I think we shouldn't put this in the header (not intended to be used by exterior)
It's used when a bridge is removed
*/
void updatePieceIsolated(Game* game, const Island* island) {
void updatePieceIsolated(Game* game, const Island* island)
{
Piece* piecePotentialyIsolated = getPieceFromIsland(game->board.arrPieces, game->board.nbPieces, *island);
if (piecePotentialyIsolated != NULL && isPieceIsolated(piecePotentialyIsolated, &game->board)) { //Check is a piece is isolated and then if the player is eliminated
piecePotentialyIsolated->stuck=true;
if (areAllPlayerPiecesStucked(piecePotentialyIsolated->idJ, game->board.arrPieces, game->board.nbPieces)) {
game->arrPlayers[piecePotentialyIsolated->idJ].rank = game->nb_rounds;//TODO : See what we put in rank
if (piecePotentialyIsolated != NULL && isPieceIsolated(piecePotentialyIsolated, &game->board))
{ // Check is a piece is isolated and then if the player is eliminated
piecePotentialyIsolated->stuck = true;
if (areAllPlayerPiecesStucked(piecePotentialyIsolated->idJ, game->board.arrPieces,
game->board.nbPieces))
{
game->arrPlayers[piecePotentialyIsolated->idJ].rank = game->nb_rounds; // TODO : See what we put in rank
}
}
}
bool clickOnBoard(const Coord coord, Game* game) {
bool clickOnBoard(const Coord coord, Game* game)
{
const IslandOrBridge islandOrBridge = coordToEntity(coord);
switch(game->phase)
switch (game->phase)
{
case PLACEMENT:
if (islandOrBridge.type==ISLAND) {
//placePiece(,islandOrBridge.x);
}
break;
case RM_BRIDGE:
if (islandOrBridge.type == BRIDGE) {
Bridge bridge = islandOrBridge.data.bridge;
rmBridge(bridge,&game->board);
case PLACEMENT:
if (islandOrBridge.type == ISLAND)
{
Piece* piece = getPieceFromIsland(game->board.arrPieces, game->board.nbPieces, islandOrBridge.data.island);
if (piece != NULL) {
if (placePiece(piece, islandOrBridge.data.island, &game->board)) {
changePhaseOrPlayerTurn(game);
return true;
}
}
}
break;
case RM_BRIDGE:
if (islandOrBridge.type == BRIDGE)
{
Bridge bridge = islandOrBridge.data.bridge;
if (rmBridge(bridge, &game->board)) {
updatePieceIsolated(game, &bridge.islandA);
updatePieceIsolated(game, &bridge.islandB);
updatePieceIsolated(game, &bridge.islandA);
updatePieceIsolated(game, &bridge.islandB);
changePhaseOrPlayerTurn(game);
return true;
}
break;
default:
break;
return true;
}
}
break;
default:
break;
}
return false;
}
Piece* getPieceFromIsland(Piece arrPieces[9], const size_t logicalSize, const Island island){
for(size_t i=0; i<logicalSize;i++)
Piece* getPieceFromIsland(Piece arrPieces[9], const size_t logicalSize, const Island island)
{
for (size_t i = 0; i < logicalSize; i++)
{
if(islandEqual(arrPieces[i].island,island))
if (islandEqual(arrPieces[i].island, island))
{
return &arrPieces[i];
}
@ -227,48 +320,57 @@ Piece* getPieceFromIsland(Piece arrPieces[9], const size_t logicalSize, const Is
return NULL;
}
bool moveOnBoard(const Coord start, const Coord end, Game* game) {
bool moveOnBoard(const Coord start, const Coord end, Game* game)
{
const IslandOrBridge islandOrBridgeStart = coordToEntity(start);
const IslandOrBridge islandOrBridgeEnd = coordToEntity(end);
const IslandOrBridge islandOrBridgeEnd = coordToEntity(end);
switch(game->phase)
switch (game->phase)
{
case MOVE_PIECE:
if(islandOrBridgeStart.type==ISLAND && islandOrBridgeEnd.type==ISLAND)
if (islandOrBridgeStart.type == ISLAND && islandOrBridgeEnd.type == ISLAND)
{
const size_t idCurrentPlayer = game->currentPlayerID;
const Island islandStart = islandOrBridgeStart.data.island;
const Island islandEnd = islandOrBridgeEnd.data.island;
const Island islandStart = islandOrBridgeStart.data.island;
const Island islandEnd = islandOrBridgeEnd.data.island;
Piece* piece = getPieceFromIsland(game->board.arrPieces, game->board.nbPieces, islandStart);
if(piece != NULL && idCurrentPlayer==piece->idJ) { //Check if the current player id is the same than the piece selected by the player
return movePiece(piece, islandEnd, &game->board);
if (piece != NULL && idCurrentPlayer == piece->idJ)
{ // Check if the current player id is the same than the piece selected by the player
bool pieceMoved = movePiece(piece, islandEnd, &game->board);
if (pieceMoved)
{
changePhaseOrPlayerTurn(game);
}
return pieceMoved;
}
}
break;
default:
default:
break;
}
return false;
}
bool rmBridge(Bridge bridge, Board* board) {
bool rmBridge(Bridge bridge, Board* board)
{
if(bridge.islandA.x==bridge.islandB.x) //Vertical bridge
if (bridge.islandA.x == bridge.islandB.x) // Vertical bridge
{
if (board->vBridges[bridge.islandA.y][bridge.islandA.x])
{
if(board->vBridges[bridge.islandA.y][bridge.islandA.x]) {
board->vBridges[bridge.islandA.y][bridge.islandA.x] = false;
return true;
}
board->vBridges[bridge.islandA.y][bridge.islandA.x] = false;
return true;
}
}
else if (bridge.islandA.y == bridge.islandB.y)
{ // Horizontal bridge
if (board->hBridges[bridge.islandA.y][bridge.islandA.x])
{
board->hBridges[bridge.islandA.y][bridge.islandA.x] = false; // bridge coordinates equals to the islandA
return true;
}
else if(bridge.islandA.y==bridge.islandB.y){ //Horizontal bridge
if(board->hBridges[bridge.islandA.y][bridge.islandA.x]) {
board->hBridges[bridge.islandA.y][bridge.islandA.x] = false; //bridge coordinates equals to the islandA
return true;
}
}
return false;
}

@ -1,4 +1,5 @@
#include "model/Island.h"
#include <stdlib.h>
Island newIsland(const int x, const int y) {
@ -17,3 +18,43 @@ bool islandValid(const Island island) {
return island.x>=0 && island.x<=4
&& island.y>=0 && island.y<=4;
}
Island* islandsAround(const Island island, size_t* nbIslandsFound) {
*nbIslandsFound = 0;
Island* neighbors = (Island*) malloc(sizeof(Island)*4);
// Left
Island i = island;
i.x -= 1;
if (islandValid(i)) {
neighbors[*nbIslandsFound] = i;
(*nbIslandsFound)++;
}
// Right
i = island;
i.x += 1;
if (islandValid(i)) {
neighbors[*nbIslandsFound] = i;
(*nbIslandsFound)++;
}
// Up
i = island;
i.y -= 1;
if (islandValid(i)) {
neighbors[*nbIslandsFound] = i;
(*nbIslandsFound)++;
}
// Down
i = island;
i.y += 1;
if (islandValid(i)) {
neighbors[*nbIslandsFound] = i;
(*nbIslandsFound)++;
}
return neighbors;
}

Loading…
Cancel
Save