Results 1 to 8 of 8
Code:
struct Players
{
int enemy, ally;
int player_id;
int health_points, magic_points, experience_points;
int level, strength, stamina, agility, speed, wisdom, intelligence;
char player_name[10];
};
I've got this structure, and some ...
- 09-21-2008 #1
Random access to structure members in C.
I've got this structure, and some code to use it with both the structure and pointers to it.Code:struct Players { int enemy, ally; int player_id; int health_points, magic_points, experience_points; int level, strength, stamina, agility, speed, wisdom, intelligence; char player_name[10]; };
The real problem I'm having is trying to figure out a way to access the structure members at "random", or in other words, without having to explicitly write the names in the source code. Is there anyway to use variable substitution or something like it?
For example, if I made my structures and their pointers in this way
Then is there a way to use a random integer to substitute 1? Something like this...Code:struct Players player1; struct Players *player1_ptr = &player1;
Now, I'm borrowing from the ways arrays work just to demonstrate what I mean. In any case, as you can see, if "i" were to replaced by a random integer, then which player is being attacked wouldn't need to be scripted in such an explicit manner.Code:attack(QK_PUNCH, player[i]_ptr, player[i]_ptr)
I realize that the structure names are like variables names and can't have variables substitute part of their name, but I'm wondering if there is any other way I can facilitate choosing "random" members of the structure to do some kind of AI.
I've been using the following to do testing, so if you could give an example using this code it would be much easier to understand.
small_pof.c
attacks.hCode:#include <stdio.h> #include "players.h" #include "attacks.h" void print_vitals(void); struct Players player1, player2, player3; struct Players *player1_ptr = &player1, *player2_ptr = &player2, *player3_ptr = &player3; int main() { init_player(player1_ptr, 0, 0, 0); init_player_vitals(player1_ptr, 100, 100, 100); init_player(player2_ptr, 1, 0, 1); init_player_vitals(player2_ptr, 100, 100, 100); init_player(player3_ptr, 0, 1, 2); init_player_vitals(player3_ptr, 100, 100, 100); printf("\nBefore anyone attacks\nHP\tMP\tEXP\n"); print_vitals(); printf("\nLet's have Player1 be attacked once\n"); attack(QK_PUNCH, player3_ptr, player1_ptr); print_vitals(); printf("\nThen let's say Player1 kills Player3"); attack(100, player1_ptr, player3_ptr); print_vitals(); printf("\nThen let's have Player1 kill his ally Player2\n"); attack(100, player1_ptr, player2_ptr); print_vitals(); return 0; } void print_vitals(void) { printf("\nPlayer1\n%i\t%i\t%i\n", player1.health_points, player1.magic_points, player1.experience_points); printf("\nPlayer2\n%i\t%i\t%i\n", player2.health_points, player2.magic_points, player2.experience_points); printf("\nPlayer3\n%i\t%i\t%i\n", player3.health_points, player3.magic_points, player3.experience_points); }
players.hCode:#define QK_PUNCH 1 #define QK_KICK 2 #define ST_PUNCH 5 #define ST_KICK 10 #define SPC_ATT 25 void attack(int damage, struct Players *attacker, struct Players *target) { target->health_points -= damage; if(target->health_points == 0) { /*target has been defeated*/ if(target->enemy == TRUE && attacker->enemy == FALSE) { target->experience_points--; attacker->experience_points++; } else if(target->enemy == FALSE && attacker->enemy == TRUE) { target->experience_points--; attacker->experience_points++; } else if(target->enemy == FALSE && attacker->ally == TRUE) { target->experience_points--; attacker->experience_points++; } else if(target->enemy == FALSE && ( attacker->ally == FALSE && attacker->enemy == FALSE) ) { target->experience_points--; attacker->experience_points--; } } }
Code:#define TRUE 1 #define FALSE 0 struct Players { int enemy, ally; int player_id; int health_points, magic_points, experience_points; int level, strength, stamina, agility, speed, wisdom, intelligence; char player_name[10]; }; void init_player_vitals(struct Players *player_struct, int health_points, int magic_points, int experience_points) { player_struct->health_points = health_points; player_struct->magic_points = magic_points; player_struct->experience_points = experience_points; } void init_player_atts(struct Players *player_struct, int level, int strength, int stamina, int agility, int speed, int wisdom, int intelligence) { player_struct->level = level; player_struct->strength = strength; player_struct->stamina = stamina; player_struct->agility = agility; player_struct->speed = speed; player_struct->wisdom = wisdom; player_struct->intelligence = intelligence; } void init_player(struct Players *player_struct, int ally, int enemy, int player_id) { player_struct->ally = ally; player_struct->enemy = enemy; player_struct->player_id = player_id; }
- 09-22-2008 #2
You actually have the answer to your question in your own post:
Arrays are exactly what you're looking for here. Instead of having an explicit player1, player2, and player3, have a 3-element array of players, and now you can use any integer to access them!Now, I'm borrowing from the ways arrays work just to demonstrate what I mean. In any case, as you can see, if "i" were to replaced by a random integer, then which player is being attacked wouldn't need to be scripted in such an explicit manner.DISTRO=Arch
Registered Linux User #388732
- 09-22-2008 #3
I suppose, although later I would have the problem of having a maximum amount of players.
The only question I have now is, what type of array would it be? I can only assume it would be an array of structures, but I don't really even know what that would look like or how it would work.
Going off of my hazy memory, wouldn't it be something like
That should make the players, and their members, accessible like so...Code:struct Players { int enemy, ally; int player_id; int health_points, magic_points, experience_points; int level, strength, stamina, agility, speed, wisdom, intelligence; char player_name[10]; }; struct Players players[16];
Right? I'm away from my source code or a compiler, so I can't test right now.Code:player[i].health_points = 100;
It also begs the question how to use the pointers to the structures. Something like
doesn't seem to work.Code:*player_ptr[i] = &player[i];
- 09-22-2008 #4
What problem of a maximum number of players? An array allows you to have as many entries as memory allows, as opposed to the number that you care to code in. You can always limit the number of players by having a check to make sure that you don't exceed some number.
It would look something like this:
I'm not sure why you have an array of players and an array of pointers, though. Why not just have an array of pointers to players? I don't see what you gain by the duplication.Code:struct Player { int enemy, ally; int player_id; int health_points, magic_points, experience_points; int level, strength, stamina, agility, speed, wisdom, intelligence; char player_name[10]; }; struct Player players[MAX_PLAYERS]; /* array of players */ struct Player *player_ptrs[MAX_PLAYERS]; /* array of pointers */ ... populate_players(); for(i = 0; i < MAX_PLAYERS; i++) player_ptrs[i] = &players[i];DISTRO=Arch
Registered Linux User #388732
- 09-22-2008 #5
Well, I suppose having a large array for players would work, but it just seemed sloppy usage of memory; but even if I had 10000 players, that would still be an insignificant amount.
I'm not sure what you mean with having both an array of players and an array of pointers. Wouldn't I need to have the player structures first to point to them, and thus need them both to be arrays? I don't think I understood you.
The reason I want pointers to structures is so I can manipulate the members of two or more of them in a function, as opposed to sending one structure at a time to a function and returning it as a value, if you're asking why the pointers to them.
- 09-22-2008 #6Linux Guru
- Join Date
- Nov 2007
- Location
- Córdoba (Spain)
- Posts
- 1,513
If you don't want to have a static array, you can implement a linked list of players, and allocate the nodes dynamically, using malloc for example. It's the most efficient way to achieve this, regarding ram usage.
- 09-24-2008 #7
The eternal tradeoff: arrays give you random access, but linked list give you indeterminate size.
One possible solution would be to start at some size, and then whenever it fills up, use realloc() to grow the array. It's still not ideal, but you get the random access and the ability to grow (with the possibility of a slight hit whenever you grow).
As for the pointer thing:
malloc() will allocate memory and return a pointer to it. This will use the same amount of space as your first approach, with two advantages:Code:player_ptrs[i] = malloc(sizeof(struct Player)); player_ptrs[i]->player_id = nextID();
- The space for the actual struct doesn't have to be contiguous
- You don't have a whole array floating around whose sole purpose is to be pointed to.
Does this make sense?DISTRO=Arch
Registered Linux User #388732
- 09-26-2008 #8
A couple of suggestions. First, don't use 'struct Player' use a typedef, it makes conceptualisation easier:
Then you only need to use:Code:struct tagPlayers { int enemy, ally; int player_id; int health_points, magic_points, experience_points; int level, strength, stamina, agility, speed, wisdom, intelligence; char player_name[10]; } Players;
Cabhan is right about using linked lists, it's probably better and easier to manage. You may, of course, find the STL collection classes here useful, but that would mean moving to C++. But then again anything that uses instances of structures naturally fits nicely with an object oriented approach.Code:Players * player; players players[100]; ...etc...
If your players list is sorted in some way, you may also want to consider arranging your data in a tree format, i.e. a node has a 'left' and 'right' item, rather than just a 'next' item like you get with a linked list.
If you're using unsorted lists and want to be able to walk the list quicker, consider a doubly-linked list, i.e. one which can be walked in either direction - store a 'prev' and 'next' pointer in each node.
If you have _lots_ of these 'player' instances and only want to manipulate a few at a time, you could write them to a file and load in only the ones you're going to manipulate. If you're doing lots of list-walking the start-up overhead of the load process is far outweighed by the time saved not having to continually walk down a huge list.
Consider a hash table, where a key field is hashed in some way to find it's entry quickly in a separate table. This can allow quick access to the array data, but could be problematic if the list becomes large and has to be re-hashed.Linux user #126863 - see http://linuxcounter.net/


Reply With Quote
