Skip to content

Instantly share code, notes, and snippets.

@prophile
Created September 17, 2009 16:17
Show Gist options
  • Save prophile/188557 to your computer and use it in GitHub Desktop.
Save prophile/188557 to your computer and use it in GitHub Desktop.
// Simple Mastermind Game
// Copyright (c) Alistair Lynn <[email protected]>, 2008
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
// a single playing piece
typedef char MM_Piece;
// PRNG
static const int MM_PRNG_COEFFICIENT = 1103515245;
static const int MM_PRNG_CONSTANT = 12345;
static const int MM_PRNG_SHIFT = 0;
static const int MM_PRNG_MASK = 0x5FFFFFFF;
int MM_Random ( int* seed )
{
int firstSeed = *seed, output;
firstSeed *= MM_PRNG_COEFFICIENT;
firstSeed += MM_PRNG_CONSTANT;
output = firstSeed >> MM_PRNG_SHIFT;
output &= MM_PRNG_MASK;
*seed = firstSeed;
return output;
}
// a single board
typedef struct _MM_Board
{
MM_Piece pieces[4];
} MM_Board;
// a record of a game
typedef struct _MM_Game
{
int nGames, seed;
MM_Board target;
MM_Piece maxPiece;
} MM_Game;
// checks if a piece is valid
bool MM_Piece_IsValid ( MM_Game* game, MM_Piece piece )
{
return piece >= 'A' &&
piece <= game->maxPiece;
}
// generates a random piece
MM_Piece MM_Piece_Random ( MM_Game* game )
{
return (MM_Random(&(game->seed)) % (game->maxPiece - 'A' + 1)) + 'A';
}
// compares two boards, giving numbers of matches and misplacements
void MM_Board_Compare ( MM_Board board1, MM_Board board2, int* matches, int* misplacements )
{
int i, j, nmatches = 0, nmisplacements = 0, usedMatches = 0;
for (i = 0; i < 4; i++)
{
if (board1.pieces[i] == board2.pieces[i])
{
usedMatches |= (1 << i);
nmatches++;
}
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
if (j == i) continue;
if (!(usedMatches & (1 << j)) && (board1.pieces[i] == board2.pieces[j]))
{
usedMatches |= (1 << j);
nmisplacements++;
}
}
}
*matches = nmatches;
*misplacements = nmisplacements;
}
// sets up a game
void MM_InitGame ( MM_Game* game, MM_Piece maxPiece, int seed, int nGames )
{
game->nGames = nGames;
game->seed = seed;
game->maxPiece = maxPiece;
game->target.pieces[0] = MM_Piece_Random(game);
game->target.pieces[1] = MM_Piece_Random(game);
game->target.pieces[2] = MM_Piece_Random(game);
game->target.pieces[3] = MM_Piece_Random(game);
}
// do a single turn, interacting with the user
void MM_TakeTurn ( MM_Game* game )
{
size_t len;
char inBuffer[6];
int matches, misplacements, i;
MM_Board inBoard;
if (fgets(inBuffer, sizeof(inBuffer), stdin) == &(inBuffer[0]))
{
len = strlen(inBuffer);
if (len != 4 && len != 5)
{
printf("\twrong number of characters\n");
return;
}
else if (len == 5)
{
inBuffer[4] = 0; // strip newline
}
// check piece validity
for (i = 0; i < 4; i++)
{
if (!MM_Piece_IsValid(game, inBuffer[i]))
{
printf("\tbad piece: %c\n", inBuffer[i]);
return;
}
inBoard.pieces[i] = inBuffer[i];
}
MM_Board_Compare(inBoard, game->target, &matches, &misplacements);
if (matches == 4)
{
printf("\tSolved.\n");
exit(0);
}
else
{
printf("\tMatches: %d\n\tMisplacements: %d\n", matches, misplacements);
game->nGames--;
if (game->nGames == 0)
{
printf("\tGame over. The board was:\n\t");
fwrite(&(game->target), sizeof(MM_Board), 1, stdout);
putchar('\n');
exit(0);
}
}
}
else
{
printf("\tfgets() failed, try again.\n");
}
}
int main ( int argc, char** argv )
{
MM_Game game;
MM_Piece maxPiece;
int seed, nGames;
if (argc != 4)
{
printf("Usage: %s [max] [seed] [turns]\n", argv[0]);
return 1;
}
maxPiece = *argv[1];
seed = atoi(argv[2]);
nGames = atoi(argv[3]);
MM_InitGame(&game, maxPiece, seed, nGames);
printf("Mastermind, v1.0.0\n");
printf("Copyright (c) Alistair Lynn <[email protected]> 2009\n");
while (1)
{
MM_TakeTurn(&game);
}
// make the compiler happy
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment