Question regarding tables

Posted by Edoren on Fri 20 Apr 2007 08:14 PM — 23 posts, 80,871 views.

#0
Hey i have a question regarding using triggers to store wildcards in tables. i have the current triggers:

^You reel in the last bit of line and your struggle is over\. You've landed a (.*) weighing (\d+) (?:pound(?:s)\.|pound(?:s) and (\d+) ounce(?:s)\.)$

^With a final tug, you finish reeling in the line and land a (.*) weighing (\d+) (?:pound(?:s)\!|pound(?:s) and (\d+) ounce(?:s)\!)$

The problem im having is in figuring out how to store the different variables in a database depending on what happens. since its a possibility of having 2 or 3 variables i always end up with an invalid number of arguments if there are only 2. the variables being the name of the fish, the pounds, and ounces. anyone have suggestions on how i should be working this out?
Amended on Fri 20 Apr 2007 08:16 PM by Edoren
Australia Forum Administrator #1
Yes, use named wildcards. You can also simplify a bit. This one worked for me on all the test cases:


<triggers>
  <trigger
   custom_colour="2"
   enabled="y"


match="^You reel in the last bit of line and your struggle is over\. You've landed a (?P&lt;fish&gt;.*) weighing (?P&lt;pounds&gt;\d+) pounds?(\.| and (?P&lt;ounces&gt;\d+) ounces?\.)$"


   regexp="y"
   send_to="2"
   sequence="100"
  >
  <send>
fish = %&lt;fish&gt;
pounds = %&lt;pounds&gt;
ounces = %&lt;ounces&gt;
</send>
  </trigger>
</triggers>



The important bit is here, withe the &lt; stuff converted (as it would look in the trigger dialog):


You've landed a (?P<fish>.*) weighing (?P<pounds>\d+) pounds?(\.| and (?P<ounces>\d+) ounces?\.)


The named wildcards are in the form (?P<name> match) and the other thing you can do to simplify is use something like "pounds?" this is because the "?" after the "s" means "zero or one of them", which is fine for detecting singular/plural.
Amended on Fri 20 Apr 2007 09:37 PM by Nick Gammon
Australia Forum Administrator #2
As for storing the data, if you use "send to script" this works fine:


lastfish = {}

lastfish.fish = "%<fish>"
lastfish.pounds = %<pounds>
lastfish.ounces = tonumber ("%<ounces>") or 0



The "or 0" handles the possibility that the ounces might not be there.
#3
i keep getting this:

Line 110: Elements terminated out of sequence, expected </ounces>, got </send> (problem in this file)

fish=%<fish>
pounds=%<pounds>
ounces=%<ounces>
Australia Forum Administrator #4
See: http://mushclient.com/pasting

If you copy and paste my example between <triggers> and </triggers> it works.
Australia Forum Administrator #5
If you are pasting into a plugin you have to change < to &lt; and > to &gt;
Australia Forum Administrator #6
Since you always get the trailing period, it could look better as:


You've landed a (?P<fish>.*) weighing (?P<pounds>\d+) pounds?( and (?P<ounces>\d+) ounces?)?\.

#7
well that helps me out with that. a question though, with that script i end up losing the data everytime its triggered. im thinking i'd be better off using my start and stop alias to create/print. also i'd be using the triggers to insert. im using a plugin atm, so whenever i try printing/inserting it doesnt work from functions. im guessing im just missing something to call the table before inserting. any suggestions?
Australia Forum Administrator #8
It is pretty hard to help from that description. Perhaps posting the plugin if it is reasonably short, and expaining what it is doing, and what you expect it to do.
#9
<trigger
   enabled="y"
   match="^You reel in the last bit of line and your struggle is over\. You've landed a (?P&lt;fish&gt;.*) weighing (?P&lt;pounds&gt;\d+) pounds?(\.| and (?P&lt;ounces&gt;\d+) ounces?\.)$"
   regexp="y"
   script="reel_stop"
   sequence="100"
  >
  </trigger>

  <trigger
   enabled="y"
   match="^With a final tug, you finish reeling in the line and land a (?P<fish>.*) weighing (?P<pounds>\d+) (pounds?(\!| and (?P<ounces>\d+) ounces?\!))$"
   regexp="y"
   script="reel_stop"
   sequence="100"
  >
  </trigger>

<alias
 match="^fish (.+)$"
 regexp="y"
 enabled="y"
 script="fishing"
 sequence="100"
 >
 </alias> 

function fishing (name, line, wildcards)
  local s=(wildcards[1])
  if s == "on" then
   Send ("unwield left")
   Send ("unwield right")
   Send ("put 2 shortsword in bag")
   Send ("get pole from kitbag")
   Send ("get bucket from kitbag")
   Send ("wield pole")
   else if s == "off" then
    world.Execute ("rl")
    Send ("unwield pole")
    Send ("put pole in kitbag")
    Send ("put bucket in kitbag")
   else
    Note ("I'm sorry, that didn't work")
  end --else if
 end --if
end --fishing on or off?

function reel_stop ()
 EnableTrigger ("reel_caught", false)
 Send ("put fish in kitbag")
 world.Execute ("bh")
end --stop reel


i want to just use the fish alias so that when its set on, it will create the table. then the triggers for inserting into the table. then once its eventually done i want to use the fish alias again to print the actual data. the reel_stop function is called when the fish is caught for both triggers, and the fishing function is called when i start and finish.

obviously there are more triggers/alias/functions but these are the only one's im referring to.
Amended on Sat 21 Apr 2007 09:58 PM by Edoren
Australia Forum Administrator #10
Well for a start, your script (if this is inside a plugin) needs to be inside <script> tags, like this:


<script>

function reel_stop ()
 EnableTrigger ("reel_caught", false)
 Send ("put fish in kitbag")
 world.Execute ("bh")
end --stop reel

---> and other functions

</script>


Next, as I tried to explain before, inside a plugin you need to convert < to &lt;. See how inside the plugin there are things like: </trigger>? Well, in your plugin it sees <fish> and tries to interpret that as some sort of XML keyword.

You have to make it &lt;fish&gt;

You have it in your first trigger, but not the second one.
#11
i left out the script/triggers tags because i copy/pasted them from the plugin since you wanted a visual of what i was talking about. as to the second trigger i was using the right one i apparently copied from the test version of the plugin where i was just checking things out so that's not a problem.

anyway, the real question i had was in regards as how i can access the table if i created it in the alias function to access in the trigger function for storing and then print it again from the alias function.
Australia Forum Administrator #12
Tables are shared between all functions in the script space. Can you show what you are doing a bit more? I am having trouble understanding what the problem is.
#13
function fishing (name, line, wildcards)
  local s=(wildcards[1])
  if s == "on" then
   Send ("unwield left")
   Send ("unwield right")
   Send ("put 2 shortsword in bag")
   Send ("get pole from kitbag")
   Send ("get bucket from kitbag")
   Send ("wield pole")
   lastfish = {}
   else if s == "off" then
    world.Execute ("rl")
    Send ("unwield pole")
    Send ("put pole in kitbag")
    Send ("put bucket in kitbag")
    table.foreach (lastfish, print)
   else
    Note ("I'm sorry, that didn't work")
  end --else if
 end --if
end --fishing on or off?


function reel_stop (name, line, wildcards)
 EnableTrigger ("reel_caught", false)
 Send ("put fish in kitbag")
 world.Execute ("bh")
 lastfish.fish = wildcards[1]
 lastfish.pounds = wildcards[2]
 lastfish.ounces = tonumber "(wildcards[3])" or 0
end --stop reel


I received this line:

You reel in the last bit of line and your struggle is over. You've landed a walleye weighing 15 pounds and 11 ounces.

it printed:

fish walleye
ounces 0
pounds 15


Actually this is a lot better than before. When i was first trying it wouldn't even print anything since it was coming out nil. Must have messed something else up that i fixed. But now i get everything except for the ounces correctly atm. The second thing is if i want to insert these into the table instead with table.insert () how would i go about it? I tried testing it out but it came back nil with the same values as above. More than likely i dont have the exact syntax for table.insert with the strings. At the moment i'm really just experimenting and learning about tables and more about functions. Anyway, my last question is how i can print the name/pound/ounces on the same line, so that every time a trigger goes off it will print those 3 before making a new line and sending the next.
Amended on Sun 22 Apr 2007 03:25 AM by Edoren
Australia Forum Administrator #14
You need to think about what you are doing here. In my example I was using "send to script" when I gave this code:


lastfish.fish = "%<fish>"
lastfish.pounds = %<pounds>
lastfish.ounces = tonumber ("%<ounces>") or 0


So, if the fish was "flounder", pounds were "22" and ounces were "7", this is what the script would have seen:


lastfish.fish = "flounder"
lastfish.pounds = 22
lastfish.ounces = tonumber ("7") or 0


That is all fine. But you have moved it into a trigger function and substituted wildcards [1] etc. So far so good. But for ounces you left the quotes in, so this is what you have:


lastfish.ounces = tonumber "(wildcards[3])" or 0


However it can't convert the words "(wildcards[3])" into a number. You have put a variable name into quotes, that won't work. You need instead:


lastfish.ounces = tonumber (wildcards[3]) or 0


The other thing to consider is, we have gone to the trouble of naming the wildcards, why not use the names? Like this:


lastfish.fish = wildcards.fish
lastfish.pounds = wildcards.pounds
lastfish.ounces = tonumber (wildcards.ounces) or 0


That make it much easier to read, and you don't get confused about what each number means.
#15
oh duh, i didn't even think about using the names for that! hmm, does the same thing work for inserting then? ie -

table.insert (lastfish.fish, (wildcards.fish))
table.insert (lastfish.pounds, wildcards.pounds)
table.insert (lastfish.ounces, (wildcards.ounces) or 0)?
Amended on Sun 22 Apr 2007 05:05 AM by Edoren
Australia Forum Administrator #16
I'm not exactly sure what you mean by "inserting" in this case. If you do this:


lastfish.fish = wildcards.fish


You *have* inserted wildcard.fish into the lastfish table, keyed by the name "fish".

When you use table.insert you are inserting something with a numeric key, which you probably don't want here.
Australia Forum Administrator #17
To illustrate that, consider this test:


require "tprint"

lastfish = {}

lastfish.fish = "cod"
lastfish.pounds = 42
lastfish.ounces = 10

tprint (lastfish)


Output

"fish"="cod"
"ounces"=10
"pounds"=42


Here we have put details about the fish into the table, keyed by the item name (eg. lastfish.fish is "cod").

Next time the trigger fires, it will replace the items with the new ones.

If you use table.insert, things just get a numeric key, like this:


require "tprint"

lastfish = {}

table.insert (lastfish, "cod")
table.insert (lastfish, 42)
table.insert (lastfish, 10)

tprint (lastfish)

Output

1="cod"
2=42
3=10


You can see that isn't as easy to use. Also, if you insert more stuff, it gets added, not replaced:


table.insert (lastfish, "flounder")
table.insert (lastfish, 16)
table.insert (lastfish, 12)

tprint (lastfish)

Output

1="cod"
2=42
3=10
4="flounder"
5=16
6=12



Try reading my post about Lua tables:

http://www.gammon.com.au/forum/?id=6036
#18
well the thing was i didn't want to replace something based on name since, the fish names are basically only a few different types. so if i wanted to keep a running tally/list of what i had caught it would be replaced rather than being stored everytime it finds the same name.
Australia Forum Administrator #19
You want to keep tally of each individual fish, is that it? You still don't want table.insert. Something like this is more like it:


lastfish [wildcards.fish] = {
  pounds = wildcards.pounds, 
  ounces = wildcards.ounces }


What that will do is create a sub-table, in the lastfish table, keyed by the name of the fish, and inside it will be the details for that type.

eg.

The table might contain:


lastfish.cod.pounds = 42
lastfish.cod.ounces = 10
lastfish.flounder.pounds = 11
lastfish.flounder.lounces = 2


#20
aha! that's what i was looking for.
#21
hmm what's wrong with this? numkey wont ever add.

function reel_stop (name, line, wildcards)
 local numkey=numkey or 0
 local gold=gold or 0
 local pounds=tonumber (wildcards.pounds) or 0
 local ounces=tonumber (wildcards.ounces) or 0
  EnableTrigger ("reel_caught", false)
  Send ("put fish in kitbag")
  lastfish [numkey] = {
   fish = wildcards.fish,
   pounds = wildcards.pounds, 
   ounces = wildcards.ounces }
  if pounds > 0 then
   count= pounds*16 + ounces
   if gold > 0 then
    gold=gold + count*0.8
   else
    gold=count*0.8
   end --gold
  else
   if gold > 0 then
    gold=gold + ounces*0.8
   else
    gold=ounces*0.8
   end --gold
  end --pounds
  numkey=numkey+1
 end --stop reel
Amended on Sun 22 Apr 2007 08:14 PM by Edoren
Australia Forum Administrator #22
You made numkey local, so each time the function is called, it is back to nil. Remove the word "local" from in front of it.