2021-10-11 18:11:48 +00:00
|
|
|
// Copyright (c) Jon Thysell <http://jonthysell.com>
|
|
|
|
// Licensed under the MIT License.
|
|
|
|
|
|
|
|
#include "Common.h"
|
|
|
|
#include "GameEngine.h"
|
|
|
|
|
|
|
|
const int8_t PuzzleSize = 5;
|
|
|
|
|
|
|
|
const uint8_t MaxStars = 3;
|
|
|
|
const uint8_t MaxHalfStars = 6;
|
|
|
|
const uint8_t MinHalfStars = 1;
|
|
|
|
|
|
|
|
const uint16_t PerfectScore = 300; // LevelCount * MaxHalfStars
|
|
|
|
|
2021-10-29 00:44:36 +00:00
|
|
|
void GameEngine_LoadLevel(GameEngine *pGameEngine, const int8_t level, const bool setB);
|
2021-11-23 18:34:18 +00:00
|
|
|
uint8_t GameEngine_CalculateHalfStars(const uint16_t par, const uint16_t moves);
|
2021-10-16 00:29:07 +00:00
|
|
|
void GameEngine_ToggleSingleLight(GameEngine *pGameEngine, const int8_t x, const int8_t y);
|
|
|
|
|
2021-10-29 00:44:36 +00:00
|
|
|
void GameEngine_NewGame(GameEngine *pGameEngine, const bool setB)
|
|
|
|
{
|
|
|
|
pGameEngine->Score = 0;
|
|
|
|
GameEngine_LoadLevel(pGameEngine, 0, setB);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameEngine_NextLevel(GameEngine *pGameEngine)
|
|
|
|
{
|
|
|
|
if (GameEngine_IsCompleted(pGameEngine))
|
|
|
|
{
|
|
|
|
pGameEngine->Score += GameEngine_GetHalfStars(pGameEngine);
|
|
|
|
GameEngine_LoadLevel(pGameEngine, pGameEngine->Level + 1, pGameEngine->SetB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameEngine_ResetLevel(GameEngine *pGameEngine)
|
|
|
|
{
|
|
|
|
GameEngine_LoadLevel(pGameEngine, pGameEngine->Level, pGameEngine->SetB);
|
|
|
|
}
|
|
|
|
|
2021-10-16 00:29:07 +00:00
|
|
|
void GameEngine_LoadLevel(GameEngine *pGameEngine, const int8_t level, const bool setB)
|
2021-10-11 18:11:48 +00:00
|
|
|
{
|
2021-10-31 22:13:51 +00:00
|
|
|
pGameEngine->Level = level;
|
2021-10-22 18:32:19 +00:00
|
|
|
pGameEngine->SetB = setB;
|
2021-11-23 18:34:18 +00:00
|
|
|
pGameEngine->PreviousLights = pGameEngine->Lights;
|
2021-10-16 00:29:07 +00:00
|
|
|
pGameEngine->Lights = Levels_GetLightsForLevel(pGameEngine->Level, setB);
|
|
|
|
pGameEngine->Par = Levels_GetParForLevel(pGameEngine->Level);
|
|
|
|
pGameEngine->Moves = 0;
|
2021-10-11 18:11:48 +00:00
|
|
|
}
|
|
|
|
|
2021-10-16 00:29:07 +00:00
|
|
|
bool GameEngine_GetLight(const GameEngine *pGameEngine, const int8_t x, const int8_t y)
|
2021-10-11 18:11:48 +00:00
|
|
|
{
|
|
|
|
if (x >= 0 && x < PuzzleSize && y >= 0 && y < PuzzleSize)
|
|
|
|
{
|
2021-10-16 00:29:07 +00:00
|
|
|
return bitRead(pGameEngine->Lights, y * PuzzleSize + x);
|
2021-10-11 18:11:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-16 00:29:07 +00:00
|
|
|
bool GameEngine_IsCompleted(const GameEngine *pGameEngine)
|
2021-10-11 18:11:48 +00:00
|
|
|
{
|
2021-10-16 00:29:07 +00:00
|
|
|
return pGameEngine->Lights == 0;
|
2021-10-11 18:11:48 +00:00
|
|
|
}
|
|
|
|
|
2021-10-31 22:13:51 +00:00
|
|
|
bool GameEngine_IsGameOver(const GameEngine *pGameEngine)
|
|
|
|
{
|
|
|
|
return pGameEngine->Level >= LevelCount;
|
|
|
|
}
|
|
|
|
|
2021-10-16 00:29:07 +00:00
|
|
|
uint8_t GameEngine_GetHalfStars(const GameEngine *pGameEngine)
|
2021-10-11 18:11:48 +00:00
|
|
|
{
|
2021-11-23 18:34:18 +00:00
|
|
|
return GameEngine_CalculateHalfStars(pGameEngine->Par, pGameEngine->Moves);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t GameEngine_CalculateHalfStars(const uint16_t par, const uint16_t moves)
|
|
|
|
{
|
|
|
|
uint8_t halfStarsLost = moves <= par ? 0 : max(0, (1 + moves - par) / 2);
|
2021-10-11 18:11:48 +00:00
|
|
|
return max(MinHalfStars, MaxHalfStars - halfStarsLost);
|
|
|
|
}
|
|
|
|
|
2021-10-16 00:29:07 +00:00
|
|
|
void GameEngine_ToggleLights(GameEngine *pGameEngine, const int8_t x, const int8_t y)
|
2021-10-11 18:11:48 +00:00
|
|
|
{
|
|
|
|
int8_t targetX = max(0, min(x, PuzzleSize - 1));
|
|
|
|
int8_t targetY = max(0, min(y, PuzzleSize - 1));
|
|
|
|
|
2021-11-23 18:34:18 +00:00
|
|
|
pGameEngine->PreviousLights = pGameEngine->Lights;
|
|
|
|
|
2021-10-16 00:29:07 +00:00
|
|
|
GameEngine_ToggleSingleLight(pGameEngine, targetX, targetY);
|
|
|
|
GameEngine_ToggleSingleLight(pGameEngine, targetX + 1, targetY);
|
|
|
|
GameEngine_ToggleSingleLight(pGameEngine, targetX, targetY + 1);
|
|
|
|
GameEngine_ToggleSingleLight(pGameEngine, targetX - 1, targetY);
|
|
|
|
GameEngine_ToggleSingleLight(pGameEngine, targetX, targetY - 1);
|
2021-10-11 18:11:48 +00:00
|
|
|
|
2021-10-16 00:29:07 +00:00
|
|
|
pGameEngine->Moves++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameEngine_ToggleSingleLight(GameEngine *pGameEngine, const int8_t x, const int8_t y)
|
|
|
|
{
|
|
|
|
if (x >= 0 && x < PuzzleSize && y >= 0 && y < PuzzleSize)
|
|
|
|
{
|
|
|
|
bitToggle(pGameEngine->Lights, y * PuzzleSize + x);
|
|
|
|
}
|
2021-10-11 18:11:48 +00:00
|
|
|
}
|
2021-11-23 18:34:18 +00:00
|
|
|
|
|
|
|
bool GameEngine_LightChanged(const GameEngine *pGameEngine, const int8_t x, const int8_t y)
|
|
|
|
{
|
|
|
|
if (x >= 0 && x < PuzzleSize && y >= 0 && y < PuzzleSize)
|
|
|
|
{
|
|
|
|
return bitRead(pGameEngine->Lights, y * PuzzleSize + x) != bitRead(pGameEngine->PreviousLights, y * PuzzleSize + x);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GameEngine_HalfStarsChanged(const GameEngine *pGameEngine)
|
|
|
|
{
|
|
|
|
return pGameEngine->Moves == 0 ||
|
|
|
|
GameEngine_CalculateHalfStars(pGameEngine->Par, pGameEngine->Moves - 1) != GameEngine_GetHalfStars(pGameEngine);
|
|
|
|
}
|