利用easyx库设计并实现一个二叉树着色游戏
Tree.h
#ifndef TREE_H
#include <graphics.h> // 引用图形库头文件
#include <easyx.h>
#include <conio.h>
#include <math.h>
#define MaxSize 50
#define LENGTH 1080
#define WIDTH 720
#define LINELENGTH floor(60*sqrt(2))
#define RADIUS floor(10*sqrt(2))
enum NodeColor { white, red, blue };
enum Direction { LEFT, RIGHT };
enum Players { one, two };
int x_tree = 540, y_tree = 60;
typedef struct PSTreeNode
{
int val; //值
int color; //颜色
PSTreeNode* parent; //双亲结点
PSTreeNode* lchild; //左孩子结点
PSTreeNode* rchild; //右孩子结点
int x; //圆心x坐标
int y; //圆心y坐标
}PSTree;
//画树枝
void DrawLine(int xi, int yi, int xe, int ye, int flag) {
int x1, x2;
int y1 = yi + 10;
int y2 = ye - 10;
if (flag == LEFT) {
x1 = xi - 10;
x2 = xe + 10;
}
else if (flag == RIGHT) {
x1 = xi + 10;
x2 = xe - 10;
}
line(x1, y1, x2, y2);
}
//计算下一个结点圆心坐标
int* CircleCenter(int flag, int x, int y) {
int a[2];
static int n = 0; //记录结点数
static int h = 1; //记录第几层
static int xchange = 400; //记录横坐标差值
++n;
if (n == pow(2, h - 1)) {
h++;
n = 0;
xchange /= 2;
}
if (flag == LEFT) {
a[0] = x - xchange;
a[1] = y + 80;
}
else if (flag == RIGHT) {
a[0] = x + xchange;
a[1] = y + 80;
}
return a;
}
//点击的位置在圆内 x,y鼠标点击的坐标
bool InCircle(int x, int y, int xc, int yc) {
if ((pow((xc - x), 2) + pow((yc - y), 2)) <= pow(RADIUS, 2))
{
return true;
}
else
return false;
}
#endif // !TREE_H
Queue.h
#ifndef QUEUE_H
#include <stdio.h>
#include "tree.h"
//#define MaxSize 50
//typedef struct qnode
//{
// PSTree* data;
// struct qnode* next;
//}QNode;
typedef struct
{
PSTree* data[MaxSize];
int front, rear;
}LiQueue;
void InitQueue(LiQueue*& q)
{
q = (LiQueue*)malloc(sizeof(LiQueue));
q->front = q->rear = 0;
}
void DestroyQueue(LiQueue*& q)
{
free(q);
}
bool QueueEmpty(LiQueue* q)
{
return (q->rear == q->front);
}
bool enQueue(LiQueue*& q, PSTree* e)
{
if ((q->rear + 1) % MaxSize == q->front) {
return false;
}
q->rear = (q->rear + 1) % MaxSize;
q->data[q->rear] = e;
return true;
}
bool deQueue(LiQueue*& q, PSTree*& e)
{
if (q->front == q->rear) {
return false;
}
q->front = (q->front + 1) % MaxSize;
e = q->data[q->front];
return true;
}
#endif // !QUEUE_H
Best.h
#ifndef BEST_H
#include "queue.h"
//打印一号玩家胜率最大的点
void PlayerOne(int n, PSTree* tree, int& oneWin)
{
int i = 1;
PSTree* p = tree;
while (p->rchild != NULL)
{
i++;
p = p->rchild;
}
if (pow(2, i) - 1 == n)
{
outtextxy(30, 60, _T("1为player1胜率较大的位置"));
oneWin = 1;
}
else if ((pow(2, i + 1) - 2 == n) && (pow(2, i) == n))
{
outtextxy(30, 60, _T("1或2为player1胜率较大的位置"));
}
else
{
outtextxy(30, 60, _T("2为player1胜率较大的位置"));
oneWin = 2;
}
return;
}
//打印二号玩家胜率最大的点
void PlayerTwo(int n, PSTree* tree, int oneWin)
{
int m, twoWin;
PSTree* p = tree;
LiQueue* qu;
InitQueue(qu);
enQueue(qu, p);
while (!QueueEmpty(qu))
{
deQueue(qu, p);
if (p->color == red)
{
m = p->val;
break;
}
if (p->lchild != NULL)
{
enQueue(qu, p->lchild);
}
if (p->rchild != NULL)
{
enQueue(qu, p->rchild);
}
}
if (m == oneWin)
{
outtextxy(30, 90, _T("player2无法获胜"));
return;
}
if (p->parent != NULL) //一号玩家不是根节点
{
twoWin = p->parent->val;
}
else //一号玩家是根节点
{
twoWin = 2;
}
char c = '0' + twoWin;
outtextxy(30, 90, c);
outtextxy(40, 90, _T("为player2胜率较大的位置"));
return;
}
#endif // !BEST_H
Game.h
#ifndef GAME_H
#include <windows.h> //用到了定时函数sleep()
#include "best.h"
int whitecount = 0; //白色结点个数
int player; //当前玩家
int count = 0; //第一次和第二次着色
bool playerone = true; //玩家1有可走结点
bool playertwo = true; //玩家2有可走结点
int rec[] = { 940,30,1040,80 };//跳过按钮
//建立一个结点
PSTree* CreateNode(PSTree* parent, int x) {
PSTree* tree = (PSTree*)malloc(sizeof(PSTree));
tree->val = x;
tree->lchild = NULL;
tree->rchild = NULL;
tree->parent = parent;
tree->color = white;
return tree;
}
//创建一棵树
PSTree* CreateTree(int root[], int n) {
settextcolor(BLACK);
setlinecolor(BLACK);
outtextxy(30, 30, _T("二叉树着色游戏"));
LiQueue* treeQueue;
int i = 2, count = 1;
InitQueue(treeQueue);
PSTree* tree;
PSTree* node = (PSTree*)malloc(sizeof(PSTree));
//创建根节点
tree = CreateNode(NULL, root[1]);
tree->x = x_tree;
tree->y = y_tree;
node = tree;
circle(node->x, node->y, RADIUS);
enQueue(treeQueue, node);
while (!QueueEmpty(treeQueue)) {
deQueue(treeQueue, node);
if (node->lchild == NULL) {
PSTree* treeNode = CreateNode(node, root[i]);
node->lchild = treeNode;
int* xy = CircleCenter(LEFT, node->x, node->y);
treeNode->x = xy[0];
treeNode->y = xy[1];
DrawLine(node->x, node->y, treeNode->x, treeNode->y, LEFT);
circle(treeNode->x, treeNode->y, RADIUS);
enQueue(treeQueue, treeNode);
count++;
i++;
if (count == n || i > n) {
break;
}
}
if (node->rchild == NULL) {
PSTree* treeNode = CreateNode(node, root[i]);
node->rchild = treeNode;
int* xy = CircleCenter(RIGHT, node->x, node->y);
treeNode->x = xy[0];
treeNode->y = xy[1];
DrawLine(node->x, node->y, treeNode->x, treeNode->y, RIGHT);
circle(treeNode->x, treeNode->y, RADIUS);
enQueue(treeQueue, treeNode);
count++;
i++;
if (count == n || i > n) {
break;
}
}
}
DestroyQueue(treeQueue);
return tree;
}
//游戏结束条件 所有结点都不是白色
bool GameOver(PSTree* tree, int n) {
if (tree != NULL) {
GameOver(tree->lchild, n);
GameOver(tree->rchild, n);
if (tree->color == white) {
++whitecount;
}
//有是白色的结点,说明游戏未结束
if (whitecount != 0) {
return false;
}
else {
return true;
}
}
}
//跳过按钮
bool pass(int x,int y) {
if (x > rec[0] && x<rec[2] && y>rec[1] && y < rec[3]) {
if (player == one) {
player = two;
playerone = false;
outtextxy(920, 100, _T("1号玩家无可走结点"));
outtextxy(930, 125, _T("已切换到2号玩家"));
return false;
}
else if (player == two) {
player = one;
playertwo = false;
outtextxy(920, 100, _T("2号玩家无可走结点"));
outtextxy(930, 125, _T("已切换到1号玩家"));
return false;
}
}
else {
return false;
}
}
//变色判断条件
void judge(PSTree* tree, int x, int y, PSTree* root, bool firORsec = false) {
if (playerone && playertwo && pass(x, y)) {
return;
}
if (!firORsec) {
if (player == one
&& tree->color == white
&& InCircle(x, y, tree->x, tree->y) ) {
if ((tree->parent == NULL
&& tree->lchild != NULL
&& tree->rchild != NULL
&& (tree->lchild->color == red || tree->rchild->color == red)
&& playerone)
|| (tree->parent != NULL
&& tree->lchild == NULL
&& tree->rchild == NULL
&& tree->parent->color == red
&& playerone)
|| (tree->parent != NULL
&& tree->lchild != NULL
&& tree->rchild != NULL
&& (tree->lchild->color == red || tree->rchild->color == red || tree->parent->color == red)
&& playerone)) {
tree->color = red;
clearcircle(tree->x, tree->y, RADIUS);
setlinecolor(BLACK);
setfillcolor(RED);
circle(tree->x, tree->y, RADIUS);
fillcircle(tree->x, tree->y, RADIUS);
if (playertwo) {
player = two;
}
}
}
else if (player == two
&& tree->color == white
&& InCircle(x, y, tree->x, tree->y)) {
if ((tree->parent == NULL
&& tree->lchild != NULL
&& tree->rchild != NULL
&& (tree->lchild->color == blue || tree->rchild->color == blue)
&& playertwo)
|| (tree->parent != NULL
&& tree->lchild == NULL
&& tree->rchild == NULL
&& tree->parent->color == blue
&& playertwo)
|| (tree->parent != NULL
&& tree->lchild != NULL
&& tree->rchild != NULL
&& (tree->lchild->color == blue || tree->rchild->color == blue || tree->parent->color == blue)
&& playertwo)) {
tree->color = blue;
clearcircle(tree->x, tree->y, RADIUS);
setlinecolor(BLACK);
setfillcolor(BLUE);
circle(tree->x, tree->y, RADIUS);
fillcircle(tree->x, tree->y, RADIUS);
if (playerone) {
player = one;
}
}
}
}
//第一次或第二次填充颜色时
else {
if (tree->color == white
&& InCircle(x, y, tree->x, tree->y)
) {
if (count == 0) {
tree->color = red;
clearcircle(tree->x, tree->y, RADIUS);
setlinecolor(BLACK);
setfillcolor(RED);
circle(tree->x, tree->y, RADIUS);
fillcircle(tree->x, tree->y, RADIUS);
++count;
player = two;
return;
}
else if (count == 1) {
tree->color = blue;
clearcircle(tree->x, tree->y, RADIUS);
setlinecolor(BLACK);
setfillcolor(BLUE);
circle(tree->x, tree->y, RADIUS);
fillcircle(tree->x, tree->y, RADIUS);
++count;
player = one;
return;
}
}
}
}
int WinPlayer(PSTree* root) {
static int oneCount = 0;
static int twoCount = 0;
if (root != NULL) {
WinPlayer(root->lchild);
WinPlayer(root->rchild);
if (root->color == red) {
oneCount++;
}
else if (root->color == blue) {
twoCount++;
}
}
return (oneCount > twoCount) ? one : two;
}
void MouseClick(PSTree* root, int x, int y, int n, bool firORsec =false) {
LiQueue* qu;
InitQueue(qu);
int count = 1;
PSTree* node = (PSTree*)malloc(sizeof(PSTree));
node = root;
enQueue(qu, node);
judge(node, x, y, root, firORsec);
while (!QueueEmpty(qu)) {
deQueue(qu, node);
if (node->lchild != NULL) {
enQueue(qu, node->lchild);
judge(node->lchild, x, y, root, firORsec);
count++;
if (count == n) {
break;
}
}
if (node->rchild != NULL) {
enQueue(qu, node->rchild);
judge(node->rchild, x, y, root, firORsec);
count++;
if (count == n) {
break;
}
}
}
DestroyQueue(qu);
}
void GamePlay() {
initgraph(LENGTH, WIDTH);//初始化窗口(黑屏)
for (int i = 0; i < 256; i += 5)
{
setbkcolor(RGB(i, i, i));//设置背景色,原来默认黑色
cleardevice();//清屏(取决于背景色)
Sleep(15);//延时15ms
}
int root[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
player = one;
int length = sizeof(root) / sizeof(int) - 1;
bool firORsec = true;
PSTree* tree = CreateTree(root, length);
RECT rect = { rec[0], rec[1], rec[2], rec[3] };
rectangle(rec[0], rec[1], rec[2], rec[3]);
drawtext(_T("pass"), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
int oneWin = 0;
PlayerOne(length, tree, oneWin);
MOUSEMSG m;//鼠标指针
setrop2(R2_NOTXORPEN);//二元光栅——NOT(屏幕颜色 XOR 当前颜色)
while (!GameOver(tree, length))
{
m = GetMouseMsg();//获取一条鼠标消息
if (m.uMsg == WM_LBUTTONDOWN && firORsec)
{
for (int i = 0; i <= 10; i++)
{
setlinecolor(RGB(25 * i, 25 * i, 25 * i));//设置圆颜色
circle(m.x, m.y, 2 * i);
Sleep(25);//停顿2ms
circle(m.x, m.y, 2 * i);//抹去刚刚画的圆
}
MouseClick(tree, m.x, m.y, length, firORsec);
if (count == 1) {
PlayerTwo(length, tree, oneWin);
}
//判断是否已经画了两个结点了
if (count >= 2) {
firORsec = false;
}
FlushMouseMsgBuffer();//清空鼠标消息缓存区
}
else if(m.uMsg == WM_LBUTTONDOWN && !firORsec){
for (int i = 0; i <= 10; i++)
{
setlinecolor(RGB(25 * i, 25 * i, 25 * i));//设置圆颜色
circle(m.x, m.y, 2 * i);
Sleep(25);//停顿2ms
circle(m.x, m.y, 2 * i);//抹去刚刚画的圆
}
MouseClick(tree, m.x, m.y, length);
FlushMouseMsgBuffer();//清空鼠标消息缓存区
}
whitecount = 0;
}
settextcolor(BLACK);
if (WinPlayer(tree) == one) {
TCHAR s[] = _T("1号玩家获胜");
outtextxy(510, 680, s);
}
else if (WinPlayer(tree) == two) {
TCHAR s[] = _T("2号玩家获胜");
outtextxy(510, 680, s);
}
system("pause");//暂停,为了显示
closegraph();
}
#endif // !GAME_H
main.cpp
#include "game.h"
//完全二叉树 结点个数为奇数
int main()
{
GamePlay();
return 0;
}