Start building the game logic and the UI.

This commit is contained in:
Jeremy Rand 2016-07-20 19:53:52 -05:00
parent ecfaa194eb
commit b91c015edd
9 changed files with 606 additions and 59 deletions

View File

@ -21,6 +21,9 @@
9D6B473F1D3FB5C800F6D704 /* dbllores.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dbllores.h; sourceTree = "<group>"; };
9D6B47401D40098300F6D704 /* game.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = game.c; sourceTree = "<group>"; };
9D6B47411D40098300F6D704 /* game.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = game.h; sourceTree = "<group>"; };
9D6B47421D400B4900F6D704 /* types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = "<group>"; };
9D6B47431D403F5B00F6D704 /* ui.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ui.c; sourceTree = "<group>"; };
9D6B47441D403F5B00F6D704 /* ui.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ui.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
@ -35,8 +38,11 @@
isa = PBXGroup;
children = (
9D6B472E1D3FB16F00F6D704 /* main.c */,
9D6B47431D403F5B00F6D704 /* ui.c */,
9D6B47441D403F5B00F6D704 /* ui.h */,
9D6B47401D40098300F6D704 /* game.c */,
9D6B47411D40098300F6D704 /* game.h */,
9D6B47421D400B4900F6D704 /* types.h */,
9D6B473E1D3FB20000F6D704 /* dbllores.s */,
9D6B473F1D3FB5C800F6D704 /* dbllores.h */,
9D6B472F1D3FB16F00F6D704 /* Makefile */,

View File

@ -9,23 +9,24 @@
#ifndef __a2bejwld__dbllores__
#define __a2bejwld__dbllores__
#include <stdint.h>
#include "types.h"
void __fastcall__ showDblLoRes(void);
void __fastcall__ clearDblLoRes(void);
void __fastcall__ unshowDblLoRes(void);
void __fastcall__ drawBgSquare(uint8_t square);
void __fastcall__ drawBgSquare(tSquare square);
void __fastcall__ drawBlueGem(uint8_t square);
void __fastcall__ drawYellowGem(uint8_t square);
void __fastcall__ drawRedGem(uint8_t square);
void __fastcall__ drawGreenGem(uint8_t square);
void __fastcall__ drawOrangeGem(uint8_t square);
void __fastcall__ drawGreyGem(uint8_t square);
void __fastcall__ drawPurpleGem(uint8_t square);
void __fastcall__ drawBlueGem(tSquare square);
void __fastcall__ drawYellowGem(tSquare square);
void __fastcall__ drawRedGem(tSquare square);
void __fastcall__ drawGreenGem(tSquare square);
void __fastcall__ drawOrangeGem(tSquare square);
void __fastcall__ drawGreyGem(tSquare square);
void __fastcall__ drawPurpleGem(tSquare square);
void __fastcall__ selectSquare(uint8_t square);
void __fastcall__ selectSquare(tSquare square);
#endif /* defined(__a2bejwld__dbllores__) */

View File

@ -6,10 +6,10 @@
; Copyright © 2016 Jeremy Rand. All rights reserved.
;
.export _showDblLoRes, _clearDblLoRes, _drawBgSquare
.export _showDblLoRes, _clearDblLoRes, _unshowDblLoRes
.export _drawGreenGem, _drawPurpleGem, _drawYellowGem
.export _drawBlueGem, _drawRedGem, _drawGreyGem
.export _drawOrangeGem, _selectSquare
.export _drawOrangeGem, _drawBgSquare, _selectSquare
.include "apple2.inc"
@ -62,6 +62,12 @@ gemmask := $8A
rts
.endproc
.proc _unshowDblLoRes
lda TXTSET
rts
.endproc
.proc _clearDblLoRes
sta LOWSCR
ldx #40

View File

@ -6,6 +6,225 @@
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "game.h"
#define MIN_MATCHING 3
#define GEM_TYPE_AT_SQUARE(square) gameState.squareStates[square].gemType
#define GEM_STARRED_AT_SQUARE(square) gameState.squareStates[square].isStarred
typedef struct tSquareState {
tGemType gemType;
bool isStarred;
} tSquareState;
typedef struct tGameState {
tSquareState squareStates[NUM_SQUARES];
uint8_t numStarred;
uint8_t numSpecial;
uint8_t level;
uint8_t score;
} tGameState;
tGameState gameState;
static tGemType randomGem(void)
{
return (rand() % (GEM_MAX_NORMAL - GEM_MIN_NORMAL)) + GEM_MIN_NORMAL;
}
static uint8_t numMatchingUpDownAtSquare(tSquare square, tGemType gemType)
{
tPos x = SQUARE_TO_X(square);
tPos y;
tPos startY = SQUARE_TO_Y(square);
uint8_t result = 0;
tPos lowerY = (startY < MIN_MATCHING ? 0 : startY - (MIN_MATCHING - 1));
tPos upperY = (startY > (BOARD_SIZE - MIN_MATCHING) ? (BOARD_SIZE - 1) : startY + (MIN_MATCHING - 1));
bool isStarred = GEM_STARRED_AT_SQUARE(square);
if (gemType == GEM_NONE)
gemType = GEM_TYPE_AT_SQUARE(square);
if (startY > 0) {
for (y = startY - 1; y >= lowerY; y--) {
square = XY_TO_SQUARE(x, y);
if (gemType != GEM_TYPE_AT_SQUARE(square))
break;
result++;
if (!isStarred)
isStarred = GEM_STARRED_AT_SQUARE(square);
}
}
if (startY < BOARD_SIZE - 1) {
for (y = startY + 1; y <= upperY; y++) {
square = XY_TO_SQUARE(x, y);
if (gemType != GEM_TYPE_AT_SQUARE(square))
break;
result++;
if (!isStarred)
isStarred = GEM_STARRED_AT_SQUARE(square);
}
}
if (result < MIN_MATCHING) {
result = 0;
isStarred = false;
}
return result;
}
static uint8_t numMatchingRightLeftAtSquare(tSquare square, tGemType gemType)
{
tPos x;
tPos y = SQUARE_TO_Y(square);
tPos startX = SQUARE_TO_X(square);
uint8_t result = 0;
tPos leftX = (startX < MIN_MATCHING ? 0 : startX - (MIN_MATCHING - 1));
tPos rightX = (startX > (BOARD_SIZE - MIN_MATCHING) ? (BOARD_SIZE - 1) : startX + (MIN_MATCHING - 1));
bool isStarred = GEM_STARRED_AT_SQUARE(square);
if (gemType == GEM_NONE)
gemType = GEM_TYPE_AT_SQUARE(square);
if (startX > 0) {
for (x = startX - 1; x >= leftX; x--) {
square = XY_TO_SQUARE(x, y);
if (gemType != GEM_TYPE_AT_SQUARE(square))
break;
result++;
if (!isStarred)
isStarred = GEM_STARRED_AT_SQUARE(square);
}
}
if (startX < 7) {
for (x = startX + 1; x <= rightX; x++) {
square = XY_TO_SQUARE(x, y);
if (gemType != GEM_TYPE_AT_SQUARE(square))
break;
result++;
if (!isStarred)
isStarred = GEM_STARRED_AT_SQUARE(square);
}
}
if (result < MIN_MATCHING) {
result = 0;
isStarred = false;
}
return result;
}
static void initSquare(tSquare square)
{
tGemType gemType;
do {
gemType = randomGem();
} while ((numMatchingUpDownAtSquare(square, gemType) != 0) ||
(numMatchingRightLeftAtSquare(square, gemType) != 0));
gameState.squareStates[square].gemType = gemType;
}
void initGame(void)
{
tSquare square;
memset(&gameState, 0, sizeof(gameState));
gameState.level = 1;
for (square = MIN_SQUARE; square <= MAX_SQUARE; square++) {
initSquare(square);
}
}
tGemType gemTypeAtSquare(tSquare square)
{
return GEM_TYPE_AT_SQUARE(square);
}
bool gemIsStarredAtSquare(tSquare square)
{
return GEM_STARRED_AT_SQUARE(square);
}
tLevel getLevel(void)
{
return gameState.level;
}
tScore getScore(void)
{
return gameState.score;
}
bool gameIsOver(void)
{
tPos x, y;
tSquare square;
tSquare otherSquare;
tGemType gemType;
tGemType otherGemType;
if (gameState.numSpecial > 0)
return false;
for (x = 0; x < (BOARD_SIZE - 1); x++) {
for (y = 0; y < (BOARD_SIZE - 1); y++) {
square = XY_TO_SQUARE(x, y);
otherSquare = XY_TO_SQUARE(x + 1, y);
gemType = GEM_TYPE_AT_SQUARE(square);
otherGemType = GEM_TYPE_AT_SQUARE(otherSquare);
if (gemType != otherGemType) {
if (numMatchingUpDownAtSquare(otherSquare, gemType) > 0)
return false;
if (numMatchingUpDownAtSquare(square, otherGemType) > 0)
return false;
}
otherSquare = XY_TO_SQUARE(x, y + 1);
otherGemType = GEM_TYPE_AT_SQUARE(otherSquare);
if (gemType != otherGemType) {
if (numMatchingRightLeftAtSquare(otherSquare, gemType) > 0)
return false;
if (numMatchingRightLeftAtSquare(square, otherGemType) > 0)
return false;
}
}
}
return true;
}

