Register to post in forums, or Log in to your existing account
 

Play RetroMUD
Post new topic  Reply to topic     Home » Forums » CMUD General Discussion
Stowslee
Wanderer


Joined: 20 Apr 2008
Posts: 69
Location: Watervliet, NY

PostPosted: Fri Sep 30, 2011 10:33 am   

Priority Order in an Array
 
I am trying to re-order elements in an array from the lowest # to the highest # and use that order as a way to prioritize a set of commands. Being fairly new to array's as well as CMud I have no idea how to even begin to attempt this, any point in the right direction would be greatly apprectiated.

Code:

blue ink=157|castorite=56|castorite slice=932|eyeball=420|eyeball slice=847|gold ink=15|green ink=110|heart=8|heart slice=386|iron=8|kidney=124|kidney slice=1599|leather=80|liver=235|liver slice=678|lung=2|lung slice=164|ovary slice=14|pineal=14|pineal slice=315|purple ink=871|red ink=333|spleen=36|spleen slice=322|stomach slice=274|sulphurite=9|sulphurite slice=98|


The above code is an example of the array that I am currently working from.
Reply with quote
Rahab
Wizard


Joined: 22 Mar 2007
Posts: 2320

PostPosted: Fri Sep 30, 2011 2:59 pm   
 
Could you be more specific about what you mean? I'm going to assume that you want to use the value "heart=8" first, then go on to "iron=8", "sulphurite=9", etc, according to the value of each key/value pair?

If that is what you are trying to do, you actually can't do it by reordering the list. What you have is a database variable. Normally, you cannot predict (or set) the order of the list in a database variable, because it is a hashed list. There is now an option to sort a database variable, but it will sort alphanumerically by the _keys_, not by the _values_, and in any case it treats it as a string value, not a numerical value.

There are a couple of possible solutions. I assume that ultimately you want "heart", not "heart=8", correct? The first thing that comes to mind is to create a simple stringlist of the keys in the order you desire. Stringlists, unlike database variables, do maintain the order in which you create the values. If your database variable above is named @dbvar, you can make an alias something like the following (untested!)
Code:

#LOCAL $tempdb $curkey $curindex $outlist $nextindex
$tempdb = @dbvar
#WHILE $tempdb {
  $curindex = 1
  $nextindex = 1
  $curkey = %dbkey($tempdb,1)
  $curval = $tempdb.1
  #WHILE ($nextindex < %numkeys($tempdb)) {
    $nextindex = ($nextindex + 1)
    #IF ($curval > $tempdb.$nextindex) {
      $curkey = %dbkey($tempdb,$nextindex)
      $curval = $tempdb.$nextindex
      $curindex = $nextindex
    }
  }
  $outlist = %addkey($outlist,$curkey,$curval)
  $tempdb = %delnitem($tempdb,$curindex)
}
@outlist = $outlist

Note that I'm not certain whether %delnitem will work on a db variable. I wrote this code in such a way as to allow multiple entries with the same key value, e.g. both "heart=8" and "heart=108" in the same list. If that does not happen, there are other ways to write it which would simplify things and you could use #DELKEY instead.
Reply with quote
Rahab
Wizard


Joined: 22 Mar 2007
Posts: 2320

PostPosted: Fri Sep 30, 2011 3:00 pm   
 
Could you be more specific about what you mean? I'm going to assume that you want to use the value "heart=8" first, then go on to "iron=8", "sulphurite=9", etc, according to the value of each key/value pair?

If that is what you are trying to do, you actually can't do it by reordering the list. What you have is a database variable. Normally, you cannot predict (or set) the order of the list in a database variable, because it is a hashed list. There is now an option to sort a database variable, but it will sort alphanumerically by the _keys_, not by the _values_, and in any case it treats it as a string value, not a numerical value.

There are a couple of possible solutions. I assume that ultimately you want "heart", not "heart=8", correct? The first thing that comes to mind is to create a simple stringlist of the keys in the order you desire. Stringlists, unlike database variables, do maintain the order in which you create the values. If your database variable above is named @dbvar, you can make an alias something like the following (untested!)
Code:

#LOCAL $tempdb $curkey $curindex $outlist $nextindex
$tempdb = @dbvar
#WHILE $tempdb {
  $curindex = 1
  $nextindex = 1
  $curkey = %dbkey($tempdb,1)
  $curval = $tempdb.1
  #WHILE ($nextindex < %numkeys($tempdb)) {
    $nextindex = ($nextindex + 1)
    #IF ($curval > $tempdb.$nextindex) {
      $curkey = %dbkey($tempdb,$nextindex)
      $curval = $tempdb.$nextindex
      $curindex = $nextindex
    }
  }
  $outlist = %addkey($outlist,$curkey,$curval)
  $tempdb = %delnitem($tempdb,$curindex)
}
@outlist = $outlist

Note that I'm not certain whether %delnitem will work on a db variable. I wrote this code in such a way as to allow multiple entries with the same key value, e.g. both "heart=8" and "heart=108" in the same list. If that does not happen, there are other ways to write it which would simplify things and you could use #DELKEY instead.
Reply with quote
Stowslee
Wanderer


Joined: 20 Apr 2008
Posts: 69
Location: Watervliet, NY

PostPosted: Sat Oct 01, 2011 12:48 am   
 
I'll try to go into greater detail.

When I check my inventory I have a trigger that collects the information regarding how many of each item I currently possess. As this rapidly changes, its a useful tool for quickly checking how many of each item on hand. Since I have the ability to harvest the items myself, I was hoping to use the information from an array and compare the values. Somehow sorting the elements in the array so that I collect the items that I have fewer of first.

And you are correct, the items that I would refer to would be Heart, Liver, Spleen, etc... So the actual number doesn't have to be in the sorted list as long as the order is correct. I'll take a look at the code you wrote up and see if I can make something like that work.
Reply with quote
Daern
Sorcerer


Joined: 15 Apr 2011
Posts: 809

PostPosted: Sat Oct 01, 2011 2:14 am   
 
If you're just trying to find out which you have least of, you can use %min and %dbvalues. Something like (untested) %dbkey(@var, %isvalue(@var, %min(%dbvalues(@var)))) should work.
Reply with quote
Stowslee
Wanderer


Joined: 20 Apr 2008
Posts: 69
Location: Watervliet, NY

PostPosted: Sat Oct 01, 2011 4:09 am   
 
From the two replies I think I have come up with a solution that will work. Only one question (and I may have it figured out by the time a response is posted). When looping through a database how would I remove items that do not contain the string "slice"?

Again, thank you for the assist. Greatly appreciated!
Reply with quote
Daern
Sorcerer


Joined: 15 Apr 2011
Posts: 809

PostPosted: Sat Oct 01, 2011 4:17 am   
 
You can use the %pos function to see if slice is in the key. Something like #IF !%pos("slice", %key) {#DELKEY var %key}.
Reply with quote
Stowslee
Wanderer


Joined: 20 Apr 2008
Posts: 69
Location: Watervliet, NY

PostPosted: Sat Oct 01, 2011 4:22 am   
 
Works perfectly, just have to put it all together now. And now I know you can use the ! in other areas then just !=
Reply with quote
Stowslee
Wanderer


Joined: 20 Apr 2008
Posts: 69
Location: Watervliet, NY

PostPosted: Sun Oct 02, 2011 3:31 am   
 
Well... ran into another seeming roadblock with this script. What I have done is created a database record @Cache. I then use a script to remove all the excess items I don't actually want to utilize when running the harvest script, in essence creating an altogether "new" @Cache. That part works perfectly, it only lists what I want to have in it. The part that I am having issues with now is the final comparison script that determines what order to collect in. The following is the code that I am using, which works fine as long as there is only one #if statement. If I use a nested #if statement it all the sudden starts acting strange. Deleting multiple keys that should have nothing to do with what is being called upon, or doing nothing at all.

This Works:
Code:

#LOOPDB @Cache {
#if (%min(@Cache) = %db(@Cache,bladder slice) and %ismember(Bladder, @AvailableOrgans)) {%delkey(@Cache, bladder slice); #ADDITEM @DissectPriority Bladder} }


This does not:
Code:

#LOOPDB @Cache {
#if (%min(@Cache) = %db(@Cache,bladder slice) and %ismember(Bladder, @AvailableOrgans)) {%delkey(@Cache, bladder slice); #ADDITEM @DissectPriority Bladder} {#if (%min(@Cache) = %db(@Cache,Heart slice) and %ismember(Heart, @AvailableOrgans)) {%delkey(@Cache, bladder slice); #ADDITEM @DissectPriority Heart} }}


And yes I realize this is probably not the most efficient way to go about this, still learning.
Reply with quote
Daern
Sorcerer


Joined: 15 Apr 2011
Posts: 809

PostPosted: Sun Oct 02, 2011 4:17 am   
 
Few things here... first of all, it would be better to avoid having spaces in your key names, perhaps replacing them with an underscore. Some things won't work properly if there's spaces in your key names, and at the very least I would put them in quotes when using them to make sure it's interpreted as one entity. Secondly, %delkey doesn't actually modify the variable. It just returns the variable with a record deleted, and you're currently not doing anything with that returned variable. Cache = %delkey(@Cache, bladder slice) would take that modified variable and assign it back to Cache, or you could use #DELKEY instead, which actually does modify variables. The last thing that jumps out as me is your #ADDITEMs - you shouldn't have the @ before @DissectPriority. #ADDITEM DissectPriority Bladder means add Bladder to the DissectPriority variable; #ADDITEM @DissectPriority Bladder means add Bladder to the contents of the DissectPriority variable, i.e. add Bladder to bladder|heart|etc (if you look in your package editor, you'll probably notice a few variables with weird names like this).

