Go Down

Topic: Issue with loops (Read 255 times) previous topic - next topic

awoodbridge

I have an array of monsters, I'm attempting to append a number if they are a duplicate. In the code below, I would have Fire Wolf 1, Fire Wolf 2, but not Fire Sprite would be left alone since there is only one.

I have tested it, and the parts of it work but not the whole. I think I'm missing something stupid, thanks for the help.

Code: [Select]
#include "Monster.h"
//Monster(char* mName,bool inCombat, int initRoll,int hp, int initMod)
//.roll() updates initRoll with D20+initMod
//.engage() move to combat
//.kill() remove from combat


//----------------------------------------------------------------------------------------------
//Variables

const int TOME_LENGTH = 12;     //the length of the master tome of players and monsters


Monster tome[TOME_LENGTH] = {
  {"Thio Ki",1,25,4, false, "PC Human Wizard"},   
  {"Zenwan",1,27,2, false, "PC Halfling Rogue"},
  {"Balkas",1,33,4, false, "PC Elf Monk"},
  {"Fire Wolf",1,7,2, true, "AC=13 Flame Bite Melee +4 2d4+1 one fire"},   
  {"Fire Wolf",1,7,2, true, "AC=13 Flame Bite Melee +4 2d4+1 one fire"},   
  {"Fire Sprite",1,7,0, true, "AC=9 Melee Bite +4 2d4 one fire"}, 
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},   
  {"Aiden",1,14,1, true, "AC=13 Spell Caster Melee +3 1d4"}
};


void setup() {
  Serial.begin(9600);
  Serial.println("Hello");
  multiMonster();
  for(byte i = 0; i < TOME_LENGTH; i++){
    Serial.println(tome[i].mName);
  }
}

void loop() {

}

//-------------------------------------------------------------------

void multiMonster(){
  for(byte active = 0; active < TOME_LENGTH; active++){
     byte monsterMatch[TOME_LENGTH];                                              //make a place to hold the matching indexes
     monsterMatch[0] = active;                                                    //add the current monster to monsterMatch
     byte matchCounter = 1;                                                       //set the counter to one, this should increment everytime there is another matching name found 
     for(byte compare = 0; compare < TOME_LENGTH; compare ++){
      if(tome[active].mName == tome[compare].mName && active != compare){         //if the mName of the active monster matched the one we're comparing it to and they are not the same monster
        monsterMatch[matchCounter] = compare;                                     //add their index to the monsterMatch array
        matchCounter ++;                                                          //increment the matchCounter for the next monster (if needed)
      }
     }
    if (matchCounter > 1){                                                        //if a second monster was added to the list
      for(byte m = 0; m < matchCounter; m ++){                                    //append 1 to the first monster, 2 to the second monster, 3 to the third monster)
        char monsterBuffer[3];
        sprintf (monsterBuffer, ' %d', m);
        tome[monsterMatch[m]].mName = strcat(tome[monsterMatch[m]].mName, monsterBuffer);
        }
    }
  }
}

PaulS

Quote
if(tome[active].mName == tome[compare].mName
What type is the mName field? If it is char * or char array, that is NOT how you compare strings.

Code: [Select]
        sprintf (monsterBuffer, ' %d', m);
Single quotes are for SINGLE characters. Double quotes are for strings.

Since m can conceivably be as high as 12, your monstoerBuffer is too small. 2 digits plus a space plus a terminating NULL is NOT going to fit in a 3 element array.
The art of getting good answers lies in asking good questions.

awoodbridge

mName is char* I will do some research on comparing strings.

Here is the code with your suggested updates:
Code: [Select]
#include "Monster.h"
//Monster(char* mName,bool inCombat, int initRoll,int hp, int initMod)
//.roll() updates initRoll with D20+initMod
//.engage() move to combat
//.kill() remove from combat


//----------------------------------------------------------------------------------------------
//Variables

const int TOME_LENGTH = 12;     //the length of the master tome of players and monsters


Monster tome[TOME_LENGTH] = {
  {"Thio Ki",1,25,4, false, "PC Human Wizard"},   
  {"Zenwan",1,27,2, false, "PC Halfling Rogue"},
  {"Balkas",1,33,4, false, "PC Elf Monk"},
  {"Fire Wolf",1,7,2, true, "AC=13 Flame Bite Melee +4 2d4+1 one fire"},   
  {"Fire Wolf",1,7,2, true, "AC=13 Flame Bite Melee +4 2d4+1 one fire"},   
  {"Fire Sprite",1,7,0, true, "AC=9 Melee Bite +4 2d4 one fire"}, 
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},   
  {"Aiden",1,14,1, true, "AC=13 Spell Caster Melee +3 1d4"}
};


