Request: generating a list of clan members

zarqon

Well-known member
Is there any way to generate a map like this:

players[1] => "Clan Member 1"
players[2] => "Clan Member 2"
...
players[X] => "Clan Member X"

I've searched quite a long time and haven't found anything that works. I tried accessing $clan as a constant, I took a look at the CLI "clan snapshot" feature to see if it left accessible files somewhere, but couldn't find a way to do it. I can parse clan_members.php and extract all the members if I must, but that would involve hours and hours of coding so I thought I'd ask first. It seems like the functionality for this must already exist somewhere...? Please tell me it does!

PS - hi everyone! I've been lurking here for several months now, and I'm undertaking my first large-scale script.
 

macman104

Member
I don't know of any function that does this. There is probably internal logic somewhere in mafia, but I've no clue how easy it would be for it to become accessible in an ASH function.
 

zarqon

Well-known member
Thanks for the help, though it's not the answer I hoped for. Sigh... looks like I'll be parsing clan_detailedroster.php to extract clan members even though the functionality is SO already in KoLmafia. Is there an official place to request ASH functions, e.g. should I visit the sourceforge site and make a request there? I think some clan-accessing functions would be very helpful to not just me, but the community.

How? Well, I think a lot of people are hardcoding clan things that could be dynamic, if only the functions existed. Hardcoding clan membernames necessitates each user rewrite their code. But some clan functions would allow for much more portable scripts. I'm thinking a few like

map [b]get_clannies()[/b]
Returns a map of [ 0 ] => Member1, [ 1 ] => Member2, ...
Would only need 1 server hit.

boolean [b]is_clannie(string id)[/b]
boolean [b]is_clannie(int id)[/b]

Returns true if the user specified by id is in your clan, or false if not. Also returns false if you are not in a clan.

would be exceptionally useful. I can probably write them myself (I'll have to check out ASH's string-handling routines in more detail) but I think accessing the existing KoLmafia functionality would be the better option.

Any thoughts? Am I the only person who thinks this is a good idea?
Well, it ended up being quite a bit simpler than I thought to do in ASH. In case anyone else stops by this thread to check it out, here's how to do it. This'll do for now... while I secretly hope for an ASH function. ;)

This function will return a map containing all your clan members by name (not number). NOTE: You'll need to remove the spaces from the < b > tags in the penultimate line.

Code:
string [int] get_clannies()
{
   string orightml = visit_url("clan_detailedroster.php");
   orightml = substring(orightml,index_of(orightml,"showplayer.php")+14);
   string[int] clannies = split_string(orightml,"showplayer.php");
   foreach i in clannies
      clannies[i] = substring(clannies[i],index_of(clannies[i],"< b >")+3,index_of(clannies[i],"< /b >"));
   return clannies;
}
 

MagiNinjA

New member
I'm pretty sure KoLmafia can get a list of clannies internally, as I know it does for the Flower Hunter.

Also, awesome coding there. Do you think you'll eventually support multiple pages?
 

zarqon

Well-known member
I'm pretty sure clan_detailedroster.php doesn't split the members into separate pages, only clan_members.php does. That's why I chose to parse clan_detailedroster.php -- easier to code and only one server hit. So no multiple-page support is necessary!
 

MagiNinjA

New member
OHHHH, right right, my bad. I totally JUST remembered which page you meant. Yes, clan_detailedroster.php is win. >:)
 

mredge73

Member
hey
don't know if anyone is still interested in this but I wrote a much more elaborate parser for clan members. This one will grab everything off of the clan_detailedroster.php and put it in a .txt. Another nice feature is that it will keep people on this list even if they are no longer in the clan but will have a rank of BOOTED. This is updated back to normal if they come back, and keeps their karma on file. This is helpful for automatically distrubuting welcome packages, if you don't want to keep giving them out to someone who has already quit once. Also helpful on auto accepting applications, if you don't want to let them back in or if you want to re-establish their rank and karma.

Code:
void BuildRoster()
{
    record
    {
        int ID;
        string Type;
        int Muscle;
        int Myst;
        int Moxie;
        int TotalStats;
        int Ascentions;
        int HCAscentions;
        int PVPscore;
        string Rank;
        int Karma;
    } [string] Roster;
    
    record
    {
        int ID;
        string Type;
        int Muscle;
        int Myst;
        int Moxie;
        int TotalStats;
        int Ascentions;
        int HCAscentions;
        int PVPscore;
        string Rank;
        int Karma;
    } [string] CurrentRoster;
    File_To_Map("ClanRoster.txt", CurrentRoster);
    
    string Name= "None";
    string ClanRoster= visit_url( "clan_detailedroster.php?sort=karma&pwd" );
    matcher RosterEntry = create_matcher( "who=(.+?)\"><b>(.+?)</b>  </a></td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td>" , ClanRoster );
    //print("build matcher");
    
    while( RosterEntry.find() )
    {
        Name= RosterEntry.group( 2 );
        Roster[Name].ID= RosterEntry.group( 1 ).to_int();
        Roster[Name].Type= RosterEntry.group( 3 );
        Roster[Name].Muscle= RosterEntry.group( 4 ).to_int();
        Roster[Name].Myst= RosterEntry.group( 5 ).to_int();
        Roster[Name].Moxie= RosterEntry.group( 6 ).to_int();
        Roster[Name].TotalStats= RosterEntry.group( 7 ).to_int();
        Roster[Name].Ascentions= RosterEntry.group( 8 ).to_int();
        Roster[Name].HCAscentions= RosterEntry.group( 9 ).to_int();
        Roster[Name].PVPscore= RosterEntry.group( 10 ).to_int();
        Roster[Name].Rank= RosterEntry.group( 11 );
        Roster[Name].Karma= RosterEntry.group( 12 ).to_int();
    }
    //print("matcher done");
    
    if (count (CurrentRoster) ==0)
    CurrentRoster=Roster;
    
    foreach Clannie in CurrentRoster
    {        
        switch 
        {        
        case !(Roster contains Clannie):
            CurrentRoster[Clannie].Type= "None";
            CurrentRoster[Clannie].Muscle= 0;
            CurrentRoster[Clannie].Myst= 0;
            CurrentRoster[Clannie].Moxie= 0;
            CurrentRoster[Clannie].TotalStats= 0;
            CurrentRoster[Clannie].Ascentions= 0;
            CurrentRoster[Clannie].HCAscentions= 0;
            CurrentRoster[Clannie].PVPscore= 0;
            CurrentRoster[Clannie].Rank= "BOOTED";
            break;
        case CurrentRoster[Clannie].ID!=Roster[Clannie].ID:
            CurrentRoster[Clannie].ID=Roster[Clannie].ID;
        case CurrentRoster[Clannie].Type!=Roster[Clannie].Type:
            CurrentRoster[Clannie].Type=Roster[Clannie].Type;
        case CurrentRoster[Clannie].Muscle!=Roster[Clannie].Muscle:
            CurrentRoster[Clannie].Muscle=Roster[Clannie].Muscle;
        case CurrentRoster[Clannie].Myst!=Roster[Clannie].Myst:
            CurrentRoster[Clannie].Myst=Roster[Clannie].Myst;
        case CurrentRoster[Clannie].Moxie!=Roster[Clannie].Moxie:
            CurrentRoster[Clannie].Moxie=Roster[Clannie].Moxie;
        case CurrentRoster[Clannie].TotalStats!=Roster[Clannie].TotalStats:
            CurrentRoster[Clannie].TotalStats=Roster[Clannie].TotalStats;
        case CurrentRoster[Clannie].Ascentions!=Roster[Clannie].Ascentions:
            CurrentRoster[Clannie].Ascentions=Roster[Clannie].Ascentions;
        case CurrentRoster[Clannie].HCAscentions!=Roster[Clannie].HCAscentions:
            CurrentRoster[Clannie].HCAscentions=Roster[Clannie].HCAscentions;
        case CurrentRoster[Clannie].PVPscore!=Roster[Clannie].PVPscore:
            CurrentRoster[Clannie].PVPscore=Roster[Clannie].PVPscore;
        case CurrentRoster[Clannie].Rank!=Roster[Clannie].Rank:
            CurrentRoster[Clannie].Rank=Roster[Clannie].Rank;
        case CurrentRoster[Clannie].Karma!=Roster[Clannie].Karma:
            CurrentRoster[Clannie].Karma=Roster[Clannie].Karma;        
        }        
    }
    Map_To_File(CurrentRoster, "ClanRoster.txt");
}
 

giraffe man

New member
I tried editing the code so it returns a map instead of putting it in a file. What's wrong with it?

Code:
void BuildRoster() 
{
     record
     { 
         int ID; 
         string Type; 
         int Muscle; 
         int Myst; 
         int Moxie; 
         int TotalStats; 
         int Ascentions; 
         int HCAscentions; 
         int PVPscore; 
         string Rank; 
         int Karma; 
     } [string] Roster;
     string Name= "None"; 
     string ClanRoster= visit_url( "clan_detailedroster.php?sort=karma&pwd" ); 
     matcher RosterEntry = create_matcher( "who=(.+?)\"><b>(.+?)</b>  </a></td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td>" , ClanRoster ); //print("build matcher"); 
     while( RosterEntry.find() ) 
     { 
         Name= RosterEntry.group( 2 ); 
         Roster[Name].ID= RosterEntry.group( 1 ).to_int(); 
         Roster[Name].Type= RosterEntry.group( 3 ); 
         Roster[Name].Muscle= RosterEntry.group( 4 ).to_int(); 
         Roster[Name].Myst= RosterEntry.group( 5 ).to_int(); 
         Roster[Name].Moxie= RosterEntry.group( 6 ).to_int(); 
         Roster[Name].TotalStats= RosterEntry.group( 7 ).to_int(); 
         Roster[Name].Ascentions= RosterEntry.group( 8 ).to_int(); 
         Roster[Name].HCAscentions= RosterEntry.group( 9 ).to_int(); 
         Roster[Name].PVPscore= RosterEntry.group( 10 ).to_int(); 
         Roster[Name].Rank= RosterEntry.group( 11 ); 
         Roster[Name].Karma= RosterEntry.group( 12 ).to_int(); 
      }
      return Roster;
}
 

jasonharper

Developer
What's wrong with it?
You tell us - what IS wrong with it? It's kind of hard to reply to messages like this when you haven't given the slightest hint as to what the problem is. Did it fail to compile? POST THE ERROR MESSAGE! Did it produce an error when run? POST THE ERROR MESSAGE! Did it do something unexpected? POST WHAT IT DID, AND WHAT YOU EXPECTED!
 

mredge73

Member
well

1. First of all, a void function does not return anything.

2. To return a record you must first define the record outside the function. The record is a user created type so you as the user must create it first.

3. Do you really want to return the record or do you just want to build the map? If you just want to build the map, define the record as a global variable instead of inside the function, then run your function as is without the return command

Code:
record
     { 
         int ID; 
         string Type; 
         int Muscle; 
         int Myst; 
         int Moxie; 
         int TotalStats; 
         int Ascentions; 
         int HCAscentions; 
         int PVPscore; 
         string Rank; 
         int Karma; 
     } [string] Roster;

void BuildRoster() 
{
     
     string Name= "None"; 
     string ClanRoster= visit_url( "clan_detailedroster.php?sort=karma&pwd" ); 
     matcher RosterEntry = create_matcher( "who=(.+?)\"><b>(.+?)</b>  </a></td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td><td class=small>(.+?)</td>" , ClanRoster ); //print("build matcher"); 
     while( RosterEntry.find() ) 
     { 
         Name= RosterEntry.group( 2 ); 
         Roster[Name].ID= RosterEntry.group( 1 ).to_int(); 
         Roster[Name].Type= RosterEntry.group( 3 ); 
         Roster[Name].Muscle= RosterEntry.group( 4 ).to_int(); 
         Roster[Name].Myst= RosterEntry.group( 5 ).to_int(); 
         Roster[Name].Moxie= RosterEntry.group( 6 ).to_int(); 
         Roster[Name].TotalStats= RosterEntry.group( 7 ).to_int(); 
         Roster[Name].Ascentions= RosterEntry.group( 8 ).to_int(); 
         Roster[Name].HCAscentions= RosterEntry.group( 9 ).to_int(); 
         Roster[Name].PVPscore= RosterEntry.group( 10 ).to_int(); 
         Roster[Name].Rank= RosterEntry.group( 11 ); 
         Roster[Name].Karma= RosterEntry.group( 12 ).to_int(); 
      }
      
}

4. FYI, I now include the original post in my Clan Admin Library

5. PS, I also agree with Jason, it helps if you post the actual problem that you are facing so we don't have to figure out both the problem and the solution.
 

Bale

Minion
5. PS, I also agree with Jason, it helps if you post the actual problem that you are facing so we don't have to figure out both the problem and the solution.
mredge73 gets bonus points for having figured out both the problem and the solution.
 

lostcalpolydude

Developer
Staff member
You tell us - what IS wrong with it? It's kind of hard to reply to messages like this when you haven't given the slightest hint as to what the problem is. Did it fail to compile? POST THE ERROR MESSAGE! Did it produce an error when run? POST THE ERROR MESSAGE! Did it do something unexpected? POST WHAT IT DID, AND WHAT YOU EXPECTED!

I'm disappointed, I thought you were a mind reader.
 
Top