Next point, it doesn't really make sense to put this in a #LOOPDB. All you're doing is executing the exact same code several times. Am I correct in guessing that you're trying to find the lowest item in Cache that is also in AvailableOrgans? If that's the case, I think it would be best to loop through the AvailableOrgans variable instead (a #FORALL loop would be good here). Keep a tracker of the lowest key/value pair you've found in Cache so far, and for each item in AvailableOrgans, check if that item in Cache is less than what you have in your tracker variables - if it is, store that new one in the tracker variables. Of course, I'd be glad to provide sample code if you want, just let me know Smile.
Reply with quote
Stowslee
Wanderer


Joined: 20 Apr 2008
Posts: 69
Location: Watervliet, NY

PostPosted: Sun Oct 02, 2011 5:17 am   
 
That is exactly what I am trying to do, and each time it finds the lowest key/value pair I was "deleting" that entry so that it would find the next lowest and so on. Eventually ending up with the DissectPriority in order with the lowest value first and highest last. Sorry for all the questions on this, its my first attempt at something of this complexity and between switching to CMud less then a week ago and having limited experience to begin with... its a challenge to say the least. I'll see what I can come up with after reading the help on the new commands and testing some things out.

As far as I am aware based on how I collect the information, not sure that the spaces are avoidable. Its one of those codes that once I got it to work, I left it alone.

Code:

<trigger name="CacheTrack" priority="3430" regex="true" enabled="false" id="343">
  <pattern>^\s+\[\s*(\d+)\] ([\w+ ']+?)(?:\s+\[\s*(\d+)\] ([\w+ ']+?))?(?:\s+\[\s*(\d+)\] ([\w+ ']+?))?$</pattern>
  <value><![CDATA[#addkey Cache {%2} {%1};#IF (%1) {#IF (%1 < 250) {#PCOL mxpred %x1} {#if (%1 <= 1000) {#PCOL mxpyellow %x1} {#IF (%1 > 1001) {#PCOL mxpgreen %x1}}}};#if (%4) {#addkey Cache {%4} {%3}};#IF (%3) {#IF (%3 < 250) {#PCOL mxpred %x3} {#if (%3 <= 1000) {#PCOL mxpyellow %x3} {#IF (%3 > 1001) {#PCOL mxpgreen %x3}}}};#if (%6) {#addkey Cache {%6} {%5}};#IF (%5) {#IF (%5 < 250) {#PCOL mxpred %x5} {#if (%5 <= 1000) {#PCOL mxpyellow %x5} {#IF (%5 > 1001) {#PCOL mxpgreen %x5}}}}]]></value>
</trigger>


It collects this:
Code:
Glancing into the cache, you see:
  [ 208] bladder slice      [ 157] blue ink           [ 170] bone slice       
  [ 936] castorite slice    [  48] cloth              [ 830] eyeball slice   
  [  15] gold ink           [ 105] green ink          [ 389] heart slice     
  [   8] iron               [1330] kidney slice       [ 130] leather         
  [ 600] liver slice        [ 140] lung slice         [  12] ovary slice     
  [ 319] pineal slice       [ 871] purple ink         [ 333] red ink         
  [   2] rope               [ 326] spleen slice       [ 272] stomach slice   
  [  96] sulphurite slice   [1466] testis slice       [ 364] tongue slice     
  [ 661] tumor slice        [ 309] yellow ink       


Last edited by Stowslee on Sun Oct 02, 2011 5:33 am; edited 1 time in total
Reply with quote
Daern
Sorcerer


Joined: 15 Apr 2011
Posts: 809

PostPosted: Sun Oct 02, 2011 5:31 am   
 
The main problem with your code, then, is that it's not actually deleting any entries, so it'll find the same minimum every time. I'm not sure what would happen if you try to delete entries from a database variable in the middle of a #LOOPDB on it either, for that matter, but I imagine it could cause issues. A better approach to avoid that problem would be to store the initial size of @Cache in a local variable (you can use %numitems to find that), then use #LOOP instead of #LOOPDB to just loop that many times. That would be the simplest solution I think, requiring very little change to your existing code.
Reply with quote
Display posts from previous:   
Post new topic   Reply to topic     Home » Forums » CMUD General Discussion All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

© 2009 Zugg Software. Hosted by Wolfpaw.net