void setup() {
  Serial.begin(9600);
  Serial.println("Hello");
  multiMonster();
  for(byte i = 0; i < TOME_LENGTH; i++){
    Serial.println(tome[i].mName);
  }
}

void loop() {

}

//-------------------------------------------------------------------

void multiMonster(){
  for(byte active = 0; active < TOME_LENGTH; active++){
     byte monsterMatch[TOME_LENGTH];                                              //make a place to hold the matching indexes
     monsterMatch[0] = active;                                                    //add the current monster to monsterMatch
     byte matchCounter = 1;                                                       //set the counter to one, this should increment everytime there is another matching name found 
     for(byte compare = 0; compare < TOME_LENGTH; compare ++){
      if(tome[active].mName == tome[compare].mName && active != compare){         //if the mName of the active monster matched the one we're comparing it to and they are not the same monster
        monsterMatch[matchCounter] = compare;                                     //add their index to the monsterMatch array
        matchCounter ++;                                                          //increment the matchCounter for the next monster (if needed)
      }
     }
    if (matchCounter > 1){                                                        //if a second monster was added to the list
      for(byte m = 0; m < matchCounter; m ++){                                    //append 1 to the first monster, 2 to the second monster, 3 to the third monster)
        char monsterBuffer[4];
        sprintf (monsterBuffer, " %d", m);
        tome[monsterMatch[m]].mName = strcat(tome[monsterMatch[m]].mName, monsterBuffer);
        }
    }
  }
}

wildbill

If mName is char* this is going to be a problem:
Code: [Select]

        tome[monsterMatch[m]].mName = strcat(tome[monsterMatch[m]].mName, monsterBuffer);


Firstly, all you need is :
Code: [Select]

        strcat(tome[monsterMatch[m]].mName, monsterBuffer);

But even then, you will write on memory you don't own. Make mName a char array with sufficient space instead.

It would be helpful if you posted the contents of monster.h.

So far, I can't see why you're using an Arduino for this. Easier to debug on the machine you're using to program the Arduino even if you do need I/O later.

awoodbridge

#4
Apr 16, 2018, 05:34 pm Last Edit: Apr 16, 2018, 05:37 pm by awoodbridge
So far, I can't see why you're using an Arduino for this. Easier to debug on the machine you're using to program the Arduino even if you do need I/O later.
The rest of my code works fine, this is just a feature I'm trying to add in with this small subset. I'm pretty new at this and hopping between Dev envrionments is a bit beyond me.

Here is the code for Monster.h:
Code: [Select]
#ifndef Monster_H
#define Monster_H

#include <Arduino.h>

class Monster{

public:
char* mName;
bool inCombat;
byte initRoll;
byte currhp;

int hp;
byte initMod;
bool npc;
char* details;


Monster(char* n, byte r,byte h, int i, bool p, char* d);
void roll();
void engage();
void kill();
void takeHit(int howHard);



};

#endif




