Skip to content

Instantly share code, notes, and snippets.

@Zegnat
Created December 1, 2010 10:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zegnat/723329 to your computer and use it in GitHub Desktop.
Save Zegnat/723329 to your computer and use it in GitHub Desktop.
Pearls before Swine. For school, I am not a C++ developer and never will be.
#include <iostream>
#include <conio+.h>
#include <cmath>
#include <time.h>
using namespace std;
// SETTINGS
#define MIN_LINES 2
#define MAX_LINES 8
#define MIN_PEARL 1
#define MAX_PEARL 6
#define MISERE TRUE
#define MOVE_WAIT TRUE
// MANIPULATORS:
double chartodouble(char* c) {
double n = 0, in = 0;
int t;
bool dec = false, neg = false;
for (int i=strlen(c)-1;i>=0;i--) {
if ((t=c[i]-48)<10 && t>-1) {
n += t*pow(10,in);
in++;
neg = false;
} else if ((t==-2||t==-4) && !dec && in!=0) {
n /= pow(10,in);
in = 0;
dec = true;
neg = false;
} else if (t==-3) neg = !neg;
}
if (neg) n *= -1;
return n;
}
char* toLowerCase(char* c) {
for (int i=0;i<(int)strlen(c);i++) c[i] = tolower(c[i]);
return c;
}
int arrsum(int* a) {
int s = 0;
for (int i=1;i<(a[0]+1);i++) s += a[i];
return s;
}
// GAME MECHANICS:
int *generate_level() {
size_t s = rand() % (MAX_LINES+1-MIN_LINES) + MIN_LINES + 1;
int *a = new int[s];
a[0] = (int)s-1;
for (size_t i=1;i<s;i++) a[i] = rand() % (MAX_PEARL+1-MIN_PEARL) + MIN_PEARL;
return a;
/* Returning an array from a function: http://www.cplusplus.com/forum/beginner/6644/ */
}
void draw_head() {
clrscr();
int l = (MAX_PEARL+5)/2-9;
if (l<1) l = 1;
for (int i=0;i<l;i++) cout << " ";
cout << "PEARLS BEFORE SWINE" << endl;
l = MAX_PEARL+5;
if (l<21) l = 21;
for (int i=0;i<l;i++) cout << "*";
cout << endl << endl;
}
void draw_level(int* level, int hilight=0) {
draw_head();
for (int i=1;i<(level[0]+1);i++) {
if (i==hilight) cout << ">" << i << ": ";
else cout << " " << i << ": ";
for (int j=0;j<level[i];j++) {
cout << "O";
}
cout << endl;
}
cout << endl;
}
int *AI(int* a) {
int X = 0, chosen_heap, nb_remove, heaps_twomore = 0, heaps_one = 0;
for (int i=1;i<(a[0]+1);i++) X = X^a[i];
if (X==0) {
/* New: remove random number of pearls from random row. */
int row, before;
do {
row = rand()%(a[0]+1)+1;
before = a[row];
if (a[row]>0) {
if (a[row]==1) a[row] = 0;
else a[row] = rand()%a[row];
}
} while (before<1);
/* Original: remove the first row with more than 0 pearls completely.
for (int i=1;i<(a[0]+1);i++) {
if (a[i]>0) {
//a[i] = 0;
a[i] = a[i]-1;
break;
}
}*/
} else {
for (int i=1;i<(a[0]+1);i++) {
if ((a[i]^X)<a[i]) chosen_heap = i;
}
nb_remove = a[chosen_heap] - (a[chosen_heap]^X);
for (int i=1,n;i<(a[0]+1);i++) {
if (chosen_heap==i) n = a[i]-nb_remove;
else n = a[i];
if (n>1) heaps_twomore += 1;
}
if (heaps_twomore==0) {
for (int i=1;i<(a[0]+1);i++) {
if (a[i]>a[chosen_heap]) chosen_heap = i;
}
for (int i=1;i<(a[0]+1);i++) {
if (a[i]==1) heaps_one++;
}
if (heaps_one%2!=(int)MISERE) nb_remove = a[chosen_heap]-1;
else nb_remove = a[chosen_heap];
}
a[chosen_heap] = a[chosen_heap] - nb_remove;
}
return a;
/* Ported from Wikipedia's Python implementation: http://en.wikipedia.org/wiki/Nim#Mathematical_theory */
}
// PLAY THE GAME:
int main() {
if (
MIN_LINES<2||
MIN_PEARL<1||
MAX_LINES<MIN_LINES||
MAX_PEARL<MIN_PEARL||
!(MISERE==0||MISERE==1)||
!(MOVE_WAIT==0||MOVE_WAIT==1)
) {
cout << "The game can not run with the current settings...";
_getch();
return 0;
}
srand((int)time(0));
bool play = true;
do {
int* level = generate_level();
char input[50];
int row, qty, last;
do {
draw_level(level);
cout << "Do you want to start? (Y/N)" << endl << "> ";
cin >> input;
toLowerCase(input);
} while (
strcmp("n",input)!=0&&
strcmp("no",input)!=0&&
strcmp("y",input)!=0&&
strcmp("yes",input)!=0
);
if (input[0]=='n') level = AI(level);
if (arrsum(level)==(int)MISERE) {
draw_level(level);
cout << "You lost.";
} else {
do {
row = 0, qty = 0;
do {
draw_level(level);
cout << "Pick a row." << endl << "> ";
cin >> input;
row = (int)chartodouble(input);
if (row>level[0]||row<1||level[row]==0) row = 0;
} while (row==0);
do {
draw_level(level,row);
cout << "Number of pearls to remove." << endl << "> ";
cin >> input;
qty = (int)chartodouble(input);
if (qty>level[row]||qty<1) qty = 0;
} while (qty==0);
level[row] = level[row]-qty;
last = 0;
if (arrsum(level)>1) {
if (MOVE_WAIT) {
draw_level(level);
cout << "Computer wants to move." << endl << "Press any button...";
_getch();
}
AI(level);
last = 1;
}
} while (arrsum(level)>1);
draw_level(level);
cout << "WINNER: ";
if (last==(int)MISERE) cout << "COMPUTER!";
else cout << "YOU!";
_getch();
do {
draw_head();
cout << "Play again? (Y/N)" << endl << "> ";
cin >> input;
toLowerCase(input);
} while (
strcmp("n",input)!=0&&
strcmp("no",input)!=0&&
strcmp("y",input)!=0&&
strcmp("yes",input)!=0
);
if (input[0]=='n') play = false;
}
} while(play);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment