-
A task involving linked lists and a headache
Hi everyone around here, im new and im hopint to give and get help ;)
The task is to create a linked list consisting of bunny's, the bunny is a class.
Im having problems in managing the list itself. I have doubts about the Delete() function in the list, is it correct?
When the bunnies reach 10 years, they should die, that means, that the first 5 bunnies should die all tohether, but they dont, 3 of them do, the other 2 die each the following 2 years. The 2 survivors dont age when the 3 die, but they should. [Bolded]
Objects are added in the back of the list, so that Head points to the very first element. The OutOfFood() function is doing nothing but harm, although it should work. Kills half of them, and then just keeps killing... If they are a lot of them, then it even prints, that nameless or completely all-less bunnies are killed.
Ive noticed, that sometimes, so bunnies are created without something (Color, Name etc.).
Sorry for the long post, the code seems a mess and i dont know where even to start cheking.
Thanks in advance!
Code:
#include <iostream>
#include <time.h>
#include <string>
using namespace std;
char *Names[15]={"Phill","Colin","Bucket","Fluffy","Mister","Lilly","Rose","Shamandale","Yoshie","Jane","PeanutButter","Plank","Sucubus","Broken","Horse ****"};
class Bunny
{
public:
string Sex;
string Color;
int Age;
string Name;
bool Mutant;
Bunny *Next;
int Random(int x)
{
return x=rand()%(x+1);
}
bool MutantBunny()
{
int X=Random(100);
if(X<2)
{
return true;
}
return false;
}
string SexIsNotAChoise()
{
int R=Random(10);
if(R<5)
{
Sex="Male";
}
else
{
Sex="Female";
}
return Sex;
}
string HopeImNotBlack()
{
int R=Random(100);
if(R<24)
{
Color="White";
}
else if(R>24 && R<=49)
{
Color="Brown";
}
else if(R>50 && R<=75)
{
Color="Black";
}
else if(R>76)
{
Color="Spotted";
}
return Color;
}
int ImNotOld()
{
Age=0;
return Age;
}
string HelloMyNameIs()
{
if(Mutant==true)
{
Name=Names[rand()%(14-10)+10];
}
else if(Sex=="Male")
{
Name=Names[rand()%5];
}
else if(Sex=="Female")
{
Name=Names[rand()%(9-5)+5];
}
return Name;
}
Bunny()
{
Mutant=MutantBunny();
if(Mutant==true)
{
Sex=SexIsNotAChoise();
Color="Green";
Age=ImNotOld();
Name=HelloMyNameIs();
}
else if(Mutant==false)
{
Sex=SexIsNotAChoise();
Color=HopeImNotBlack();
Age=ImNotOld();
Name=HelloMyNameIs();
}
}
void print()
{
cout<<"Bunny "<<Name<<" was born!";
if(Mutant==true)
{
cout<<" He's a mutant..!"<<endl;
}
else
{
cout<<endl;
}
}
~Bunny()
{
cout<<"A bunny with the name "<<Name<<" has died!"<<endl;
}
};
class BunnyList
{
private:
int size;
public:
Bunny *Head;
BunnyList()
{
size=0;
Head=NULL;
}
int Count()
{
return size;
}
int AddBunny(Bunny* NewBunny)
{
if(Head==NULL)
{
Bunny *Temp=new Bunny;
Temp=NewBunny;
Temp->Next=Head;
Head=Temp;
return ++size;
}
else
{
Bunny *Current=new Bunny;
Current=Head;
while(Current->Next!=NULL)
{
Current=Current->Next;
}
Current->Next=NewBunny;
NewBunny->Next=NULL;
return ++size;
}
}
Bunny *GetBunny(int Pos)
{
Bunny *Current=Head;
for(int i=1;i<Pos && Current!=NULL;i++)
{
Current=Current->Next;
}
return Current;
}
bool Delete(int Pos)
{
if(GetBunny(Pos)==NULL)
{
return false;
}
else
{
if(Pos==1)
{
Bunny *Temp=Head->Next;
Head=Temp;
size--;
return true;
}
else
{
GetBunny(Pos-1)->Next=GetBunny(Pos+1);
size--;
}
return true;
}
}
int MutantCheck()
{
int MutantCount=0;
for(int i=1;i<Count() && GetBunny(i)!=NULL;i++)
{
if(GetBunny(i)->Mutant==true)
{
MutantCount++;
}
}
return MutantCount;
}
int Male()
{
int M=0;
for(int i=1;i<Count()+1 && GetBunny(i)!=NULL;i++)
{
if(GetBunny(i)->Sex=="Male" && GetBunny(i)->Age>2)
{
M++;
}
}
return M;
}
int Female()
{
int F=0;
for(int i=1;i<Count()+1 && GetBunny(i)!=NULL;i++)
{
if(GetBunny(i)->Sex=="Female" && GetBunny(i)->Age>2)
{
F++;
}
}
return F;
}
bool WeWillMate()
{
int M=Male(),F=Female();
if(M>=1 && F>=1)
{
return true;
}
else
{
return false;
}
}
void OutOfFood()
{
if(Count()>100)
{
int k=Count()/2;
for(int i=0;i<k;i++)
{
int z=rand()%k;
if(GetBunny(z)!=NULL)
{
GetBunny(z)->~Bunny();
Delete(z);
}
else
{
do{
z=rand()%k;
}
while(GetBunny(z)!=NULL);
GetBunny(z)->~Bunny();
Delete(z);
}
}
}
}
};
void PrintTheHorde(BunnyList* List)
{
cout<<"The Horde consists of "<<List->Count()<<" bunnies, here they are: "<<endl;
cout<<endl;
for(int i=1;i<List->Count()+1 && List->GetBunny(i)!=NULL;i++)
{
Bunny *Temp=List->GetBunny(i);
cout<<"Name: "<<Temp->Name<<" Sex: "<<Temp->Sex<<" Age: "<<Temp->Age<<" Color: "<<Temp->Color;
if((Temp->Mutant)==true)
{
cout<<" Im a Mutant.."<<endl;
}
else if((Temp->Mutant)==false)
{
cout<<endl;
}
}
}
int main()
{
srand(time(NULL));
BunnyList *List=new BunnyList;
for(int i=0;i<5;i++)
{
Bunny *NewBunny=new Bunny();
List->AddBunny(NewBunny);
NewBunny->print();
}
while(List->Count()>0)
{
for(int i=1;i<List->Count()+1 && List->GetBunny(i)!=NULL;i++)
{
Bunny *Temp=new Bunny;
Temp=List->GetBunny(i);
Temp->Age++;
if(Temp->Age>10)
{
Temp->~Bunny();
List->Delete(i);
}
}
bool C=List->WeWillMate();
if(C==true)
{
int k=List->Female();
for(int i=0;i<k;i++)
{
Bunny *NewBunny=new Bunny();
List->AddBunny(NewBunny);
NewBunny->print();
}
}
List->OutOfFood();
PrintTheHorde(List);
int m=List->Male(),f=List->Female();
cout<<"Adult males: "<<m<<endl;
cout<<"Adult females: "<<f<<endl;
cout<<"The Horde consists of "<<List->Count()<<" bunnies! "<<endl;
system("pause");
system("cls");
}
return getchar();
}
-
Re: A task involving linked lists and a headache
So, I did what you should be doing, stepping through your code using the debugger and ran into problems right away. The first big issue is AddBunny.
Code:
int AddBunny(Bunny* NewBunny)
{
if(Head==NULL)
{
Bunny *Temp=new Bunny;
Temp=NewBunny;
Temp->Next=Head;
Head=Temp;
return ++size;
}
You're passing in a Bunny*, but ignoring it and creating a new Bunny. You should just use the pointer you passed in. Also, you're setting next to head. That's a mistake too. Next in the last node should point to NULL.
From a design point of view, your list class should have a node class or struct that has the Bunny* as a member, and handles the next pointer. It's bad design to have the Bunny class contain the next pointer.
I would imagine there are lots more problems, but when writing code, you need to write small chunks, debug them and make sure they're working, then move on to the next piece. When you try to write it all at once, you end up with a huge mess. Get the list class properly designed, get the AddBunny function working properly, then move on and debug it piece by piece.
-
Re: A task involving linked lists and a headache
Thank you for your reply and advice :) Will tear this mess down peace by peace and learn to debug. I got the idea how to write the add function from a tutorial, guess it was wrong or i miss understood something and that propably means i might have some other mistakes..
-
Re: A task involving linked lists and a headache
Another thing, never under any circumstances call a destructor directly. Use delete and the destructor is called for you.
-
Re: A task involving linked lists and a headache
Quote:
Im having problems in managing the list itself.
Trying to figure out the steps needed to manage the head/tail/next/previous pointers for all the operations for a linked list can get a little mind boggling after a while.
My choice for solving problems like this is the draw the sequence of steps that are needed for each operation (Add, Delete, Insert), with lines showing where each pointer points to at each step. Otherwise it's easy to get yourself in a muddle.
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
MustSeeMelons
I got the idea how to write the add function from a tutorial,
That is the wrong approach. No tutorial, unless it is geared towards a definite aspect of an application, is going to write the program for you.
If you are to look at source code, then it should only be used to see how "programmer x" implemented a linked list. What "programmer x" did may not even look like or fit the requirements that you're looking for. What if that programmer implemented a template-based, STL-like linked list, complete with iterators, etc? Are you going to blindly copy the code or copy major portions of it? Of course not.
Googling or web searching for the exact code that fits what you're doing is a waste of time and energy, when that time could have been spent writing the program. It's better you learn what a linked list is, and based on that learning, create the program yourself.
You should have had a data structures textbook describing what a linked list is -- it's your job to then take the description of the linked list and create a program that manages a linked list.
Regards,
Paul McKenzie
-
Re: A task involving linked lists and a headache
@JohnW@Wessex
Thats what I am going to do, cant put everything together in my head.
@Paul McKenzie
Thanks for the post. I learned what a linked list is from tutorials, I went through 3 if i remmember corectly, but I didnt just plain copy the code, i tried to undesrstand and by what i learnt i made this mess. I know that copying gets you nowhere, i try to understand what and why i am writing something.
Reading just the description in not always enough, especially[did google check this word] if you dont have much experiance.
@GCDEF
Could you please explain this? I cant wrap my head around the idea..
"From a design point of view, your list class should have a node class or struct that has the Bunny* as a member, and handles the next pointer. It's bad design to have the Bunny class contain the next pointer."
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
MustSeeMelons
@GCDEF
Could you please explain this? I cant wrap my head around the idea..
"From a design point of view, your list class should have a node class or struct that has the Bunny* as a member, and handles the next pointer. It's bad design to have the Bunny class contain the next pointer."
You need another class or struct to make up the elements of your list. For example
Code:
struct BunnyListNode
{
BunnyListNode* pNext;
BunnyListNode* pPrev;// if you want doubly linked
Bunny* pBunny;
};
That way you've decoupled the concepts of your Bunny class and the container that holds them. When you call AddBunny, you'd create a new BunnyListNode and set pBunny to point to the Bunny that node is containing, and set the BunnyListNode pointers instead of having your Bunny class responsible for its position in the list.
-
Re: A task involving linked lists and a headache
What GCDEF is referring to is to have a struct:
Code:
struct Node
{
MyClass data;
Node *next; //points to next node in the list
};
You then will use these nodes in your linked list class.
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
Alterah
What GCDEF is referring to is to have a struct:
Code:
struct Node
{
MyClass data;
Node *next; //points to next node in the list
};
You then will use these nodes in your linked list class.
data would typically be a pointer to MyClass though.
-
Re: A task involving linked lists and a headache
Well ok, thanks, understood the idea. When i create a new bunny, i create a struct inside, that has the information about the bunnies location and its neighbours. The bunny itself now is just data and has nothing to do with the list itself.
Could you try explaining why my method was inferior? Unless my previous sentence is the reason.
-
Re: A task involving linked lists and a headache
I don't really understand your previous sentence. You create a struct inside what?
Whenever possible you should decouple classes as much as possible. There's no reason Bunny should know anything about the list, or any other container that may hold them. When you're working with Bunny objects, you shouldn't have to be concerned with whether they're members of a list, and if you change the implementation of your list, you shouldn't have to change your Bunny class to accommodate it. While it's not always possible, good design dictates that you reduce inter-dependencies among classes as much as possible.
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
GCDEF
data would typically be a pointer to MyClass though.
Is the reason to decrease the size of the nodes? Most examples don't have data as a pointer, but then again, most examples use primitives for the data.
-
Re: A task involving linked lists and a headache
It's so that the list can store the actual object, not a copy of it, and again, it decouples the class from its container. If the list contains an actual object, that that object only exists as long as the list node exists, and that's not necessarily desirable behavior.
-
Re: A task involving linked lists and a headache
Dont have much time, but i have done some changes, created another class that handles the bunnies in the list. The sad parts is that nothing has changed :| If i create 5 bunnies and then delete with a simple cycle (Bold), all is whel, they are deleted, but if i make a cycle with aging (Bold), 2 of them are still not deleted.. Whats wrong with the cycle?
Another, possibly dumb, question:
Code:
for(int i=1;i<List->Count()+1 && List->GetBunnyInList(i)!=NULL;i++)
When the cycle goes through, does it recalculate List->Count()?
Thanks!
Code:
class BunnyInList
{
public:
BunnyInList *Next;
Bunny *Cur;
};
class BunnyList
{
public:
BunnyInList *Head;
int size;
BunnyList()
{
Head=NULL;
size=0;
}
int Count()
{
return size;
}
int Add(Bunny* NewBunny)
{
BunnyInList *InList= new BunnyInList;
if(Head==NULL)
{
InList->Cur=NewBunny;
InList->Next=Head;
Head=InList;
return size++;
}
else
{
BunnyInList *Current=new BunnyInList;
Current=Head;
while(Current->Next!=NULL)
{
Current=Current->Next;
}
Current->Next=InList;
InList->Cur=NewBunny;
InList->Next=NULL;
return size++;
}
}
BunnyInList *GetBunnyInList(int Pos)
{
BunnyInList *Current=Head;
for(int i=1;i<Pos && Current!=NULL;i++)
{
Current=Current->Next;
}
return Current;
}
bool Delete(int Pos)
{
if(GetBunnyInList(Pos-1)==NULL)
{
Head=GetBunnyInList(Pos+1);
size--;
return true;
}
else if(GetBunnyInList(Pos+1)==NULL)
{
GetBunnyInList(Pos-1)->Next=NULL;
size--;
return true;
}
else
{
GetBunnyInList(Pos-1)->Next=GetBunnyInList(Pos+1)->Next;
size--;
return true;
}
return false;
}
int MutantCheck()
{
int MutantCount=0;
for(int i=1;i<Count() && GetBunnyInList(i)!=NULL;i++)
{
if(GetBunnyInList(i)->Cur->Mutant==true)
{
MutantCount++;
}
}
return MutantCount;
}
int Male()
{
int M=0;
for(int i=1;i<Count()+1 && GetBunnyInList(i)!=NULL;i++)
{
if(GetBunnyInList(i)->Cur->Sex=="Male" && GetBunnyInList(i)->Cur->Age>2)
{
M++;
}
}
return M;
}
int Female()
{
int F=0;
for(int i=1;i<Count()+1 && GetBunnyInList(i)!=NULL;i++)
{
if(GetBunnyInList(i)->Cur->Sex=="Female" && GetBunnyInList(i)->Cur->Age>2)
{
F++;
}
}
return F;
}
bool WeWillMate()
{
int M=Male(),F=Female();
if(M>=1 && F>=1)
{
return true;
}
else
{
return false;
}
}
};
Code:
srand(time(NULL));
BunnyList *List=new BunnyList;
for(int i=0;i<5;i++)
{
Bunny *NewBunny=new Bunny();
List->Add(NewBunny);
NewBunny->print();
}
PrintTheHorde(List);
for(int i=1;i<6;i++)
{
List->Delete(i);
}
while(List->Count()>0)
{
for(int i=1;i<List->Count()+1 && List->GetBunnyInList(i)!=NULL;i++)
{
BunnyInList *Temp=new BunnyInList;
Temp=List->GetBunnyInList(i);
if(Temp->Cur->Age>=10)
{
List->Delete(i);
}
Temp->Cur->Age++;
cout<<List->Count()<<endl;
}
-
Re: A task involving linked lists and a headache
I didn't try and compile and run your code, but a quick check still shows this problem that I mentioned previously.
Code:
if(Head==NULL)
{
InList->Cur=NewBunny;
InList->Next=Head; This is wrong
As to what's wrong with your loop, each time you delete a node, your list gets smaller. Your loop variable i doesn't account for that. You really shouldn't be forcing array constructs onto a list anyway.
Did you try debugging yet?
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
MustSeeMelons
Dont have much time, but i have done some changes, created another class that handles the bunnies in the list. The sad parts is that nothing has changed :| If i create 5 bunnies and then delete with a simple cycle (Bold), all is whel, they are deleted, but if i make a cycle with aging (Bold), 2 of them are still not deleted.. Whats wrong with the cycle?
If your goal is to delete all of the objects, then why not just keep deleting the head object until there are no objects in the list left to delete?
Code:
while (there are bunnies in my list)
{
delete the head bunny;
}
In other words, get rid of the for loop that uses "i". In any event, it's totally wrong anyway. If your list has 6 bunnies, and they are numbered 1,2,3,4,5, and 6, when you delete bunny "1", then bunny 2 now becomes bunny 1, bunny 3 becomes bunny 2, etc... Your for loop implies that when one is deleted, the other bunnies identifying number doesn't decrease. Your loop counter is going up, while the number of bunnies in the list is going down -- see anything wrong with that?
This is wrong not only in the way you wrote the loop, but the way you implemented the interface to the linked list. You're not supposed to index a linked list like an array, in other words, there is no Bunny[1], Bunny[2], etc.. You can only "point to" or get to a certain item in the list by traversing the list and finding the bunny that you want. So right there, you are not using a linked list in your assignment as a linked list. What you did was write a linked list, and reality using it as if it's an array.
Secondly, even if you were to use indexing into the list as if it's an array, you're mixing up zero-based and 1-based indexing. Why does Delete use 1 based indexing , but GetBunnyInList uses 0-based indexing? Look at your code -- when you call GetBunnyInList, you immediately subtract 1? The user of your linked list doesn't know whether bunnies start at 0 or 1, given the inconsistency of the implementation. Not only that, your internal code gets confusing with the "Pos-1", "Pos+1", etc. You're practically begging for a memory overwrite or some sort of memory corruption to occur with that type of coding. Be consistent and start at 0, where every C++ programmer expects a container to start indexing.
Your Add() function is confusing. You're allocating twice for no reason.
Code:
int Add(Bunny* NewBunny)
{
// create a bunny
BunnyInList *InList= new BunnyInList;
InList->Next = NULL;
if (Head == NULL)
{
// this is the head bunny
Head = InList;
return ++size;
}
// there are bunnies already existing, so add this
// new one to the end of the list
BunnyInList* Current=Head;
while(Current->Next)
Current=Current->Next;
Current->Next=InList;
return ++size;
}
This is much simpler. If the list is empty, then the new item becomes the head, else you traverse the list and add the new item at the end.
Regards,
Paul McKenzie
-
Re: A task involving linked lists and a headache
Code:
if(Head==NULL)
{
InList->Cur=NewBunny;
InList->Next=Head; This is wrong
Head is still NULL at that point, why is it wrong? Should i just use InList=NULL then?
I tried debugging - it was overwhelming and hard to understand, still searsching for a good debugging tutorial.
My goal is to make a function, which deletes bunnies when they hit age 10. I was afraid that the list was getting smaller when deleting, thanks for making that clear. Understood, start always with 0, i had some sort of reason why i wrote 1, ill fix that.
Ok, now i have to ask this, how should i treat i linked list? Use a counter in loops and go through elements by using Next? The reason im trying to use the list like an array is probably because im used to solid structures, the list seems like it could be scattered all over the memory.
Is there something wrong with using Pos-1 & Pos +1?
Thank you wery much.
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
MustSeeMelons
Code:
if(Head==NULL)
{
InList->Cur=NewBunny;
InList->Next=Head; This is wrong
Head is still NULL at that point, why is it wrong? Should i just use InList=NULL then?
Just use the implementation of Add() that I had. Your version of Add() complicates everything by making two allocations when one is all that's required.
Quote:
I tried debugging - it was overwhelming and hard to understand, still searsching for a good debugging tutorial.
This is what happens when you copy code from somewhere, and you don't fully understand the code yourself.
If you wrote the program from scratch, then debugging the program becomes easy because you wrote the program, so you must have had something in mind when you wrote it. In other words, you had a plan, you had this plan written out on paper, and now you implemented it. So now the program doesn't work -- where does the program deviate from the plan you had written down? Then this becomes straightforward as to how to proceed from there.
Quote:
The reason im trying to use the list like an array is probably because im used to solid structures, the list seems like it could be scattered all over the memory.
That's right, and for good reason why the memory is "scattered". When you remove an item from a linked list, all you're doing is manipulating a couple of pointers. If it were a (dynamic) array, you have to remove the item, and then "squeeze" all of the items together in the array to cover up the hole that is created with the item that has been removed. That takes more time to execute.
Assume you had a linked list of 10,000 items, and you want to delete the 5,000th entry in the list. You have a pointer to the 5,000th entry, so all you need to do is manipulate the pointers to entry 4,999 and 5,001 to remove entry 5000 (and then of course you deallocate the memory for entry 5000). For an array, to delete entry 5,000 requires you to move all the entries starting from 5,001 to cover up the hole created when 5,000 is removed, one by one. That takes way more time, and especially if the entries are expensive to copy.
In other words, the links in a linked list can be anywhere in memory -- the aspect that keeps them in order is that "Next" pointer link (hence the term "linked list"). For an array, the items must be consecutive in memory. It is the consecutiveness of an array that keeps an array in order (you know where any item is in an array, since each item must follow the previous or next item in memory). Therefore a link in a linked list can be easily removed, since it just needs a couple of pointer updates to remove the item from the list -- it doesn't matter where the link is in memory, as long as the Next pointer is doing the right thing. For an array, to keep the items consecutive, you have to fill the hole created when you removed an item, and that requires copying all elements after the removed item "up by 1".
Quote:
Is there something wrong with using Pos-1 & Pos +1?
There is nothing "wrong", it's just confusing and makes the code harder to maintain. If you had stuck to 0-based indexing, then things become easier.
Regards,
Paul McKenzie
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
MustSeeMelons
Code:
if(Head==NULL)
{
InList->Cur=NewBunny;
InList->Next=Head; This is wrong
Head is still NULL at that point, why is it wrong? Should i just use InList=NULL then?
I tried debugging - it was overwhelming and hard to understand, still searsching for a good debugging tutorial.
My goal is to make a function, which deletes bunnies when they hit age 10. I was afraid that the list was getting smaller when deleting, thanks for making that clear. Understood, start always with 0, i had some sort of reason why i wrote 1, ill fix that.
Ok, now i have to ask this, how should i treat i linked list? Use a counter in loops and go through elements by using Next? The reason im trying to use the list like an array is probably because im used to solid structures, the list seems like it could be scattered all over the memory.
Is there something wrong with using Pos-1 & Pos +1?
Thank you wery much.
You're right, but as you can see from my mistake, setting next = head and assuming head == NULL makes the code harder to read. If you want it to be NULL, set it to NULL.
Typically you'll iterate a list using a while loop, checking to see if the current node's next pointer != NULL, although some implementations allow for a for loop also.
-
Re: A task involving linked lists and a headache
Im happy to inform, that this is a happy post - i corrected my mess and everything is working as it should^^ (Maybe there is a small glitch somewhere, but i havent found it yet). Went through my code and found two really dumb mistakes: GetBunnyInList couldnt return a NULL, so changes were made. And the worst mistake, when deleting a node in the middle i had written that the previous nodes next is the next nodes next, that caused all the deletion problems, dont know what i was thinking when i wrote that line..
Want to thank GCDEF and esspecially Paul McKenzie for there great posts ;)
I still have some work to do, like add some more features like:
★ Modify the program to run in real time, with each turn lasting 2 seconds, and a one second pause between each announement.
★★ Allow the user to hit the 'k' key to initiate a mass rabit cull! which causes half of all the rabits to be killed (randomly chosen).
★★★★ Modify the program to place the rabits in an 80x80 grid. Have the rabits move one space each turn randomly.
Mark juvenile males with m, adult males w/ M,
juvenile females w/ f, adult femails w/ F
radioactive mutant vampire bunnies with X
Modify the program so that radioactive mutant vampire bunnies only convert bunnies that end a turn on an adjacent square.
Modify the program so that new babies are born in an empty random adjacent square next to the mother bunny. (if no empty square exits then the baby bunny isn't born)
★★★★★ Modify the program so that it saves each turn to a file and can play back at accelearted speed all subsequent turns.
If ill have any more headackes or finish the program with no problems, ill definetly post here.
Thanks yet again and heres the code, which works.
Code:
#include <iostream>
#include <time.h>
#include <string>
using namespace std;
char *Names[15]={"Phill","Colin","Bucket","Fluffy","Mister","Lilly","Rose","Shamandale","Yoshie","Jane","PeanutButter","Plank","Sucubus","Broken","Horse ****"};
class Bunny
{
public:
string Sex;
string Color;
int Age;
string Name;
bool Mutant;
Bunny *Next;
int Random(int x)
{
return x=rand()%(x+1);
}
bool MutantBunny()
{
int X=Random(100);
if(X<1)
{
return true;
}
return false;
}
string SexIsNotAChoise()
{
int R=Random(10);
if(R<5)
{
Sex="Male";
}
else
{
Sex="Female";
}
return Sex;
}
string HopeImNotBlack()
{
int R=Random(100);
if(R<24)
{
Color="White";
}
else if(R>24 && R<=49)
{
Color="Brown";
}
else if(R>50 && R<=75)
{
Color="Black";
}
else if(R>76)
{
Color="Spotted";
}
return Color;
}
int ImNotOld()
{
Age=0;
return Age;
}
string HelloMyNameIs()
{
if(Mutant==true)
{
Name=Names[rand()%(14-10)+10];
}
else if(Sex=="Male")
{
Name=Names[rand()%5];
}
else if(Sex=="Female")
{
Name=Names[rand()%(9-5)+5];
}
return Name;
}
Bunny()
{
Mutant=MutantBunny();
if(Mutant==true)
{
Sex=SexIsNotAChoise();
Color="Green";
Age=ImNotOld();
Name=HelloMyNameIs();
}
else if(Mutant==false)
{
Sex=SexIsNotAChoise();
Color=HopeImNotBlack();
Age=ImNotOld();
Name=HelloMyNameIs();
}
}
void print()
{
cout<<"Bunny "<<Name<<" was born!";
if(Mutant==true)
{
cout<<" He's a mutant..!"<<endl;
}
else
{
cout<<endl;
}
}
~Bunny()
{
cout<<"A bunny with the name "<<Name<<" has died!"<<endl;
}
};
class BunnyInList
{
public:
BunnyInList *Next;
Bunny *Cur;
};
class BunnyList
{
public:
BunnyInList *Head;
int size;
int BunnyCount;
BunnyList()
{
Head=NULL;
size=0;
BunnyCount=0;
}
int Count()
{
return size;
}
int Add(Bunny* NewBunny)
{
BunnyInList *InList= new BunnyInList;
InList->Next=NULL;
if(Head==NULL)
{
InList->Cur=NewBunny;
Head=InList;
BunnyCount++;
return ++size;
}
else
{
BunnyInList *Current=Head;
while(Current->Next!=NULL)
{
Current=Current->Next;
}
Current->Next=InList;
InList->Cur=NewBunny;
BunnyCount++;
return ++size;
}
}
BunnyInList *GetBunnyInList(int Pos)
{
BunnyInList *Current=Head;
if(Pos>=0)
{
for(int i=0;i<Pos && Current!=NULL;i++)
{
Current=Current->Next;
}
return Current;
}
else
{
return Current=NULL;
}
}
bool Delete(int Pos)
{
if(GetBunnyInList(Pos-1)==NULL)
{
Head=GetBunnyInList(Pos+1);
size--;
return true;
}
else if(GetBunnyInList(Pos+1)==NULL)
{
GetBunnyInList(Pos-1)->Next=NULL;
size--;
return true;
}
else
{
GetBunnyInList(Pos-1)->Next=GetBunnyInList(Pos+1);
size--;
return true;
}
return false;
}
int MutantCheck()
{
int MutantCount=0;
for(int i=0;i<Count() && GetBunnyInList(i)!=NULL;i++)
{
if(GetBunnyInList(i)->Cur->Mutant==true)
{
MutantCount++;
}
}
return MutantCount;
}
int NormalCheck()
{
int NormalCount=0;
for(int i=0;i<Count() && GetBunnyInList(i)!=NULL;i++)
{
if(GetBunnyInList(i)->Cur->Mutant==false)
{
NormalCount++;
}
}
return NormalCount;
}
int Male()
{
int M=0;
for(int i=0;i<Count() && GetBunnyInList(i)!=NULL;i++)
{
if(GetBunnyInList(i)->Cur->Sex=="Male" && GetBunnyInList(i)->Cur->Age>2 && GetBunnyInList(i)->Cur->Mutant==false)
{
M++;
}
}
return M;
}
int Female()
{
int F=0;
for(int i=0;i<Count() && GetBunnyInList(i)!=NULL;i++)
{
if(GetBunnyInList(i)->Cur->Sex=="Female" && GetBunnyInList(i)->Cur->Age>2 && GetBunnyInList(i)->Cur->Mutant==false)
{
F++;
}
}
return F;
}
bool WeWillMate()
{
int M=Male(),F=Female();
if(M>=1 && F>=1)
{
return true;
}
else
{
return false;
}
}
void OutOfFood()
{
if(Count()>1000)
{
int ToKill=Count()/2;
while(ToKill!=0)
{
int UnLucky=rand()%(Count());
BunnyInList *Temp=GetBunnyInList(UnLucky);
Delete(UnLucky);
delete Temp->Cur;
ToKill--;
}
}
}
void Conversion()
{
int Change=MutantCheck();
int Normal=NormalCheck();
if(Change>0 && Normal>0)
{
while(Change!=0)
{
int UnLucky=rand()%(Count());
BunnyInList *Temp=GetBunnyInList(UnLucky);
while(GetBunnyInList(UnLucky)->Cur->Mutant!=false)
{
UnLucky=rand()%(Count());
}
Temp=GetBunnyInList(UnLucky);
Temp->Cur->Mutant=true;
Temp->Cur->Color="Green";
cout<<Temp->Cur->Name<<" is a mutant now!"<<endl;
Change--;
Normal--;
if(Normal==0)
{
break;
}
}
}
}
};
void PrintTheHorde(BunnyList* List)
{
cout<<"The Horde consists of "<<List->Count()<<" bunnies, here they are: "<<endl;
cout<<endl;
for(int i=0;i<List->Count() && List->GetBunnyInList(i)!=NULL;i++)
{
BunnyInList *Temp=List->GetBunnyInList(i);
cout<<"Name: "<<Temp->Cur->Name<<" Sex: "<<Temp->Cur->Sex<<" Age: "<<Temp->Cur->Age<<" Color: "<<Temp->Cur->Color;
if((Temp->Cur->Mutant)==true)
{
cout<<" Im a Mutant.."<<endl;
}
else if((Temp->Cur->Mutant)==false)
{
cout<<endl;
}
}
}
int main()
{
srand(time(NULL));
BunnyList *List=new BunnyList;
for(int i=0;i<5;i++)
{
Bunny *NewBunny=new Bunny();
List->Add(NewBunny);
NewBunny->print();
}
while(List->Count()>0)
{
int i=0;
BunnyInList *Temp=List->Head;
while(Temp!=NULL)
{
Temp->Cur->Age++;
if(Temp->Cur->Mutant==true)
{
if(Temp->Cur->Age==50)
{
List->Delete(i);
delete Temp->Cur;
i--;
}
}
else if(Temp->Cur->Mutant==false)
{
if(Temp->Cur->Age==10)
{
List->Delete(i);
delete Temp->Cur;
i--;
}
}
Temp=Temp->Next;
i++;
}
bool Mate=List->WeWillMate();
if(Mate==true)
{
int NewB=List->Female();
for(int i=0;i<NewB;i++)
{
Bunny *NewBunny=new Bunny();
List->Add(NewBunny);
NewBunny->print();
}
}
List->Conversion();
List->OutOfFood();
int m=List->Male(),f=List->Female();
cout<<"Adult males: "<<m<<endl;
cout<<"Adult females: "<<f<<endl;
cout<<"The Horde consists of "<<List->Count()<<" bunnies! "<<endl;
//system("pause");
//system("cls");
/*system("pause");
system("cls");*/
}
cout<<endl;
cout<<"A total of "<<List->BunnyCount<<" bunnies lived in this farm.."<<endl;
return getchar();
}
-
Re: A task involving linked lists and a headache
Code:
string HopeImNotBlack()
{
int R=Random(100);
if(R<24)
{
Color="White";
}
else if(R>24 && R<=49)
{
Color="Brown";
}
else if(R>50 && R<=75)
{
Color="Black";
}
else if(R>76)
{
Color="Spotted";
}
return Color;
}
This must be a first - I've never seen a racist method name before :eek:
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
Peter_B
This must be a first - I've never seen a racist method name before :eek:
Well thank you. Im not racist, but i do like to make my method names a bit more interesting, otherwise its just too plain and booring, without any character. Spices thing up.
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
MustSeeMelons
Well thank you. Im not racist, but i do like to make my method names a bit more interesting, otherwise its just too plain and booring, without any character. Spices thing up.
I didn't say you were racist, I said the method name was :)
But seriously, you should consider how the person marking this assignment might see this. They won't be looking for 'interesting' method names, but would prefer that they are clear and descriptive of what the method does.
The place to spice things up is in the user interface, not the code.
-
Re: A task involving linked lists and a headache
You have a number of issues with your code that could be improved.
You need to get the next pointer out of your Bunny Class.
Your use of Random makes little sense. You're doing weird things like saying Random(10) to determine sex, when it seems like Random(2) would make more sense. Same with color.
You'd be better off storing attributes as ordinal values rather than string literals. Then you could do things like
sex = Random(2);
without all those if statements. If you use enums or const ints rather than string literals, the compiler will catch it if you make a spelling mistake, whereas it won't with string literals.
What's the difference between size and BunnyCount in your list?
Why are you writing things like
Name=Names[rand()%(14-10)+10
Why not just write 4 if you mean 4?
If you maintained a pointer to the tail of your list, you wouldn't have to iterate the list every time you add a bunny.
There are other issues but if you're so inclined, you could start with them.
-
Re: A task involving linked lists and a headache
Um, the Bunny doesnt have the next pointer, BunnyInList does, the Bunny it self has no idea that its in a class.
As for the Random function, well, youre right, dont know how i didnt think of that before, thanks.
The BunnyCount is just a ticker on how many bunnies have lived in total, its not decremented, as for now, 2547 is the biggest farm ive had :D
Why are you writing things like
Name=Names[rand()%(14-10)+10
Why not just write 4 if you mean 4?
Because the Names array contains all gender & mutant names, so i need a random number between 10 and 14 for specific names, i might just make 3 different arrays if ill want to add more names.
The code runs great, so for now ill keep it as it is and will take your advice the next time ill be making something simiral.
Noone is marking this, its just for myself, the code is just for me. I would like the code to be a bit spiced, so that i can think odd things about people based on there code :D
A question about programming itself, ill be graduating next year and i am willing to learn usefull programming related stuff at home. For now im doing C++ and JAVA, what else could be usefull? To try to land a job or practise position?
Last question, related to the real-time program execution.
"Modify the program to run in real time, with each turn lasting 2 seconds, and a one second pause between each announement."
How to understand the bolded part? I have to restrict the time given for the turn or make a pause? Ive made a function which takes care of the pause.
Code:
void TimePause(int MiliS)
{
int Time=clock();
while(Time+MiliS!=clock());
}
-
Re: A task involving linked lists and a headache
Look at your Bunny class again. The most recent one still has a next*.
Still, why write (14 - 10) instead of just 4?
-
Re: A task involving linked lists and a headache
Quote:
Noone is marking this, its just for myself, the code is just for me.
So why didn't you just use the std::list class?
Quote:
The code runs great, so for now ill keep it as it is
The issue is not that it "runs great" (and that isn't even conclusive). The issue is that you don't want to write code in the way you wrote it. It is not the way a junior or senior professional programmer would write the code. For example, your BunnyList lacks a proper copy constructor and assignment operator. I can crash or totally make your class useless with just a 2 or 3 line main() program. Another example is that you don't check what happens if the color is exactly 24.
Another example is this:
Code:
GetBunny(z)->~Bunny();
This is not how you use destructors. By doing this, your object is erroneously destroyed twice, once with that ill-advised line above, and another when the object goes out of scope.
Honestly, don't keep this program. It has bugs, bad coding, etc.
Quote:
A question about programming itself, ill be graduating next year and i am willing to learn usefull programming related stuff at home.
Learn how to use the C++ library. There already is a std::list class that you could/should have used. Unless you know how to use the standard library, you really can't call yourself a C++ programmer to any great extent.
Regards,
Paul McKenzie
-
Re: A task involving linked lists and a headache
Here is an example of usage of the standard library. Note how many of your functions have been eliminated, replaced with library functions.
Code:
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <time.h>
using namespace std;
const char *Names[]={"Phill","Colin","Bucket","Fluffy","Mister","Lilly","Rose","Shamandale","Yoshie","Jane","PeanutButter","Plank","Sucubus","Broken","Horse ****"};
class Bunny
{
string Gender;
string Color;
int Age;
string Name;
bool Mutant;
public:
std::string GetName() const { return Name; }
std::string GetColor() const { return Color; }
int GetAge() const { return Age; }
void SetAge(int theAge) { Age = theAge; }
std::string GetGender() const { return Gender; }
bool IsMutant() const { return Mutant; }
bool IsMale() const { return Gender == "Male" && Age > 2; }
bool IsFemale() const { return Gender == "Female" && Age > 2; }
bool IsOlderInAge(int testAge) const { return Age > testAge; }
bool IsYoungerInAge(int testAge) const { return Age < testAge; }
bool IsEqualInAge(int testAge) const { return Age == testAge; }
int Random(int x)
{ return x=rand()%(x+1); }
bool MutantBunny()
{
int X=Random(100);
return X < 2;
}
string SetGender()
{
int R=Random(10);
Gender = (R<5?"Male":"Female");
return Gender;
}
string SetColor()
{
int R=Random(100);
if(R<24)
Color="White";
else if(R>24 && R<=49)
Color="Brown";
else if(R>50 && R<=75)
Color="Black";
else if(R>76)
Color="Spotted";
return Color;
}
int ResetAge()
{
Age=0;
return Age;
}
std::string SetName()
{
if(Mutant)
{
Name=Names[rand()%(14-10)+10];
}
else if(Gender=="Male")
{
Name=Names[rand()%5];
}
else if(Gender=="Female")
{
Name=Names[rand()%(9-5)+5];
}
return Name;
}
Bunny()
{
Mutant=MutantBunny();
if(Mutant)
{
Gender=SetGender();
Color="Green";
Age=ResetAge();
Name=SetName();
}
else
{
Gender=SetGender();
Color=SetColor();
Age=ResetAge();
Name=SetName();
}
}
void print()
{
std::cout<<"Bunny "<<Name<<" was born!";
if (Mutant)
{
cout<<" He's a mutant..!"<<endl;
}
else
{
cout<<endl;
}
}
~Bunny()
{
cout<<"A bunny with the name "<<Name<<" has died!"<<endl;
}
};
class BunnyList
{
typedef std::list<Bunny> BunnyLinkedList;
private:
BunnyLinkedList m_theBunnyList;
public:
typedef enum {AGE_EQUAL, AGE_YOUNGER, AGE_OLDER } AgeType;
int Count()
{ return (int)m_theBunnyList.size(); }
void AddBunny(const Bunny& NewBunny)
{ m_theBunnyList.push_back(NewBunny); }
const Bunny& GetBunny(int Pos) const
{
if ( Pos >= 0 && Pos < (int)m_theBunnyList.size())
{
BunnyLinkedList::const_iterator it = m_theBunnyList.begin();
std::advance(it, Pos);
return *it;
}
throw std::out_of_range("Bunny position invalid");
}
bool Delete(int Pos)
{
if ( Pos >= 0 && Pos < (int)m_theBunnyList.size())
{
BunnyLinkedList::const_iterator it = m_theBunnyList.begin();
std::advance(it, Pos);
m_theBunnyList.erase(it);
return true;
}
return false;
}
int GetNumMutants()
{ return (int)std::count_if(m_theBunnyList.begin(), m_theBunnyList.end(), std::mem_fun_ref(&Bunny::IsMutant)); }
int GetNumMale()
{ return (int)std::count_if(m_theBunnyList.begin(), m_theBunnyList.end(), std::mem_fun_ref(&Bunny::IsMale)); }
int GetNumFemale()
{ return (int)std::count_if(m_theBunnyList.begin(), m_theBunnyList.end(), std::mem_fun_ref(&Bunny::IsFemale)); }
bool WeWillMate()
{
int M=GetNumMale();
int F=GetNumFemale();
return (M>=1 && F>=1);
}
void OutOfFood()
{
if(Count()>100)
{
int k=Count()/2;
for(int i=0;i<k;i++)
{
int z=rand()%k;
Delete(z);
}
}
}
void PrintAllBunnies() const
{
cout<<"The Horde consists of " << m_theBunnyList.size() <<" bunnies, here they are: "<<endl;
cout<<endl;
BunnyLinkedList::const_iterator it = m_theBunnyList.begin();
while (it != m_theBunnyList.end())
{
const Bunny& Temp = *it;
cout<<"Name: "<<Temp.GetName() <<" Sex: "<<Temp.GetGender() <<" Age: "<<Temp.GetAge() <<" Color: "<<Temp.GetColor();
if (Temp.IsMutant())
cout<<" Im a Mutant.."<<endl;
else
cout<<endl;
++it;
}
}
void DeleteByAge(int age, AgeType aType = AGE_EQUAL)
{
switch (aType)
{
case AGE_EQUAL:
m_theBunnyList.remove_if(std::bind2nd(std::mem_fun_ref(&Bunny::IsEqualInAge), age));
break;
case AGE_YOUNGER:
m_theBunnyList.remove_if(std::bind2nd(std::mem_fun_ref(&Bunny::IsYoungerInAge), age));
break;
case AGE_OLDER:
m_theBunnyList.remove_if(std::bind2nd(std::mem_fun_ref(&Bunny::IsOlderInAge), age));
break;
}
}
};
int main()
{
srand(time(NULL));
BunnyList List;
for(int i=0;i<5;i++)
{
Bunny theBunny;
List.AddBunny(theBunny);
theBunny.print();
}
// remove all bunnies with age 10
List.DeleteByAge( 10 );
List.PrintAllBunnies();
return getchar();
}
To be honest, this isn't even my best attempt. I didn't address the random number issues that GCDEF mentioned, but at the very least, you can start to look at this code and understand how it does what it does.
Regards,
Paul McKenzie
-
Re: A task involving linked lists and a headache
Quote:
Look at your Bunny class again. The most recent one still has a next*.
Still, why write (14 - 10) instead of just 4?
Forgot to delete that pointer for the bunny, anyway, it wasnt used.
Because, rand()%4 would give me 0-4, but those positions contain Male names, i need rand()%(14 - 10)+10 gives me 10-14, which are the names i need.
Quote:
So why didn't you just use the std::list class?
I had C++ just for 1 semester, one in two weeks, we didnt have classes what so ever, mostly just OOP principles etc.,
So I took the hard road. The upside is that i feel that i have learned something.
Quote:
Learn how to use the C++ library. There already is a std::list class that you could/should have used. Unless you know how to use the standard library, you really can't call yourself a C++ programmer to any great extent.
Im not saying i am, i am willing to be. Ok then, will look in to your code and start learning STL.I got 8 months to make myself usefull, wish me luck :D
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by MustSeeMelons
rand()%4 would give me 0-4
Actually, it will give you integers in the range [0, 3].
-
Re: A task involving linked lists and a headache
-
Re: A task involving linked lists and a headache
Quote:
Originally Posted by
MustSeeMelons
Forgot to delete that pointer for the bunny, anyway, it wasnt used.
Because, rand()%4 would give me 0-4, but those positions contain Male names, i need rand()%(14 - 10)+10 gives me 10-14, which are the names i need.
Good grief.
rand() % 4 + 10.
The (14 - 10) just evaluates to 4. Why not just write 4? Why not (107 - 103)? Keep it as simple as possible.