First (real) attempt to make an ash script: Sewer.ash

Theraze

Active member
You do need to convert it though...
> ash string x = "12"; print(x*3);

Operator '*' applied to string operands ()
Returned: void

> ash string x = "12"; print(x+3);

123
Returned: void
 

Grotfang

Developer
Fair point. I apologise. However, I still don't think "int to_int( string x )" does anything:

Code:
> ash string x = "9"; if( x > 10 ) print( "Done" );

Done
Returned: true

> ash string x = "9"; int to_int( string x ); if( x > 10 ) print( "Done" );

Done
Returned: true

So removing the line will exhibit the same behaviour as before. However, both behaviours are wrong. Is that correct?
 

heeheehee

Developer
Staff member
At first, I thought that was incorrect syntax, but then I realized that this syntax is perfectly legitimate for initializing a function, sorta like initializing a variable without assigning it a value. Even so, since to_int(string) is defined in Mafia, that does absolutely nothing. :p

What would be desired is either
Code:
string x = "3";
if (to_int(x) > 3) print("Done");
or
Code:
string x = "3";
int y = to_int(x);
if (y > 3) print("Done");

(edit: if you saw something, that was just because I wasn't really reading the above post in context.)
 
Last edited:

Veracity

Developer
Staff member
However, I still don't think "int to_int( string x )" does anything...
It's a forward reference to a function; it tells KoLmafia that you will be defining a function with that signature later in the file. If you don't define the function, there's no problem unless you actually called that function somewhere.

It's a pretty obscure feature; usually you can simply declare your functions before they are used, but not if you have two mutually recursive functions - a calls b and b calls a - for example.
 

slyz

Developer
Except for mutual recursion it shows a lack of organization.
In aqualectrix's case, it looked more like tidiness. At the top of the script, all the global variables then all then functions are forward defined (with a little explanatory comment). It is a helpful thing to do in a library script.
 

fronobulax

Developer
Staff member
Obscure indeed. I only know it from examining dj_d's EatDrink which is the only place I've ever seen it used. Except for mutual recursion it shows a lack of organization.

Forward references have their uses in languages besides Ash and when compilers and syntax checkers are augmented by other processes. I worked a project that used C and a homebrew preprocessor. The latter worked much better if functions were declared before they were defined.

That said, I am not a big fan of them if only because there is the possibility that one more place needs to be changed when the function signature changes. I do, however use them if it allows me to group related functions together in the code or if it let's me write and debug code in one area before I futz with something unrelated.
 

Fluxxdog

Active member
It's a forward reference to a function; it tells KoLmafia that you will be defining a function with that signature later in the file. If you don't define the function, there's no problem unless you actually called that function somewhere.

It's a pretty obscure feature; usually you can simply declare your functions before they are used, but not if you have two mutually recursive functions - a calls b and b calls a - for example.
How exactly would you code these to work if a and b called each other? I've actually just run in to that little hangup.
 

slyz

Developer
How exactly would you code these to work if a and b called each other? I've actually just run in to that little hangup.
PHP:
// declare the functions
boolean func1( int i );
boolean func2( int i );

// define the functions
boolean func1( int i )
{
   boolean f2 = func2( i );
   ...
}

boolean func2( int i )
{
   boolean f1 = func1( i );
   ...
}
 

heeheehee

Developer
Staff member
Overall, the format's right, but I don't think that'd work -- if the first thing you do in each function is call the other one, that'd be an infinite loop, no? You'd probably want a base case, in which you actually return a value, in one of those functions.
 

me259259

Member
OK, after reading this, I am thoroughly confused. I was under the impression that when you save something via set_property, it would save it as a string, even when it should be something else. That's why I set up a string to int conversion. The glyph checker would come up with the number of glyphs that you have, and would set a property. Sewer.ash would get that property, convert it to an int, and then use it as a regular variable. I wasn't going to bother setting a property, and just use a variable by combining the scripts... but do people want to have to check for glyphs every time they adventure in the sewers? It seemed like a wasted server hit that could be avoided.

That all being said, I have a few questions:

Was I right in thinking that when a property gets set with set_property, it saves it as a string?
If so, does mafia automatically turn it back into an int?
If mafia doesn't handle it automatically, does the code I wrote (with to_int) do the conversion?
If it works, but to_int is obscure, why is it obscure?
 

Theraze

Active member
The problem isn't that you're doing to_int, it's that you're redefining to_int by not setting it to a value. You did this:
PHP:
int to_int (string hoboGlyphs);
If you'd done something like this instead, the whole question wouldn't have come up:
PHP:
int hoboCount to_int(string hoboGlyphs);

By doing int without actually giving it an int which you're calling, you're defining... not calling an existing function.
 

Fluxxdog

Active member
PHP:
// declare the functions
boolean func1( int i );
boolean func2( int i );

// define the functions
boolean func1( int i )
{
   boolean f2 = func2( i );
   ...
}

boolean func2( int i )
{
   boolean f1 = func1( i );
   ...
}
OK, so make both forward references first, then define them fully later.
Was I right in thinking that when a property gets set with set_property, it saves it as a string?
Yes
If so, does mafia automatically turn it back into an int?
From my experience, no.
If mafia doesn't handle it automatically, does the code I wrote (with to_int) do the conversion?
to_int() will convert, yes.
If it works, but to_int is obscure, why is it obscure?
It's not obscure. It was the way the specific example is written. The example had "int to_int(string x)" which is an example of a forward reference, an obscure method of programming in ASH. What you properly need is "to_int(x)". Given what Grotfang was referencing:
Code:
> ash string x = "9"; int to_int( string x ); if( x > 10 ) print( "Done" );

Done
Returned: true
He's talking about the middle part. To get it to behave the way you want, you would need:
Code:
> ash string x = "9"; if( to_int( x ) > 10 ) print( "Done" );

Returned: false
 

me259259

Member
Oh man, this is the 5th time I'm rewritting this post. At the beginning, I still had no idea what you all were talking about. Now I finally get it. It turns out that the whole problem was caused by an epic misreading of the to_int page on the mafia wiki. Whoops! The code I had before only worked by pure chance for reasons that shouldn't have worked... and only worked in ways I don't want to get into because I've already been writting this post for a long time now.

In the next release, I'll fix that section entirely, as well as a couple of hard to notice bugs that I ended up catching while trying to understand all this.

In a related note, do you guys mind if I take the code samples you used to help me, and add it to the to_int wiki page?
 

Bale

Minion
In a related note, do you guys mind if I take the code samples you used to help me, and add it to the to_int wiki page?

I'm not responsible for writing any of those code samples, but as one of the people responsible for the wiki I'd be overjoyed for anything helpful that you could add there.
 

Grotfang

Developer
The code I had before only worked by pure chance for reasons that shouldn't have worked... and only worked in ways I don't want to get into because I've already been writting this post for a long time now.

I'm so sorry! I hadn't intended to confuse you. I just hadn't seen that form of expression before and was curious as to what it was doing. Turns out both of us got confused :)

One final thing (and please feel free to completely discount this if it is of no use to you). I notice that in your script, the number of hobo codes you have determines the number of sewer items purchased. You could actually get a more precise (and cheap) result if you were willing to do the maths behind the grates calculation. In my hobopolis script suite, I use the following code:

Code:
int grates_open()
{	
	print( "Checking grates" );
	int count = 0;
	int open_grates = 0;
	string parsed_grates = visit_url( "clan_raidlogs.php" );
	if( contains_text( parsed_grates , "sewer grate" ) )
	{
		string p = substring(parsed_grates , index_of( parsed_grates, "sewer grate" ));

		string leftover(string s)
		{
			p = substring(s, index_of( s, "sewer grate" ));
			p = substring(p, index_of(p, "("));
			int i = to_int(substring( p, 0, index_of( p , " turn" ) ));
			count = count + i;
			return p;
		}
	
		while( contains_text( p, "sewer grate" ) )
		{
			leftover(p);
		}
	}
	open_grates = count;
	print( count + " open grates" , "blue" );
	return open_grates;
}

It will return the number of open grates. This can be used to determine a proportion of grates open you are likely to encounter (and also, if you want to be brave and do more complicated sums, the number of grates you need to open before moving onto tunnels). This allows you to purchase potentially lower minimums, then buy as needed later on. I would add that my scripts handle adventuring a little differently, using visit_url() and run_combat(), so it is simpler to adapt to circumstance. Anyways, as I said, I don't know how complicated you are looking to make this script. Just figured I would share as well as apologise!

Best wishes
 
Top