簡單遊戲場景用戶模擬

幫朋友寫的, 很簡單...

還是貼出來, 希望能對看客有所幫助, 也希望看客能對我有所幫助...


謝謝.


#include <stdio.h>
#include <stdlib.h>
/**
 * author: selfimpr
 * blog: http://blog.csdn.net/lgg201
 * mail: [email protected]
 */

struct UserPool {
	struct User *head;			/* 所分配存儲空間首指針 */
	struct User *useable;		/* 當前未使用的存儲空間首指針 */
	struct User *free;			/* 空閒鏈表首指針 */
	int			used;			/* 內存池中已在線的用戶數 */
	int			alloced;		/* 分配的內存池大小 */
};	/* 用戶內存池 */

struct User {
	int				uid;		/* 用戶標識 */
	int				fd;			/* 文件描述符 */
	struct Map		*map_p;		/* 所在地圖 */
	int				map_i;		/* 在所在地圖用戶數組中的下標 */
	struct User		*next;		/* 作爲內存池空閒鏈表時的構造指針 */
	struct UserPool	*pool;		/* 所在內存池 */
	int				isfree;		/* 是否空閒(1表示用戶已離線, 空間可重用) */
	int				pool_i;		/* 在內存池中的下標 */
};	/* 用戶 */

struct Map {
	struct User	**users;	/* 用戶數組 */
	int			alloced;	/* 已分配用戶數組大小 */
	int			used;		/* 已使用用戶數組大小 */
};	/* 地圖 */

struct HashTableElement {
	unsigned int				key;		/* 鍵 */
	void						*value;		/* 值 */
	struct HashTableElement		*next;		/* 下一個節點 */
};	/* 哈希表元素 */

struct HashTable {
	struct HashTableElement		*elements;		/* 存儲數據的鏈表數組 */
	unsigned int				size;			/* 哈希表大小 */
};	/* 哈希表 */

/* 創建哈希表 */
struct HashTable *hash_table_create(unsigned int size) {
	struct HashTable	*ht;

	ht				= (struct HashTable *)malloc(sizeof(struct HashTable));
	if ( ht == NULL ) 
		goto failed;
	
	ht->size		= size;
	ht->elements	= (struct HashTableElement *)calloc(size, sizeof(struct HashTableElement));
	if ( ht->elements == NULL )
		goto failed;

	return ht;

failed:
	printf("hash_table_create failed\n");
	if ( ht != NULL ) {
		if ( ht->elements != NULL )
			free(ht->elements);
		free(ht);
	}
	return NULL;
}

/* 向哈希表中寫入或更新數據 */
int hash_table_add_or_update(struct HashTable *ht, unsigned int k, void *value) {
	struct HashTableElement		*h, *e, *n;

	h	= &(ht->elements[k % ht->size]);
	e	= h->next;

	if ( e == NULL ) {
		e	= h;
		goto insert;
	}

	do {
		if ( e->key == k )
			goto update;
		else
			e	= e->next;
	} while ( e->next != NULL );
	
insert:
	n			= (struct HashTableElement *)calloc(1, sizeof(struct HashTableElement));
	n->key		= k;
	n->value	= value;
	e->next		= n;

	return (0);

update:
	e->value	= value;
	return (0);
}

/* 在哈希表中查找數據 */
struct HashTableElement *hash_table_find(struct HashTable *ht, unsigned int k) {
	struct HashTableElement	*h, *e;

	h	= &(ht->elements[k % ht->size]);
	e	= h->next;

	if ( e == NULL )
		goto failed;
	
	do {
		if ( e->key == k )
			return e;
		else 
			e	= e->next;
	} while ( e != NULL );
	
failed:
	return NULL;
}

/* 從哈希表中刪除數據 */
int hash_table_delete(struct HashTable *ht, unsigned int k) {
	struct HashTableElement	*p, *e;

	p	= &(ht->elements[k % ht->size]);
	e	= p->next;

	if ( e == NULL )
		goto failed;
	
	do {
		if ( e->key == k ) {
			p->next	= e->next;
			free(e);
			return (0);
		} else {
			p	= e;
			e	= e->next;
		}
	} while ( e != NULL );

failed:
	return (-1);
}

/* 輸出哈希表數據 */
void hash_table_dump(struct HashTable *ht, char *(*to_string)(void *)) {
	int						i;
	struct HashTableElement	*h, *e;

	for ( i = 0; i < ht->size; i ++ ) {
		h	= &(ht->elements[i]);
		e	= h->next;
		while ( e != NULL ) {
			printf("%d: %s\n", e->key, to_string(e->value));
			e	= e->next;
		}
	}
}

/* 用於哈希表測試用例的字符串轉換函數 */
char *empty_to_string(void *v) {
	return (char *)v;
}

/* 哈希表測試用例 */
void hash_table_test() {
	struct HashTable	*ht;

	ht	= hash_table_create((unsigned int)30);

	hash_table_add_or_update(ht, 1, (void *)"one");
	hash_table_add_or_update(ht, 2, (void *)"two");
	hash_table_add_or_update(ht, 3, (void *)"three");
	hash_table_add_or_update(ht, 4, (void *)"four");
	hash_table_add_or_update(ht, 1, (void *)"first-one");
	hash_table_add_or_update(ht, 2, (void *)"second-two");
	hash_table_add_or_update(ht, 3, (void *)"third-three");
	hash_table_add_or_update(ht, 4, (void *)"forth-four");
	hash_table_delete(ht, 3);

	hash_table_dump(ht, empty_to_string);
}

/* 地圖創建 */
struct Map *map_create(int num) {
	struct Map	*map;

	map				= (struct Map *) malloc(sizeof(struct Map));
	if ( map == NULL )
		goto failed;

	map->users		= (struct User **) calloc(num, sizeof(struct User *));
	map->alloced	= num;
	map->used		= 0;

	return map;
failed:
	if ( map != NULL )
		free(map);
	return NULL;
}

/* 用戶進入地圖 */
int map_user_enter(struct Map *map, struct User *user) {
	int		i;

	for ( i = 0; i < map->alloced; i ++ ) {
		if ( map->users[i] == NULL ) {
			map->users[i]	= user;
			user->map_p		= map;
			user->map_i		= i;
			map->used ++;
			return (0);
		}
	}
	return (-1);
}

/* 用戶離開地圖 */
int map_user_leave(struct User *user) {
	user->map_p->users[user->map_i]	= NULL;
	user->map_p->used --;
	user->map_i		= 0;
	user->map_p		= NULL;
}

/* 創建用戶內存池 */
struct UserPool *user_pool_create(int size) {
	struct UserPool	*pool;

	pool	= (struct UserPool *)malloc(sizeof(struct UserPool));

	pool->head		= (struct User *)calloc(size, sizeof(struct User));
	pool->useable	= pool->head;
	pool->free		= NULL;
	pool->alloced	= size;
	pool->used		= 0;

	return (pool);
failed:
	if ( pool != NULL ) {
		if ( pool->head != NULL ) 
			free(pool->head);
		free(pool);
	}
	return (NULL);
}

/* 從內存池分配一個用戶的空間 */
struct User *user_pool_alloc_user(struct UserPool *pool) {
	struct User	*u;
	/* TODO 此處應該是內存池擴展邏輯, 比較複雜, 未實現 */
	
	/* 從空閒鏈表中分配 */
	if ( pool->free != NULL ) {
		u			= pool->free;
		u->isfree	= 0;
		pool->free	= pool->free->next;
		pool->used ++;
		return u;
	}

	/* 從未使用空間中分配 */
	u			= pool->useable;
	u->pool		= pool;
	u->pool_i	= pool->useable - pool->head;
	pool->useable ++;
	pool->used ++;
	return u;
}

/* 從內存池中釋放一個用戶 */
void user_pool_free_user(struct User *user) {
	struct UserPool	*pool;

	pool			= user->pool;
	user->isfree	= 1;
	/* 將被釋放的空間放入空閒鏈表 */
	user->next		= pool->free;
	pool->free		= user;
	/* 更新用戶計數 */
	pool->used --;
}

struct Map			**maps;		/* 所有的地圖 */
struct HashTable	*user_ht;	/* 用戶哈希表 */
struct UserPool		*user_pool;	/* 用戶內存池 */

/* 地圖數量 */
int map_num = 1;
/* 地圖最大人數 */
int map_user_num = 10;
/* 總人數上限 */
int user_num = 100;

/* 遊戲初始化 */
int game_init() {
	int		i;

	/* 地圖初始化 */
	maps	= (struct Map **)calloc(map_num, sizeof(struct Map *));

	for ( i = 0; i < map_num; i ++ ) {
		maps[i]	= map_create(map_user_num);
	}

	/* 用戶存儲初始化 */
	user_pool	= user_pool_create(user_num);

	/* 用戶哈希表初始化 */

	user_ht		= hash_table_create(user_num);
}

/* 用戶登入 */
void user_login(int uid, int fd) {
	struct User	*user;

	/* 在內存池中爲用戶分配空間 */
	user		= user_pool_alloc_user(user_pool);

	/* 初始化用戶基本信息 */
	user->uid	= uid;
	user->fd	= fd;

	/* 用戶進入地圖 */
	map_user_enter(maps[0], user);

	/* 將用戶放入哈希表便於查找 */
	hash_table_add_or_update(user_ht, uid, (void *)user);
}

/* 用戶登出 */
void user_logout(int uid) {
	struct HashTableElement	*e;
	struct User 			*user;

	/* 從哈希表中查找用戶 */
	e		= (struct HashTableElement *)hash_table_find(user_ht, uid);
	user	= (struct User *)e->value;

	/* 用戶離開地圖 */
	map_user_leave(user);

	/* 從內存池中釋放用戶 */
	user_pool_free_user(user);

	/* 從哈希表中移除用戶 */
	hash_table_delete(user_ht, uid);
}

/* 將用戶轉換爲字符串 */
char *user_to_string(void *value) {
	static char	buffer[1024];
	struct User	*user;

	user	= (struct User *)value;
	sprintf(buffer, "uid: %d, fd: %d, map_p: %p, map_i: %d, pool: %p, pool_i: %d, ptr: %p, next: %p", 
		user->uid, user->fd, user->map_p, user->map_i, user->pool, user->pool_i, user, user->next);
	return buffer;
}

int main(int argc, char *argv[]) {
	/* 初始化遊戲 */
	game_init();

	int				i;
	struct User 	*tmp;

	/* 登入十個用戶 */
	for ( i = 1; i <= 10; i ++ ) 
		user_login(i, i);

	/* 登出三個用戶 */
	user_logout(2);
	user_logout(3);
	user_logout(4);

	/* 打印在線用戶信息 */
	hash_table_dump(user_ht, user_to_string);

	/* 打印用戶內存池的空閒鏈表 */
	printf("\nfree elements:\n");
	for ( tmp = user_pool->free; tmp != NULL; tmp = tmp->next )
		printf("%s\n", user_to_string((void *)tmp));
}


發佈了123 篇原創文章 · 獲贊 1149 · 訪問量 130萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章