View File

@ -10,6 +10,35 @@
#define __a2bejwld__game__
#include <stdbool.h>
#include "types.h"
#define BOARD_SIZE 8
#define NUM_SQUARES (BOARD_SIZE * BOARD_SIZE)
#define MIN_SQUARE 0
#define MAX_SQUARE (MIN_SQUARE + NUM_SQUARES - 1)
#define SQUARE_TO_X(square) ((square) & 0x7)
#define SQUARE_TO_Y(square) ((square) >> 3)
#define XY_TO_SQUARE(x, y) ((y << 3) | x)
#define SCORE_PER_LEVEL 240
void initGame(void);
void moveSquareInDir(tSquare square, tDirection dir);
tGemType gemTypeAtSquare(tSquare square);
bool gemIsStarredAtSquare(tSquare square);
tLevel getLevel(void);
tScore getScore(void);
bool gameIsOver(void);
#endif /* defined(__a2bejwld__game__) */

View File

@ -8,58 +8,16 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <stdbool.h>
#include "dbllores.h"
#include "ui.h"
int main(void)
{
uint8_t square;
printInstructions();
srand(0);
showDblLoRes();
clearDblLoRes();
for (square = 0; square < 64; square++) {
drawBgSquare(square);
switch (rand() % 7) {
case 0:
drawOrangeGem(square);
break;
case 1:
drawBlueGem(square);
break;
case 2:
drawRedGem(square);
break;
case 3:
drawGreyGem(square);
break;
case 4:
drawYellowGem(square);
break;
case 5:
drawPurpleGem(square);
break;
case 6:
drawGreenGem(square);
break;
}
while (true) {
playGame();
}
selectSquare(19);
cgetc();
return 0;
}

44
a2bejwld/types.h Normal file
View File

@ -0,0 +1,44 @@
//
// types.h
// a2bejwld
//
// Created by Jeremy Rand on 2016-07-20.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#ifndef __a2bejwld__types__
#define __a2bejwld__types__
#include <stdint.h>
#define DIR_UP 0
#define DIR_DOWN 1
#define DIR_LEFT 2
#define DIR_RIGHT 3
#define GEM_NONE 0
#define GEM_GREEN 1
#define GEM_RED 2
#define GEM_PURPLE 3
#define GEM_ORANGE 4
#define GEM_GREY 5
#define GEM_YELLOW 6
#define GEM_BLUE 7
#define GEM_SPECIAL 8
#define GEM_MIN_NORMAL GEM_GREEN
#define GEM_MAX_NORMAL GEM_BLUE
typedef uint8_t tSquare;
typedef uint8_t tDirection;
typedef uint8_t tGemType;
typedef uint8_t tLevel;
typedef uint8_t tScore;
typedef int8_t tPos;
#endif /* defined(__a2bejwld__types__) */

266
a2bejwld/ui.c Normal file
View File

@ -0,0 +1,266 @@
//
// ui.c
// a2bejwld
//
// Created by Jeremy Rand on 2016-07-20.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include "ui.h"
#include "dbllores.h"
#include "game.h"
static tSquare gSelectedSquare = 0;
static bool gPlaySounds = true;
static void initUI(void)
{
showDblLoRes();
clearDblLoRes();
}
void printInstructions(void)
{
int seed = 0;
unshowDblLoRes();
videomode(VIDEOMODE_80x24);
clrscr();
printf(
// 0000000001111111111222222222233333333334
// 1234567890123456789012345678901234567890
" Apple Jeweled\n"
"\n"
" Use I-J-K-M or the arrow keys to move\n"
" your selection. Hold the Apple key and\n"
" move your selection to swap two jewels\n"
" and match 3 or more jewels.\n"
"\n"
" Play ends when no more matches can be\n"
" made.\n"
"\n"
" Press escape or Q to quit at any time.\n"
" Press R to start a new game.\n"
" Press S to toggle sound.\n"
" Press H to see this info again.\n"
"\n"
"\n"
"\n"
" Press any key to start");
// The amount of time the user waits to read the in
while (!kbhit())
seed++;
cgetc();
srand(seed);
clrscr();
initUI();
}
static void drawGemAtSquare(tSquare square)
{
switch (gemTypeAtSquare(square)) {
case GEM_GREEN:
drawGreenGem(square);
break;
case GEM_RED:
drawRedGem(square);
break;
case GEM_PURPLE:
drawPurpleGem(square);
break;
case GEM_ORANGE:
drawOrangeGem(square);
break;
case GEM_GREY:
drawGreyGem(square);
break;
case GEM_YELLOW:
drawYellowGem(square);
break;
case GEM_BLUE:
drawBlueGem(square);
break;
default:
asm("brk");
break;
}
}
static void drawBoard(void)
{
tSquare square;
for (square = MIN_SQUARE; square <= MAX_SQUARE; square++) {
drawBgSquare(square);
drawGemAtSquare(square);
}
selectSquare(gSelectedSquare);
}
static void quitGame(void)
{
unshowDblLoRes();
videomode(VIDEOMODE_40x24);
clrscr();
exit(0);
}
static void moveUp(void)
{
tSquare oldSquare = gSelectedSquare;
tPos x = SQUARE_TO_X(gSelectedSquare);
tPos y = SQUARE_TO_Y(gSelectedSquare);
if (y == 0)
y = BOARD_SIZE - 1;
else
y--;
gSelectedSquare = XY_TO_SQUARE(x, y);
drawBgSquare(oldSquare);
drawGemAtSquare(oldSquare);
selectSquare(gSelectedSquare);
}
static void moveDown(void)
{
tSquare oldSquare = gSelectedSquare;
tPos x = SQUARE_TO_X(gSelectedSquare);
tPos y = SQUARE_TO_Y(gSelectedSquare);
if (y == BOARD_SIZE - 1)
y = 0;
else
y++;
gSelectedSquare = XY_TO_SQUARE(x, y);
drawBgSquare(oldSquare);
drawGemAtSquare(oldSquare);
selectSquare(gSelectedSquare);
}
static void moveLeft(void)
{
tSquare oldSquare = gSelectedSquare;
tPos x = SQUARE_TO_X(gSelectedSquare);
tPos y = SQUARE_TO_Y(gSelectedSquare);
if (x == 0)
x = BOARD_SIZE - 1;
else
x--;
gSelectedSquare = XY_TO_SQUARE(x, y);
drawBgSquare(oldSquare);
drawGemAtSquare(oldSquare);
selectSquare(gSelectedSquare);
}
static void moveRight(void)
{
tSquare oldSquare = gSelectedSquare;
tPos x = SQUARE_TO_X(gSelectedSquare);
tPos y = SQUARE_TO_Y(gSelectedSquare);
if (x == BOARD_SIZE - 1)
x = 0;
else
x++;
gSelectedSquare = XY_TO_SQUARE(x, y);
drawBgSquare(oldSquare);
drawGemAtSquare(oldSquare);
selectSquare(gSelectedSquare);
}
void playGame(void)
{
initGame();
drawBoard();
while (true) {
while (!kbhit()) {
// Maybe do some animation stuff here...
}
switch (cgetc()) {
case 'i':
case 'I':
case CH_CURS_UP:
moveUp();
break;
case 'j':
case 'J':
case CH_CURS_LEFT:
moveLeft();
break;
case 'k':
case 'K':
case CH_CURS_RIGHT:
moveRight();
break;
case 'm':
case 'M':
case CH_CURS_DOWN:
moveDown();
break;
case CH_ESC:
case 'q':
case 'Q':
quitGame();
break;
case 'r':
case 'R':
return;
case 's':
case 'S':
gPlaySounds = !gPlaySounds;
break;
case 'h':
case 'H':
printInstructions();
drawBoard();
break;
}
}
}

18
a2bejwld/ui.h Normal file
View File

@ -0,0 +1,18 @@
//
// ui.h
// a2bejwld
//
// Created by Jeremy Rand on 2016-07-20.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#ifndef __a2bejwld__ui__
#define __a2bejwld__ui__
void printInstructions(void);
void playGame(void);
#endif /* defined(__a2bejwld__ui__) */