My code runs and does the comparison and appending correctly, I'm just getting too many numbers. Here is the result of execution:
Code: [Select]
Hello
Thio Ki
Zenwan
Balkas
Fire Wolf 0 1 0 1
Fire Wolf 0 1 0 1
Fire Sprite
Son of Ignis 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
Son of Ignis 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
Son of Ignis 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
Son of Ignis 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
Son of Ignis 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
1 2 3 4 0 1 2 3 4

wildbill

Quote
My code runs and does the comparison and appending correctly
Until you fix all of the problems PaulS identified for you and make mName a char array (maybe 16 bytes?), I don't think that's a true statement.

awoodbridge

As suggested, I changed mName  to char mName[20], here is my code now:

Code: [Select]
#include <CircularBuffer.h>
#include "Monster.h"

//Monster(char mName[20] ,bool inCombat, int initRoll,int hp, int initMod)
//.roll() updates initRoll with D20+initMod
//.engage() move to combat
//.kill() remove from combat

 

 

//----------------------------------------------------------------------------------------------

//Variables
const int TOME_LENGTH = 12;     //the length of the master tome of players and monsters

Monster tome[TOME_LENGTH] = {

  {"Thio Ki",1,25,4, false, "PC Human Wizard"}, 
  {"Zenwan",1,27,2, false, "PC Halfling Rogue"},
  {"Balkas",1,33,4, false, "PC Elf Monk"},
  {"Fire Wolf",1,7,2, true, "AC=13 Flame Bite Melee +4 2d4+1 one fire"}, 
  {"Fire Wolf",1,7,2, true, "AC=13 Flame Bite Melee +4 2d4+1 one fire"}, 
  {"Fire Sprite",1,7,0, true, "AC=9 Melee Bite +4 2d4 one fire"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"},
  {"Son of Ignis",1,10,1, true, "AC=11 Spell Caster Melee +3 1d4"}, 
  {"Aiden",1,14,1, true, "AC=13 Spell Caster Melee +3 1d4"}
};

 

 

void setup() {

  Serial.begin(9600);
  Serial.println("Hello");
  multiMonster();
  for(byte i = 0; i < TOME_LENGTH; i++){
    Serial.println(tome[i].mName);
  }
}

 

void loop() {


}

void multiMonster(){
  for(byte active = 0; active < TOME_LENGTH; active++){
    CircularBuffer<byte,20> monsterMatch;
    monsterMatch.push(active);                         //Adds the active index to monsterMatch
    for(byte compare = 0; compare < TOME_LENGTH; compare++){
      if(strcmp(tome[active].mName, tome[compare].mName) == 0 &&  active !=  compare){
        monsterMatch.push(compare);
      }
    }
   
    byte apendCounter = 1;
    if (monsterMatch.size() > 1){
      for(byte u = 0; u < monsterMatch.size(); u++){
        char monsterBuffer[4];
        sprintf(monsterBuffer, " %d", apendCounter);
        strcat(tome[monsterMatch[u]].mName, monsterBuffer);
        apendCounter++;
      }
    }       
    //for(byte i = 0; i < monsterMatch.size(); i ++){
    //  Serial.println(tome[active].mName);
    //  Serial.println(monsterMatch[i]);
    //}
  monsterMatch.clear();

  }

}




and here is the current result:
Code: [Select]
Hello
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12



For reference here is the revised Monster.h
Code: [Select]
#ifndef Monster_H
#define Monster_H

#include <Arduino.h>

class Monster{

public:
char mName[20];
bool inCombat;
byte initRoll;
byte currhp;

int hp;
byte initMod;
bool npc;
char* details;


Monster(char mName[20], byte r,byte h, int i, bool p, char* d);
void roll();
void engage();
void kill();
void takeHit(int howHard);



};

#endif


and the Monster.cpp
Code: [Select]
#include "Monster.h"

Monster::Monster(char mName[20], byte r,byte h, int i, bool p, char* d){
inCombat = false;
initRoll = r;
hp = h;
currhp = hp;
initMod = i;
npc = p;
details = d;

}


void Monster::roll(){
initRoll = random(1,21) + initMod;
}

void Monster::engage(){
inCombat = true;
}

void Monster::kill(){
inCombat = false;
}

void Monster::takeHit(int howHard){
currhp -= howHard;
if (currhp <= 0){
kill();
}
}



So I'm missing something else now, probably related to dealing with Char arrays.

PaulS

Why does the constructor take a name (mName) that it doesn't use?

Code: [Select]
char* details;
You still don't understand that you REALLY need to declare an array...

The art of getting good answers lies in asking good questions.

awoodbridge

I understand the memory allocation logic behind using a char array over char*. I don't understand how to implement that in my class constructor. I have attempted to do it for both the mName and the details.

Code: [Select]
#include "Monster.h"

Monster::Monster(char m[20], byte r,byte h, int i, bool p, char d[25]){
mName[20] = m;
inCombat = false;
initRoll = r;
hp = h;
currhp = hp;
initMod = i;
npc = p;
details[25] = d;

}


void Monster::roll(){
initRoll = random(1,21) + initMod;
}

void Monster::engage(){
inCombat = true;
}

void Monster::kill(){
inCombat = false;
}

void Monster::takeHit(int howHard){
currhp -= howHard;
if (currhp <= 0){
kill();
}
}



and Monster.cpp
Code: [Select]
#ifndef Monster_H
#define Monster_H

#include <Arduino.h>

class Monster{

public:
char mName[20];
bool inCombat;
byte initRoll;
byte currhp;

int hp;
byte initMod;
bool npc;
char details[25];


Monster(char m[20], byte r,byte h, int i, bool p, char d[25]);
void roll();
void engage();
void kill();
void takeHit(int howHard);



};

#endif



If this is not correct, please include a URL of where I can learn how to do this.

PaulS

Quote
If this is not correct, please include a URL of where I can learn how to do this.
Of course it is wrong. What I can not understand is why you can't understand how arrays work.

An array is a continuous block of memory. You defined an array, mName, with 20 elements. Then, you try to assign a value to the 21st position in that array, while ignoring the previous 20 elements.

Code: [Select]
char mName[20];

mName[20] = m;

That, or course, is rubbish. Even without the incorrect value in the brackets, that is NOT how you copy data from one array to another. strcmp() rules.

The assignment to details is equally wrong.

ANY C book will clear up all of your erroneous misconceptions by the end of chapter 4. GET A BOOK. Forget about online resources. If nothing else, we can beat you over the head with the book. Can't do that with a URL.
The art of getting good answers lies in asking good questions.

awoodbridge

I'll work on getting a book.

I've looked at my .h and .cpp with fresh eyes, and I've implemented strcpy.

Monster.h:
Code: [Select]
#ifndef Monster_H
#define Monster_H

#include <Arduino.h>

class Monster{

public:
char mName[20];
bool inCombat;
byte initRoll;
byte currhp;

int hp;
byte initMod;
bool npc;
char details[25];


Monster(char n[20], byte r,byte h, int i, bool p, char d[25]);
void roll();
void engage();
void kill();
void takeHit(int howHard);
};

#endif



Monster.cpp:
Code: [Select]
#include "Monster.h"

Monster::Monster(char n[25], byte r,byte h, int i, bool p, char d[25]){
strcpy(n , mName);
  inCombat = false;
initRoll = r;
hp = h;
currhp = hp;
initMod = i;
npc = p;
strcpy(d, details);
}


void Monster::roll(){
initRoll = random(1,21) + initMod;
}

void Monster::engage(){
inCombat = true;
}

void Monster::kill(){
inCombat = false;
}

void Monster::takeHit(int howHard){
currhp -= howHard;
if (currhp <= 0){
kill();
}
}

PaulS

Code: [Select]
strcpy(n , mName);

The arguments are to where, from where.

The art of getting good answers lies in asking good questions.

awoodbridge

That's the missing piece. Everything works as expected, and has been folded into the main code. Thank you.

Go Up