目录
一、扫雷
二、迷宫
三、通讯录
四、核心代码
功能简介:1. 棋盘设置 2. 设置模式 3. 红旗标志 4. 递归展开(DFS)
扫雷
功能介绍: 1. 二维矩阵设置 2. 键盘输入 3. 自动求解(回溯)
迷宫
功能介绍:1. 设计模板 2. 添加、删除、查找 3. 文件操作 4. 用户栏信息展开 5. 排序与优化
可视化通讯录
1. Interface.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#undef UNICODE
#undef _UNICODE
#include
#include
#include
#include
#include
#pragma comment(lib,"winmm.lib")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//1. Minesweeper
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2
#define MODE_EAZY 10
#define MODE_MID 15
#define MODE_HARD 20
void InitBoard(char Board[ROWS][COLS], int rows, int cols, int set);
void SetBoard(char Board[ROWS][COLS], int row, int col, int mode);
void StartToPlay(char inBoard[ROWS][COLS], char outBoard[ROWS][COLS], int row, int col, int mode, int* keep_playing);
//2. Mazegame
#define mROW 21
#define mCOL 29
void MazeGame();
//3. Contact
#define NAME_MAX 16
#define SEX_MAX 8
#define ADD_MAX 16
#define TELE_MAX 16
#define KEY_MAX 16
#define CON_MAX 32
#define AVA_MAX 32
typedef struct PeoInfo //通过学号定位
{
long long stu_number; //学号
char name[NAME_MAX];
char key[KEY_MAX]; //密码
int age;
char sex[SEX_MAX];
char address[ADD_MAX];
char tele[TELE_MAX];
char contact[CON_MAX]; //该学生的通讯录
char avatar[AVA_MAX]; //头像
}IP;
void ContactInter(IP info, unordered_map ID, long long* saveId);
//基于map的所有用户管理
void LoadStudentsID(unordered_map& ID);
void SaveStudentsID(long long* id, IP* info);
void DelstudentsID(long long del);
2.Minesweeper.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Interface.h"
void InitBoard(char Board[ROWS][COLS], int rows, int cols, int set) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
Board[i][j] = set;
}
}
}
//踩雷之后展示整个棋盘
void DisPlayBoardGra(char Board[ROWS][COLS], int r, int c) {
for (int i = 1; i < ROWS-1; i++) {
for (int j = 1; j < COLS-1; j++) {
if (i == r && j == c) continue;
if (Board[i][j] - '0' == 1) {
IMAGE bomb;
loadimage(&bomb, "image_minesweeper\\bomb.jpg");
putimage(100 + (j - 1) * 40, 100 + (i - 1) * 40, &bomb);
}
else {
IMAGE blank2;
loadimage(&blank2, "image_minesweeper\\blank.jpg");
putimage(100 + (j - 1) * 40, 100 + (i - 1) * 40, &blank2);
}
Sleep(75);
}
}
}
//随机放置mode个数的雷到底层棋盘中
void SetBoard(char Board[ROWS][COLS], int row, int col, int mode){
int count = mode;
while (count){
int x = rand() % row + 1;
int y = rand() % col + 1;
if (Board[x][y] != '1'){
Board[x][y] = '1';
count--;
}
}
}
//计算周围雷的数量
int Count(char inBoard[ROWS][COLS], int x, int y){
return (inBoard[x - 1][y - 1] + inBoard[x - 1][y] + inBoard[x][y - 1] +
inBoard[x + 1][y - 1] + inBoard[x + 1][y] + inBoard[x + 1][y + 1] +
inBoard[x][y + 1] + inBoard[x - 1][y + 1] - 8 * '0');
}
void LookForRay(char inBoard[ROWS][COLS], char outBoard[ROWS][COLS], int x, int y, int* win){
if (outBoard[x][y] == 'F') return; //递归到红旗返回
if (inBoard[x][y] == '0')
*win -= 1; //记录win
char sum = Count(inBoard, x, y); //计算周围雷的个数:越界问题?
outBoard[x][y] = sum + '0';
//显示该点周围雷的个数
char sum_str[30];
sprintf(sum_str, "image_minesweeper\\%d.jpg", sum); // 用sprintf合并字符串,通过文件相对位置找到对应图片
IMAGE number;
loadimage(&number, sum_str);
putimage(100 + (y - 1) * 40, 100 + (x - 1) * 40, &number);
//该坐标周围没有雷,想周围递归
if (outBoard[x][y] == '0'){
IMAGE blank;
loadimage(&blank, "image_minesweeper\\blank.jpg");
putimage(100 + (y - 1) * 40, 100 + (x - 1) * 40, &blank);
if (x - 1 >= 1 && x - 1 <= ROW && y - 1 >= 1 && y - 1 <= COL && outBoard[x - 1][y - 1] == '*') //递归条件:递归坐标未被排点,
LookForRay(inBoard, outBoard, x - 1, y - 1, win); //win为地址
if (x - 1 >= 1 && x - 1 <= ROW && y >= 1 && y <= COL && outBoard[x - 1][y] == '*')
LookForRay(inBoard, outBoard, x - 1, y, win);
if (x - 1 >= 1 && x - 1 <= ROW && y + 1 >= 1 && y + 1 <= COL && outBoard[x - 1][y + 1] == '*')
LookForRay(inBoard, outBoard, x - 1, y + 1, win);
if (x >= 1 && x <= ROW && y - 1 >= 1 && y - 1 <= COL && outBoard[x][y - 1] == '*')
LookForRay(inBoard, outBoard, x, y - 1, win);
if (x >= 1 && x <= ROW && y + 1 >= 1 && y + 1 <= COL && outBoard[x][y + 1] == '*')
LookForRay(inBoard, outBoard, x, y + 1, win);
if (x + 1 >= 1 && x + 1 <= ROW && y - 1 >= 1 && y - 1 <= COL && outBoard[x + 1][y - 1] == '*')
LookForRay(inBoard, outBoard, x + 1, y - 1, win);
if (x + 1 >= 1 && x + 1 <= ROW && y >= 1 && y <= COL && outBoard[x + 1][y] == '*')
LookForRay(inBoard, outBoard, x + 1, y, win);
if (x + 1 >= 1 && x + 1 <= ROW && y + 1 >= 1 && y + 1 <= COL && outBoard[x + 1][y + 1] == '*')
LookForRay(inBoard, outBoard, x + 1, y + 1, win);
}
}
void StartToPlay(char inBoard[ROWS][COLS], char outBoard[ROWS][COLS], int row, int col, int mode, int* keep_playing){
int r = 0;
int c = 0;
int win = row * col - mode; //当win等于0时,即剩下的格子全是雷时,判断胜利
bool die = false;
//数量
int flag = mode;
char flag_str[5];
//防止一开始就踩雷
int deathfree = 0;
char deathfree_str[20];
if (mode == MODE_EAZY) deathfree = 1;
if (mode == MODE_MID) deathfree = 2;
if (mode == MODE_HARD) deathfree = 3;
//判断循环条件
while (win && !die){
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg) {
case WM_LBUTTONDOWN: {
r = ((msg.y - 100) / 40) + 1; // 5位棋盘格一小格的宽度 10 * 50 = 500
c = ((msg.x - 100) / 40) + 1;
if (msg.x > 830 && msg.x < 970 && msg.y > 525 && msg.y < 580) {
*keep_playing = 0; //退出游戏,返回扫雷界面
return;
}
if (r >= 1 && r <= row && c >= 1 && c <= col) {
if (outBoard[r][c] == 'F') break; //点击已插旗的格子
//一开始踩到雷的情况 :将该点插入红旗,提醒该点有雷,放置一开始就点到雷
if (inBoard[r][c] == '1' && deathfree > 0) {
Beep(494, 200);
//减少红旗并插入红旗
flag--;
outBoard[r][c] = 'F';
IMAGE FLAG;
loadimage(&FLAG, "image_minesweeper\\flag.jpg");
putimage(100 + (c - 1) * 40, 100 + (r - 1) * 40, &FLAG);
IMAGE flag_board;
loadimage(&flag_board, "image_minesweeper\\flag_board.jpg");
putimage(700, 40, &flag_board);
sprintf(flag_str, "%d", flag);
outtextxy(850, 40, (flag_str));
deathfree--;
sprintf(deathfree_str, "剩余防弹衣:%d", deathfree);
HWND hWnd = GetHWnd();
MessageBox(hWnd, deathfree_str, "! ! ! ! ! ! !", MB_OKCANCEL);
break;
}
if (inBoard[r][c] == '1' && deathfree == 0) {
mciSendString("open bomb.mp3", 0, 0, 0);
mciSendString("play bomb.mp3", 0, 0, 0);
IMAGE red_bomb;
loadimage(&red_bomb, "image_minesweeper\\red_bomb.jpg");
putimage(100 + (c - 1) * 40, 100 + (r - 1) * 40, &red_bomb);
DisPlayBoardGra(inBoard, r, c); //展示整个棋盘
die = true; //将die置为true跳出外层的while循环
break;
}
if (outBoard[r][c] != '*') {
break;
}
LookForRay(inBoard, outBoard, r, c, &win); //排雷:DFS --> 54
if (deathfree > 0) //最开始的前几此排雷对deathfree--;
deathfree--;
}
break;
}
//右键插入红旗 : 该坐标有旗与无旗? 剩余红旗?
case WM_RBUTTONDOWN: {
r = ((msg.y - 100) / 40) + 1;
c = ((msg.x - 100) / 40) + 1;
if (r > 0 && r < 11 && c > 0 && c < 11) {
if (outBoard[r][c] == '*' && outBoard[r][c] != 'F') {
outBoard[r][c] = 'F';
if (flag == 0) {
Beep(494, 200);//震动提示
HWND hWnd = GetHWnd();
MessageBox(hWnd, "无剩余红旗可用!", "无剩余红旗可用!", MB_OKCANCEL);
break;
}
flag--;
IMAGE flag_board;
loadimage(&flag_board, "image_minesweeper\\flag_board.jpg");
putimage(700, 40, &flag_board);
sprintf(flag_str, "%d", flag);
outtextxy(850, 40, flag_str);
//放置
IMAGE FLAG;
loadimage(&FLAG, "image_minesweeper\\flag.jpg");
putimage(100 + (c - 1) * 40, 100 + (r - 1) * 40, &FLAG);
}
else if (outBoard[r][c] == 'F') {
outBoard[r][c] = '*';
//回收
IMAGE back;
loadimage(&back, "image_minesweeper\\back.jpg");
putimage(100 + (c - 1) * 40, 100 + (r - 1) * 40, &back);
flag++;
IMAGE flag_board;
loadimage(&flag_board, "image_minesweeper\\flag_board.jpg");
putimage(700, 40, &flag_board);
sprintf(flag_str, "%d", flag);
outtextxy(850, 40, flag_str);
}
}
break;
}
}
}
}
IMAGE end;
loadimage(&end, "image_minesweeper\\end.jpg");
putimage(200, 150, &end);
if (win == 0) {
settextcolor(RGB(250, 51, 57));
outtextxy(280, 100, "!!!WIN!!!");
}
while (1) {
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg) {
case WM_LBUTTONDOWN: {
if (msg.x > 200 && msg.x < 800 && msg.y > 150 && msg.y < 300) {
return; //keep_playing未改变,继续玩
}
if (msg.x > 200 && msg.x < 800 && msg.y > 300 && msg.y < 450) {
*keep_playing = 0; //返回扫雷界面
return;
}
}
}
}
}
}
3.Mazegame.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Interface.h"
vector path;
bool BackTracking(int maze[mROW][mCOL], int r, int c, int move[4][2], char moveS[4]) {
if (r == 19 && c == 27) return true; //找到出口
if (maze[r - 1][c] == 1 && maze[r + 1][c] == 1 && maze[r][c + 1] == 1 && maze[r][c - 1] == 1) {
return false; //四面均被堵,返回false,回溯,另外求解
}
for (int i = 0; i < 4; i++) {
if (maze[r + move[i][0]][c + move[i][1]] == 1) continue;
path.push_back(moveS[i]);
maze[r + move[i][0]][c + move[i][1]] = 1; //将来路封锁,防止无限递归
if (BackTracking(maze, r + move[i + 4][0], c + move[i + 4][1], move, moveS)) return true; //找到出口连续返回true
else {
path.pop_back(); //弹出path中的走向
maze[r + move[i][0]][c + move[i][1]] = 0; //将该去路封锁 :表示该路找不到答案
}
}
return false; //四路都无答案,返回false(可有可无)
}
void AutomaticSolving(int maze[mROW][mCOL], int startrow, int startcol) {
char moveS[4] = { 's', 'w', 'd', 'a' };
int move[8][2] = { {1,0},{-1, 0},{0, 1},{0, -1},{2,0},{-2, 0},{0, 2},{0, -2} }; //前四个为行走方向,后四个为行走步长
BackTracking(maze, startrow, startcol, move, moveS); 从目前[startrow, startcol]位置开始寻找答案:回溯->获得解决方案 -> 5
int i = startrow;
int j = startcol;
int x = 4 + (j / 2) * 50;
int y = 4 + (i / 2) * 50;
settextcolor(RED);
IMAGE mazeimage;
loadimage(&mazeimage, "image_mazegame\\迷宫.jpg");
IMAGE boger;
loadimage(&boger, "image_mazegame\\博哥.jpg", 45, 45);
for (char move : path) { //读出path中的行走路径
cleardevice();
putimage(0, 0, &mazeimage);
putimage(x, y, &boger);
if (move == 'w') {
i -= 2;
y -= 50;
} else if (move == 's') {
i += 2;
y += 50;
} else if (move == 'a') {
j -= 2;
x -= 50;
} else {
j += 2;
x += 50;
}
Sleep(100);
}
}
void MazeGame(){
int maze[mROW][mCOL] = { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},{1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1},
{1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1},{1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1},{1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1},
{1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1},{1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1},
{1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1},{1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1},
{1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1},{1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1},
{1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1},{1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1},
{1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1},{1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1},
{1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1},{1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1},
{1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1},{1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1},{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} };
while (1) {
int i = 1; //行 (初始坐标)
int j = 1; //列
int learnPoint = 90;
char lPointstr[20];
settextcolor(RED);
IMAGE mazeimage;
loadimage(&mazeimage, "image_mazegame\\迷宫.jpg");
IMAGE boger;
loadimage(&boger, "image_mazegame\\博哥.jpg", 45, 45);
int x = 4;
int y = 4;
int Armor = 3; //护甲,撞墙时-1
char armorStr[20];
while (i != 19 || j != 27) {
FlushBatchDraw();
cleardevice();
putimage(0, 0, &mazeimage);
putimage(x, y, &boger);
sprintf(lPointstr, "所剩学分:%d", learnPoint);
outtextxy(700, 300, lPointstr);
EndBatchDraw();
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg) {
case WM_LBUTTONDOWN:
if (msg.x > 700 && msg.x < 800 && msg.y > 357 && msg.y < 400) {
AutomaticSolving(maze, i, j); //自动求解 -> 26
i = 19; j = 27; //将横纵坐标设置未终点位置,跳出while之后,判断为游戏胜利
break;
}
if (msg.x > 700 && msg.x < 800 && msg.y > 10 && msg.y < 52) {
return;
}
}
}
if (GetAsyncKeyState(VK_UP))
{
if (maze[i - 1][j] == 1) {
if (Armor == 0)
break;
else {
Beep(494, 200);
Armor--;
sprintf(armorStr, "剩余护甲值:%d", Armor);
HWND hWnd = GetHWnd();
MessageBox(hWnd, armorStr, "! ! ! ! ! ! !", MB_OKCANCEL);
continue;
}
}
i -= 2;
y -= 50;
learnPoint--;
Sleep(300);
}
else if (GetAsyncKeyState(VK_DOWN))
{
if (maze[i + 1][j] == 1) {
if (Armor == 0)
break;
else {
Beep(494, 200);
Armor--;
sprintf(armorStr, "剩余护甲值:%d", Armor);
HWND hWnd = GetHWnd();
MessageBox(hWnd, armorStr, "! ! ! ! ! ! !", MB_OKCANCEL);
continue;
}
}
i += 2;
y += 50;
learnPoint--;
Sleep(300);
}
else if (GetAsyncKeyState(VK_LEFT))
{
if (maze[i][j - 1] == 1) {
if (Armor == 0)
break;
else {
Beep(494, 200);
Armor--;
sprintf(armorStr, "剩余护甲值:%d", Armor);
HWND hWnd = GetHWnd();
MessageBox(hWnd, armorStr, "! ! ! ! ! ! !", MB_OKCANCEL);
continue;
}
}
j -= 2;
x -= 50;
learnPoint--;
Sleep(300);
}
else if (GetAsyncKeyState(VK_RIGHT))
{
if (maze[i][j + 1] == 1) {
if (Armor == 0)
break;
else {
Beep(494, 200);
Armor--;
sprintf(armorStr, "剩余护甲值:%d", Armor);
HWND hWnd = GetHWnd();
MessageBox(hWnd, armorStr, "! ! ! ! ! ! !", MB_OKCANCEL);
continue;
}
}
j += 2;
x += 50;
learnPoint--;
Sleep(300);
}
if (learnPoint < 0) break;
}
//三种结束情况
if (learnPoint < 0) {
int lod = -500;
IMAGE game_over_point;
loadimage(&game_over_point, "image_mazegame\\game_over_point.jpg");
while (lod <= 0) {
BeginBatchDraw();
cleardevice();
putimage(0, lod, &game_over_point);
EndBatchDraw();
lod++;
Sleep(1);
}
}
else if (i == 19 && j == 27) {
int lod = 500;
IMAGE game_over_win;
loadimage(&game_over_win, "image_mazegame\\game_over_win.jpg");
while (lod >= 0) {
BeginBatchDraw();
cleardevice();
putimage(0, lod, &game_over_win);
EndBatchDraw();
lod--;
Sleep(1);
}
}
else if (maze[i - 1][j] == 1 || maze[i + 1][j] == 1 || maze[i][j - 1] == 1 || maze[i][j + 1] == 1) {
int lod = 800;
IMAGE game_over_die;
loadimage(&game_over_die, "image_mazegame\\game_over_die.jpg");
while (lod >= 0) {
BeginBatchDraw();
cleardevice();
putimage(lod, 0, &game_over_die);
EndBatchDraw();
lod--;
Sleep(1);
}
}
while (1) {
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg) {
case WM_LBUTTONDOWN:
if (msg.x > 228 && msg.x < 571 && msg.y > 200 && msg.y < 300) {
goto AGAIN; //返回到最外层的while循环
}
if (msg.x > 228 && msg.x < 571 && msg.y > 300 && msg.y < 400) {
return;
}
}
}
}
AGAIN:
printf("keeping playing!\n");
}
}
5.Contact.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Interface.h"
//判断通讯录中是否已经有这个人
bool IsAdd(vector user, long long stu_number) {
for (IP* contact : user) {
if (contact->stu_number == stu_number) {
return true; //如果已添加此人,则返回true
}
}
return false;
}
//用于AddContact() 与 SearchContact() 函数的相互添加功能(考虑当添加-删除-添加后,如何防止对方用户重复添加)
void InterAdd(long long stu_number, unordered_map ID, IP info) {
//判断之前对方是否已经添加过登录用户
FILE* pfr = fopen(ID[stu_number].contact, "rb"); //ID[stu_number].contact ---> 访问对方通讯录
IP* ret = (IP*)malloc(sizeof(IP));
while (fread(ret, sizeof(IP), 1, pfr)) {
if (ret->stu_number == info.stu_number) {
fclose(pfr);
return;
}
}
fclose(pfr);
//若无重复则添加
FILE* pf = fopen(ID[stu_number].contact, "ab");
fwrite(&info, sizeof(IP), 1, pf);
fclose(pf);
}
//bug:map传地址,否则添加到vector的指针是出函数会被摧毁
void AddContact(vector& user, unordered_map& ID, IP info) {
while (1) {
long long stu_number;
printf("学号:>");
scanf("%lld", &stu_number);
//考虑三种情况: 已添加、 添加自己、 添加用户不存在
if (!ID.count(stu_number)) {
printf("查无此人,请重新输入!!\n");
continue;
}
else if (stu_number == info.stu_number) {
printf("无法添加自己,请重新输入!!\n");
continue;
}
else if (IsAdd(user, stu_number)) {
printf("已添加此人,请重新输入\n");
}
else {
user.push_back(&ID[stu_number]);
InterAdd(stu_number, ID, info);
return;
}
}
}
//删除个人账户中的联系人(不删除对方用户的通讯录中自己的信息)
void DelectContact(vector& user) {
if (user.empty()) {
printf("通讯录为空,无法删除\n");
return;
}
char name[NAME_MAX];
printf("请输入你要删除的名字:>");
scanf("%s", name);
IP* search = nullptr;
for (int i = 0; i < user.size(); i++) {
if (!strcmp(name, user[i]->name)) {
search = user[i];
break;
}
}
if (!search) return;
auto del = find(user.begin(), user.end(), search); //find函数返回迭代器,指向search,配合erase删除search
if (del == user.end()) {
printf("没有你要查找的人\n");
return;
}
user.erase(del);
printf("删除成功!\n");
//删除后SaveContact() 保存txt文档
}
//查找ID里的用户 --- 返回true表示查找后添加 , 返回false表示查找后没有添加
bool SearchContact(vector& user, unordered_map& ID, IP info) {
printf("请输入学号:>");
long long stu_number;
scanf("%lld", &stu_number);
if (!ID.count(stu_number)) {
printf("查无此人!\n");
return false;
}
else {
//展示该用户信息
IP people = ID[stu_number];
IMAGE search;
loadimage(&search, "image_contact\\search.jpg");
putimage(200, 200, &search);
settextstyle(22, 0, "黑体");
outtextxy(278, 224, people.name);
char str_number[20] = { '\0' };
sprintf(str_number, "%lld", people.stu_number);
outtextxy(486, 224, str_number);
char str_age[20] = { '\0' };
sprintf(str_age, "%d", people.age);
outtextxy(278, 290, str_age);
outtextxy(500, 290, people.sex);
outtextxy(278, 354, people.tele);
outtextxy(544, 354, people.address);
while (1) {
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg) {
case WM_LBUTTONDOWN:
//添加此人
if (msg.x > 250 && msg.x < 400 && msg.y > 400 && msg.y < 450) {
if (stu_number == info.stu_number) {
HWND hWnd = GetHWnd();
MessageBox(hWnd, "无法添加自己", "! ! ! ! ! ! !", MB_OKCANCEL);
continue;
}
else if (IsAdd(user, stu_number)) { //在链表中查找是否已经添加了该用户, 如果已添加返回true
HWND hWnd = GetHWnd();
MessageBox(hWnd, "已添加该用户", "! ! ! ! ! ! !", MB_OKCANCEL);
continue;
}
else {
user.push_back(&ID[stu_number]);
InterAdd(stu_number, ID, info);
return true; //若添加返回true, 保存txt文档
}
}
//返回
else if (msg.x > 500 && msg.x < 650 && msg.y > 400 && msg.y < 450) {
return false; //没添加则无需保存
}
}
}
}
}
}
//注销学生账户(从map中将该学生信息销毁)
void DelstudentsID(long long del) {
FILE* pf1 = fopen("studentsID.txt", "rb"); //读数据
FILE* pf2 = fopen("del_tmp.txt", "wb"); //写入临时文件
long long* stu_number1 = (long long*)malloc(sizeof(long long));
IP* ip1 = (IP*)malloc(sizeof(IP));
//将除开要删除的学生的信息读取到临时文件
while (fread(stu_number1, sizeof(long long), 1, pf1) && fread(ip1, sizeof(IP), 1, pf1)) {
if (*stu_number1 != del) {
fwrite(stu_number1, sizeof(long long), 1, pf2);
fwrite(ip1, sizeof(IP), 1, pf2);
}
}
fclose(pf1);
fclose(pf2);
FILE* pf3 = fopen("studentsID.txt", "wb");
FILE* pf4 = fopen("del_tmp.txt", "rb");
long long* stu_number2 = (long long*)malloc(sizeof(long long));
IP* ip2 = (IP*)malloc(sizeof(IP));
//再将临时文件的信息读回到studentsID.txt文件中,以此完成对文档的信息删除
while (fread(stu_number2, sizeof(long long), 1, pf4) && fread(ip2, sizeof(IP), 1, pf4)) {
fwrite(stu_number2, sizeof(long long), 1, pf3);
fwrite(ip2, sizeof(IP), 1, pf3);
}
fclose(pf3);
fclose(pf4);
printf("注销完成\n");
}
//加载info.contact文本中的数据到user中,并在ID中检查是否有注销的用户
void LoadContact(vector& user, IP info, unordered_map ID) {
//检查该用户的txt文档中有没有被注销的账户
FILE* pf1 = fopen(info.contact, "rb"); //读数据
FILE* pf2 = fopen("del_tmp.txt", "wb"); //写入临时文件
IP* ip1 = (IP*)malloc(sizeof(IP));
bool flag = false; //判断是否有被注销的账户
while (fread(ip1, sizeof(IP), 1, pf1)) {
if (ID.count(ip1->stu_number)) { //在map中存在则写入临时文本
fwrite(ip1, sizeof(IP), 1, pf2);
}
else {
flag = true; //位于用户文档的信息在map中不存在, 此时flag置为true, 表示需要对临时文件读数据到info.contact中(参考DelstudentsID())
}
}
fclose(pf1);
fclose(pf2);
if (flag) {
FILE* pf3 = fopen(info.contact, "wb");
FILE* pf4 = fopen("del_tmp.txt", "rb");
IP* ip2 = (IP*)malloc(sizeof(IP));
while (fread(ip2, sizeof(IP), 1, pf4)) {
fwrite(ip2, sizeof(IP), 1, pf3);
}
fclose(pf3);
fclose(pf4);
}
FILE* pf = fopen(info.contact, "rb");
int n = 0;
IP* tmp = (IP*)malloc(sizeof(IP));
while (fread(tmp, sizeof(IP), 1, pf)) {
n++;
}
rewind(pf);
while (n--) {
IP* tmp = (IP*)malloc(sizeof(IP));
fread(tmp, sizeof(IP), 1, pf);
user.push_back(tmp);
}
fclose(pf);
pf = NULL;
}
void SaveContact(vector& user, IP info) { //将数组所有节点的数据写入到文档中
FILE* pf = fopen(info.contact, "wb");
if (pf == NULL) {
exit(EXIT_FAILURE);
return;
}
for (int i = 0; i < user.size(); i++) {
fwrite(user[i], sizeof(IP), 1, pf);
}
fclose(pf);
pf = NULL;
}
//加载所有账户信息
void LoadStudentsID(unordered_map& ID) {
FILE* pf = fopen("studentsID.txt", "rb");
int n = 0;
long long* tmp1 = (long long*)malloc(sizeof(long long));
IP* tmp2 = (IP*)malloc(sizeof(IP));
while (fread(tmp1, sizeof(long long), 1, pf) && fread(tmp2, sizeof(IP), 1, pf)) {
n++;
}
rewind(pf);
while (n--) {
long long* stu_number = (long long*)malloc(sizeof(long long));
IP* ip = (IP*)malloc(sizeof(IP));
fread(stu_number, sizeof(long long), 1, pf);
fread(ip, sizeof(IP), 1, pf);
ID[*stu_number] = *ip;
}
fclose(pf);
pf = NULL;
}
//注册一个用户
void SaveStudentsID(long long* stu_number, IP* info) {
FILE* pf = fopen("studentsID.txt", "ab");
fwrite(stu_number, sizeof(long long), 1, pf);
fwrite(info, sizeof(IP), 1, pf);
fclose(pf);
pf = NULL;
}
//展示用户信息,考虑是否有展开的信息
void DisplayContact(vector user, int y, vector isunfold) { //用isunfold数组,记录某一下标的信息是否已被展开
settextcolor(RGB(40, 40, 40));
setbkmode(TRANSPARENT);
settextstyle(25, 15, "微软雅黑");
int index = 0;
for (IP* contact : user) { //遍历user数组中的所有联系人
if (isunfold[index] == false) {
IMAGE doc;
loadimage(&doc, "image_contact\\doc.jpg");
putimage(508, y, &doc);
outtextxy(528, (y + 5), contact->name);
y += 50;
}
else if (isunfold[index] == true) {
IMAGE Unfold;
loadimage(&Unfold, "image_contact\\Unfold.jpg");
putimage(500, y, &Unfold);
settextstyle(30, 0, "黑体");
outtextxy(523, y + 11, contact->name);
settextstyle(26, 0, "黑体");
char str_number[20] = { '\0' };
sprintf(str_number, "%lld", contact->stu_number);
outtextxy(795, y + 11, str_number);
char str_age[20] = { '\0' };
sprintf(str_age, "%d", contact->age);
outtextxy(582, y + 58, str_age);
outtextxy(795, y + 58, contact->sex);
outtextxy(582, y + 105, contact->tele);
outtextxy(845, y + 105, contact->address);
y += 150;
}
index++;
}
}
//展示登录用户的信息
void UserInfo(IP info) {
settextcolor(RGB(40, 40, 40));
setbkmode(TRANSPARENT);
settextstyle(40, 0, "黑体");
outtextxy(675, 12, info.name);
settextstyle(17, 0, "黑体");
char str_number[20] = { '\0' };
sprintf(str_number, "%lld", info.stu_number);
outtextxy(736, 105, str_number);
}
//将鼠标点击的纵坐标传入函数,通过不同的展开与否对y减去相应的值,当y < 0时即找到点击的用户栏位置,并更改isunfold数组的值
void GetIndex(int n, vector& isunfold, int y) {
int index = 0;
for (int i = 0; i < n; i++) {
if (isunfold[index] == false) {
if (y - 50 <= 0) {
isunfold[index] = true;
return;
}
else y -= 50; //未展开的图形高度为50
}
else if (isunfold[index] == true) {
if (y - 150 <= 0) {
isunfold[index] = false;
return;
}
else y -= 150; //已展开的图形高度为150
}
index++;
}
}
//用于ContactInter函数中多次刷新界面
void RefreshInterface(IMAGE avatar, IMAGE chatInter, IMAGE desktop, IP info) {
cleardevice();
putimage(0, 0, &desktop);
putimage(500, 0, &chatInter);
putimage(520, 10, &avatar);
UserInfo(info);
}
//重载
bool CompareName(IP* cont1, IP* cont2) {
return cont1->name < cont2->name;
}
void ContactInter(IP info, unordered_map ID, long long* saveUser) {
vector user;
LoadContact(user, info, ID);
IMAGE chatInter; //界面
IMAGE desktop; //桌面
IMAGE avatar; //头像
loadimage(&desktop, "desktop.jpg");
loadimage(&chatInter, "image_contact\\chatInter.jpg");
loadimage(&avatar, info.avatar, 130, 130);
int enter = 1000;
while (enter >= 500) {
BeginBatchDraw();
cleardevice();
putimage(0, 0, &desktop);
putimage(enter, 0, &chatInter);
putimage(enter + 20, 10, &avatar);
EndBatchDraw();
enter -= 10;
Sleep(2);
}
vector isunfold(100, false);
UserInfo(info); //用户信息
DisplayContact(user, 155, isunfold); //联系人信息——140
while (1) {
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg) {
case WM_LBUTTONDOWN: {
//添加
if (msg.x > 906 && msg.x < 929 && msg.y >123 && msg.y < 145) {
HWND hWnd = GetHWnd();
MessageBox(hWnd, "请在命令行输入添加用户的学号!!","!", MB_OKCANCEL);
AddContact(user, ID, info); //添加的用户必须是ID里存在的用户
//保存、刷新(覆盖图片)、展示 更改信息后必要的三步骤
SaveContact(user, info);
RefreshInterface(avatar, chatInter, desktop, info);
DisplayContact(user, 155, isunfold);
}
//删除
else if (msg.x > 939 && msg.x < 961 && msg.y > 123 && msg.y < 145) {
HWND hWnd = GetHWnd();
MessageBox(hWnd, "请在命令行输入你要删除的人", "! ! ! ! ! ! !", MB_OKCANCEL);
DelectContact(user);
SaveContact(user, info);
RefreshInterface(avatar, chatInter, desktop, info);
DisplayContact(user, 155, isunfold);
}
//通过GetIndex改变isunfold数组相应位置的值,再通过DisplayContact函数展示所有用户
else if (msg.x > 508 && msg.x < 992 && msg.y > 155 && msg.y < 600) {
GetIndex(user.size(),isunfold, msg.y - 155);
RefreshInterface(avatar, chatInter, desktop, info);
DisplayContact(user, 155, isunfold);
}
//查找 -> 展示搜索出的用户的信息 -> 选择是否添加
else if (msg.x > 972 && msg.x < 995 && msg.y > 123 && msg.y < 145) {
HWND hWnd = GetHWnd();
MessageBox(hWnd, "请在命令行输入你要查找的人", "! ! ! ! ! ! !", MB_OKCANCEL);
if (SearchContact(user, ID, info)) { //返回true表示添加联系人,此时保存联系人
SaveContact(user, info);
}
RefreshInterface(avatar, chatInter, desktop, info);
DisplayContact(user, 155, isunfold);
}
//排序
else if (msg.x > 873 && msg.x < 897 && msg.y > 123 && msg.y < 145) {
sort(user.begin(), user.end(), CompareName); //->421
RefreshInterface(avatar, chatInter, desktop, info);
DisplayContact(user, 155, isunfold);
}
//退出登录
else if (msg.x > 872 && msg.x < 995 && msg.y > 4.6 && msg.y < 24.6) {
*saveUser = 0;
int exit = 500;
while (exit <= 1000) {
BeginBatchDraw();
cleardevice();
putimage(0, 0, &desktop);
putimage(exit, 0, &chatInter);
EndBatchDraw();
exit += 10;
Sleep(2);
}
return;
}
//返回桌面, 保持登录
else if (msg.x > 0 && msg.x < 500 && msg.y > 0 && msg.y < 600) {
int exit = 500;
while (exit <= 1000) {
BeginBatchDraw();
cleardevice();
putimage(0, 0, &desktop);
putimage(exit, 0, &chatInter);
EndBatchDraw();
exit += 10;
Sleep(2);
}
return;
}
}
}
}
}
}
拷贝代码仓库到本地:
gitee:Program lobby: C/C++程序设计 + easyx (gitee.com)