looking at clan_raidlogs.php

Pazleysox

Member
Code:
{
	string log = visit_url( "clan_raidlogs.php" );
	foreach place in $strings[forest]
		if(log.contains_text( ") drove some werewolves out of the " + place))
			print( "The " + place + " has had werewolves driven out" );
		else print( "The " + place + " needs to have werewolves driven out" );
}

This only shows one instance of the werewolves being driven out of the castle, even if there is 2.

Code:
if(log.contains_text( ") drove some werewolves out of the " + place) && (log.contains_text( ") drove some werewolves out of the " + place)))

this also only looks at the first instance.
Code:
{
	string log = visit_url( "clan_raidlogs.php" );
	foreach place in $strings[Woods, Village]
		if(log.contains_text( ") drove some werewolves out of the "))
			print( "The " + place + " has had werewolves driven out" );
		else print( "The " + place + " needs to have werewolves driven out" );
}
This prints out 2, but doesn't look past the first instance.

Anyone have any suggestions how I can get the script to look into 2 locations for? IE, I need to look in the "Woods" part of the logs, and again in the "Village" for the same thing.
 

Theraze

Active member
Use split_string instead. Whether by splitting on location or on the discovery, it just depends on how accurate you want... what.
 

Veracity

Developer
Staff member
Use a matcher. Something like this:

Code:
{
    string log = visit_url( "clan_raidlogs.php" );
    int [string,string] zones;
    matcher matcher = create_matcher( log, "drove some (bugbears|werewolves|zombies|ghosts|skeletons|vampires) out of the (forest|village|castle)" );
    while ( matcher.find() ) {
	string mon = matcher.group(1);
	string zone = matcher.group(2);
	zones[ zone, mon ]++;
    }
    foreach zone, mon, count in zones {
	print( mon + " have been banished from " + zone + " " + count + " times." );
    }
}
This assumes that the message is the same for all monsters/zone.

It's also not necessary to track which zone a particular monster is from since that is constant. But, the code is indicative.
 
Last edited:

Pazleysox

Member
Use a matcher. Something like this:

Code:
{
    matcher matcher = create_matcher( log, "drove some (bugbears|werewolves|zombies|ghosts|skeletons|vampires) out of the (forest|village|castle)" );
    while ( find (matcher.find() ) {
	string mon = matcher.group(1);
	string zone = matcher.group(2);
	zones[ zone, monster ]++;
    }
    foreach zone, monster, count in zones {
	print( monster + " have been banished from " + zone + " " + count + " times." );
    }
}

Mafia did not like this. Changed "Matcher Matcher" to "Matcher clanlog" to get around it. Had to change all instances of matcher to clanlog for the script to work.

here's what I have, and the error I get:
Code:
{
    string log = visit_url( "clan_raidlogs.php" );
    int [string,string] zones;
    matcher clanlog = create_matcher( log, "drove some (bugbears) out of the (forest)" );
    while ( find(clanlog) ) {
	string animal = clanlog.group(1);
	string zone = clanlog.group(2);
	zones[ zone, animal ]++;
    }
    foreach zone, animal, count in zones {
	print( animal + " have been banished from " + zone + " " + count + " times." );
    }

Invalid pattern syntax (00 TEST.ash, line 5)

I've been fiddling around with it for over an hour. Adding thing, taking things out, trying different variations, to no avail...

I cut this
(bugbears|werewolves|zombies|ghosts|skeletons|vampires)
down to this
(bugbears)
in hopes of trying to figure out what was going wrong. Trying to reduce what the problem might be.
 

Veracity

Developer
Staff member
Reverse the order of the arguments to create_matcher. The pattern comes first. I should have looked it up in the Wiki, but, I figured you would do that. I was teaching you about concepts you (apparently) were not aware of.
 

Pazleysox

Member
Reverse the order of the arguments to create_matcher. The pattern comes first. I should have looked it up in the Wiki, but, I figured you would do that. I was teaching you about concepts you (apparently) were not aware of.

Haha! Doing a little more research, I did figure out what you meant! Now the script works Thank you very much!

Now...

How can I put an "IF" expression in there...

I'll work on it, but I need to figure out something along the lines of this:
Code:
	if (count) == 1	print("only 1 found, proceed"); (command to continue)
	if (count) == 2 print("2 found, no more to do here");
        return;
 
Last edited:

Veracity

Developer
Staff member
You can start with simple patterns - like the ones I showed - and work your way up to more complicated things.
 

Bale

Minion
Gee. I usually try to NOT show regexp to beginners. It has been known for people's heads to explode when encountering regexps for the first time. Even zarqon still hasn't come to terms with them even though he cannot deny their versatility.

Anyway, if someone is going to start studying the subject I recommend this site: Regular Expression Tutorial. I also wrote up a guide for using regexp with kolMafia. The later guide stresses the points that are more frequently important in ash scripting, but leaves out a lot of the detail in the previous guide which is way better.

After studying regexp for a bit you can try them out HERE since it gives some useful feedback on what you're doing.

Of course once someone gets comfortable with regexp they start to look like the best solution for nearly all string matching possible. (Other than very basic contains_text() checks.) They're amazing.
 
Last edited:

Veracity

Developer
Staff member
Curious what you would recommended to solve the OP's problem without using a matcher.
Theraze recommended using split_string. Because... I have no idea how that is relevant.
How would you do it?
 

Theraze

Active member
> ash string testing = "You drove some werewolves out of here. He drove some werewolves out of there."; split_string(testing, "drove some werewolves");

Returned: aggregate string [3]
0 => You
1 => out of here. He
2 => out of there.

> ash string testing = "You drive some werewolves out of here. He drank some werewolves out of there."; split_string(testing, "drove some werewolves");

Returned: aggregate string [1]
0 => You drive some werewolves out of here. He drank some werewolves out of there.

> ash string testing = "You drove some werewolves out of here. He drove some werewolves out of there."; split_string(testing, "drove some werewolves").count();

Returned: 3
One less than the count is how many matches you get. Easy/lazy not-matcher matching.
 

Bale

Minion
Curious what you would recommended to solve the OP's problem without using a matcher.
Theraze recommended using split_string. Because... I have no idea how that is relevant.
How would you do it?

While regexp are built into split_string it isn't necessary to know much about them. I think it is probably the simplest solution. It is relevant like this:

Code:
void main() {
	string log = visit_url("clan_raidlogs.php");
	string [int] drove;
	foreach place in $strings[some werewolves out of the forest, 
		some bugbears out of the forest, 
		some vampires out of the castle,
		some skeletons out of the castle, 
		some zombies out of the village, 
		some ghosts out of the village] {
			drove = split_string(log, place);
			if(count(drove) > 1)
				print("Drove " + place+ " " + (count(drove) - 1) + " times.");
			else print("Didn't drive " + place);
	}
}
 
Last edited:

Theraze

Active member
Strange, but it works and it's relatively easy to sort out if you just need to do some basic counting.
 

Bale

Minion
A very slow ninja by Theraze while I was testing. (And checking old clan raidlogs.) Our code is essentially similar, but I hope you won't think mine is as strange.
 

Veracity

Developer
Staff member
I would call both of the split_string solutions grossly inefficient, both in computation and memory usage. Repeatedly processing the same page text and repeatedly creating new strings from large parts of it. And to my eye, less maintainable.

My solution, with a pattern and a matcher, makes one pass through the response text and generates 3 strings (group(0), (1), and (2)) from each match.

Maybe "strange" is not the right word. "I have to study the code for a while to understand what's happening" might be more of what I had in mind.
 

ckb

Minion
Staff member
For the record, I would advocate just learning some basic RegEx. But start slow, and don't try to look through existing code until you know what you are doing a bit more. It can be very rewarding once to get the hang of it.
And understand that you have to slash slashes and escape escapes in parts of ash.

So to use \d in ash (to matche any digit character), you in fact need to use "\\d" in your ash string.
 

Bale

Minion
I would call both of the split_string solutions grossly inefficient, both in computation and memory usage. Repeatedly processing the same page text and repeatedly creating new strings from large parts of it. And to my eye, less maintainable.

My solution, with a pattern and a matcher, makes one pass through the response text and generates 3 strings (group(0), (1), and (2)) from each match.

I agree. I would have used your solution myself.
 

Theraze

Active member
Agreed that matcher is great for when properly caffeinated and so forth. The split_string solution is sort of a... gateway regexp. If you don't know how to do anything more complex and you're just asking how to get into the door, it works.
 
Top