[V] Question on Extracting Monster Power

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • nullfame
    Adept
    • Dec 2007
    • 167

    [V] Question on Extracting Monster Power

    I've become very interested in a monster power calculation which I mentioned in passing in another thread. Magnate asked me to look at eval_r_power in init1.c and pointed me at ticket 869, review and revise said algorithm. I've read the algorithm pretty closely and though I don't have any specific suggestions (yet!) I noticed a few omissions (e.g., ARROW_1-4) and likely errors (e.g., if (rsf_has(r_ptr->spell_flags, RSF_TELE_LEVEL) && spell_dam < 40) spell_dam = 25; when I assume you would want the assignment to be 40 or the test 25). I don't think these minor issues are contributing to the power ratings being out of whack as described in the ticket but ironing those out seems like an obvious starting point before making suggestions.

    I just want to be able to print the monster list and their current power ratings so as I iron those issues out I can verify my results. I've written maybe 10 lines of C in my life but am quite comfortable with a number of descendants (especially PHP, Java, Perl, and JavaScript... I'll give you 1 guess as to what I do for a living). I'm on a Mac and can get it to compile which is always a bonus. I'm using r2035 for now.

    Reading the code I came across emit_r_info_index in init1.c which sounds like a real winner (once one realizes "r_info" refers to monsters... heh). So I tacked this on after the description:

    Code:
    file_putf(fp, "D:%d:%d\n",r_ptr->power, r_ptr->highest_threat);
    I also tried doing it as a comment before appending it to the description. Then over in init2.c I dropped the conditional from this line in init_r_info:
    Code:
    if (arg_rebalance) r_head.emit_info_txt_index = emit_r_info_index;
    I don't know if arg_rebalance is true or false (I assume) or what. I also tried explicitly setting it to true.

    So I build, launch, roll a character, take a turn in town, and quit assuming it would spit my new monster.txt out but that doesn't appear to be the case. Honestly I'm not even sure where to look (I assume in the "package contents" of Angband.app).

    Or, is this just a totally silly approach to begin? Am I missing something else fundamental?

    Don't ask me why my curiosity is so piqued by this obscure and utterly unimportant function and ticket with zero gameplay value. I like to think of myself as a special brand of crazy.
  • myshkin
    Angband Devteam member
    • Apr 2007
    • 327

    #2
    You were almost there...

    Originally posted by nullfame
    Then over in init2.c I dropped the conditional from this line in init_r_info:
    Code:
    if (arg_rebalance) r_head.emit_info_txt_index = emit_r_info_index;
    I don't know if arg_rebalance is true or false (I assume) or what. I also tried explicitly setting it to true.
    By default, arg_rebalance is true only if you give angband the command-line option -r. The Windows port supports setting this variable via an .ini file, but the Mac OS X port doesn't seem to have the same.

    So I build, launch, roll a character, take a turn in town, and quit assuming it would spit my new monster.txt out but that doesn't appear to be the case. Honestly I'm not even sure where to look (I assume in the "package contents" of Angband.app).
    It's in $HOME/Library/Preferences/Angband/monster.txt. Notice

    Code:
     /* Open for output */
    path_build(user_file, 1024, ANGBAND_DIR_USER, format("%s.txt", filename));
    in init_info() of init2.c. ANGBAND_DIR_USER gets defined earlier in init2.c, in init_file_paths().

    Code:
    #ifdef PRIVATE_USER_PATH
    
            /* Build the path to the user specific directory */
            path_build(buf, sizeof(buf), PRIVATE_USER_PATH, VERSION_NAME);
            ANGBAND_DIR_USER = string_make(buf);
    
    #else /* !PRIVATE_USER_PATH */
    
            ANGBAND_DIR_USER = string_make(format("%suser", datapath));
    
    #endif /* PRIVATE_USER_PATH */
    That definition relies on PRIVATE_USER_PATH, which, for you, is set in Makefile.osx:

    Code:
    CFLAGS = \
            -I. $(WARNINGS) -std=gnu99 $(OPT) -DMACH_O_CARBON -DHAVE_MKSTEMP \
            -DPRIVATE_USER_PATH=\"~/Library/Preferences\" -DUSE_PRIVATE_PATHS \
            -arch ppc -arch i386 -mmacosx-version-min=10.0

    Comment

    • nullfame
      Adept
      • Dec 2007
      • 167

      #3
      Originally posted by myshkin
      You were almost there...

      It's in $HOME/Library/Preferences/Angband/monster.txt.
      Ha! There is it. Grrr, and I was so proud of myself having stumbled that far along too. I even looked in there but was looking for an edit subdirectory and didn't notice it in my mess of dumps and preferences. Thanks for the help.

      Comment

      • andrewdoull
        Unangband maintainer
        • Apr 2007
        • 816

        #4
        Any errors are undoubtedly my fault - I updated the power calculation code at one point and problems like ARROW1-4 missing are inherited from the Unangband code.

        Andrew
        The Roflwtfzomgbbq Quylthulg summons L33t Paladins -more-
        In UnAngband, the level dives you.
        ASCII Dreams: http://roguelikedeveloper.blogspot.com
        Unangband: http://unangband.blogspot.com

        Comment

        • nullfame
          Adept
          • Dec 2007
          • 167

          #5
          Actually it's a nice piece of code and is more or less what I had in mind (scale for damage and HP, assign arbitrary values to non-damage spells). As a contributor, maybe I can ask you a question of intent: why is monster power scaled by level?

          The ticket compares the power of snagas (28) to uruks (24). Everything gets a (what I'm calling) "raw power" and then that is scaled to the average HP and average damage output of everything on previous levels. Snagas are scaled relative to centipedes, snakes, and yeeks. Probably the most dangerous thing you see beforehand is a green naga. So, naturally their power rating is high for their level. Uruks are scaled against early dragons, demons, and loner humans/elves. While their "raw power" (numerator) is higher than the snaga's the product of average monster damage and hp (denominator) grows much quicker in those early levels.

          I feel like a minor tweak to that calculation could make a difference, I just want to understand why it was done that way so I can factor that in to my proposal. Perhaps it's nothing more than keeping the power ratings within a smaller range of numbers.

          Comment

          • Derakon
            Prophet
            • Dec 2009
            • 8820

            #6
            I can come up with one explanation: it helps you to determine how valuable a given piece of anti-Foo equipment is at a given depth in the dungeon. Slay Orc weapons would be very useful when you first find Snagas since they're practically the most dangerous thing around. By the time you get to Uruks, you generally have more dangerous creatures around to deal with, so a Slay Orc brand isn't so helpful.

            Comment

            • Magnate
              Angband Devteam member
              • May 2007
              • 4916

              #7
              Originally posted by Derakon
              I can come up with one explanation: it helps you to determine how valuable a given piece of anti-Foo equipment is at a given depth in the dungeon. Slay Orc weapons would be very useful when you first find Snagas since they're practically the most dangerous thing around. By the time you get to Uruks, you generally have more dangerous creatures around to deal with, so a Slay Orc brand isn't so helpful.
              That's a fair point, and I find myself ambivalent about whether the power calc should rate snagas as more dangerous than uruks or not ... for their depth. I think the problem is that the power calc is sort of expected to represent the absolute power of the monster, i.e. wherever it's found. If you meet a snaga and an uruk together before you're powerful enough to ignore both, it's pretty obvious which one's more dangerous. This is the thinking behind the original algorithm (which has its roots in randart generation).

              Nullfame: how much hassle would it be to maintain two values of power, one for absolute and one modified for native depth? And by the way, huge congrats on working out as much as you did without help - that's way further than I got when I started. And thanks again for picking this up - I'm not sure it would ever have reached the top of my to-do list. I look forward to testing and committing it. Did you ever get the emitted monster.txt to show the power rating, btw? That would be a good start - but your next job is to get it to do that *without* rebalancing!
              "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

              Comment

              • nullfame
                Adept
                • Dec 2007
                • 167

                #8
                Originally posted by Magnate
                how much hassle would it be to maintain two values of power, one for absolute and one modified for native depth?
                I am glad you suggested this because it is what I am doing. IMO this will not be useful because, I believe by definition, raw_power will always be in the same order as scaled_power on the same level and they are meaningless on different levels, but I haven't fully fleshed out my thoughts on the subject.

                I was planning to submit my patch in two phases, unless you advise me otherwise:

                1. Changes I consider to be non-controversial: accounting for ARROW, BOULDER, SHRIEK, ESCORT, ESCORTS, HURT_LIGHT, and adjusting the aforementioned test/assignment inconsistencies. I have this diff ready to submit (on another machine). These will not close the ticket.

                2. Changes I think fix the problem but fundamentally alter the algorithm: using the sum of spell damage and melee damage instead of the max of the two, not scaling by level for the power value (but saving a scaled_power), using a constant overflow adjustment rather than by level (i.e., scaling by level again). I have this code written but haven't prepared a diff. I'm writing a detailed explanation my proposals for the few people that might be interested. Maybe this weekend.

                There may be other minor changes I'm missing but these are certainly the most important ones. I've looked a lot at how power and depth compare within a given monster symbol and that seems pretty consistent and when they are out of order it is usually because the power value is right (Bolg) or they are so close on depth or power that it really doesn't matter (low mushrooms). I haven't studied how the power value looks across symbols by depth but being right within a race is an encouraging sign.

                Comment

                • Magnate
                  Angband Devteam member
                  • May 2007
                  • 4916

                  #9
                  Originally posted by nullfame
                  I am glad you suggested this because it is what I am doing. IMO this will not be useful because, I believe by definition, raw_power will always be in the same order as scaled_power on the same level and they are meaningless on different levels, but I haven't fully fleshed out my thoughts on the subject.

                  I was planning to submit my patch in two phases, unless you advise me otherwise:

                  1. Changes I consider to be non-controversial: accounting for ARROW, BOULDER, SHRIEK, ESCORT, ESCORTS, HURT_LIGHT, and adjusting the aforementioned test/assignment inconsistencies. I have this diff ready to submit (on another machine). These will not close the ticket.

                  2. Changes I think fix the problem but fundamentally alter the algorithm: using the sum of spell damage and melee damage instead of the max of the two, not scaling by level for the power value (but saving a scaled_power), using a constant overflow adjustment rather than by level (i.e., scaling by level again). I have this code written but haven't prepared a diff. I'm writing a detailed explanation my proposals for the few people that might be interested. Maybe this weekend.

                  There may be other minor changes I'm missing but these are certainly the most important ones. I've looked a lot at how power and depth compare within a given monster symbol and that seems pretty consistent and when they are out of order it is usually because the power value is right (Bolg) or they are so close on depth or power that it really doesn't matter (low mushrooms). I haven't studied how the power value looks across symbols by depth but being right within a race is an encouraging sign.
                  This all sounds excellent - thanks for your work. I'm sure you're right about the depth thing: I think we might not need the scaled_power value, at least for my purposes (items) - though it might come in handy in dungeon generation one day.

                  In case it's helpful, here's the rest of my thinking when I created the ticket: my ultimate aim is to get rid of all the arbitrary power constants which are used to peg the values of various attack methods, spells etc. (These are not to be confused with the actual damage constants in monster/constants.h - those we can't get rid of.)

                  So ideally the power algorithm would be constructed in such a way that we can use the constants for the time being, and replace them with formulae piece by piece, as they become available. This is subject to the Pareto principle: using a formula for the power of breath damage is easy (so easy in fact that it's already there, IIRC), but calculating the power value of TELE_AWAY is probably unachievable - certainly more effort than it's worth.

                  Once you've done your first two stages, I'd be interested in your views on this ambition, and which values you think we could calculate.
                  "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                  Comment

                  • nullfame
                    Adept
                    • Dec 2007
                    • 167

                    #10
                    I'm not sure the right way to submit a patch (can I combine all the diffs in to one file somehow?) but here is a tar.gz with the two patches (edit: against 2041):

                    init1.c-AMF-p1.diff: just the non-controversial changes.
                    init1.c-AMF-p2.diff and types.h-AMF-p2.diff: the contents of the first patch and other changes I propose.

                    The non-controversial changes are accounting for a number of spells, fixing a few comparison/assignment inconsistencies, modifying for escorts (giving a small bonus than friends), and modifying for HURT_LIGHT.

                    My major changes are:

                    1. Not scaling the monsters by level. Instead the raw power is used for the power rating but a scaled_power value is still saved.

                    2. Prevent overflow consistently across all levels. There was code with the comment "use an adjustment factor to prevent overflow" with code that started dividing the power value by 100 at level 40, 10,000 at 65, and 1,000,000 at 95. I assume that was to prevent integer overflow. I think this would be better handled with a consistent value (what I've done) or maybe an exponential.

                    3. Add magic to melee, don't pick the maximum of the two. Spell power is scaled by frequency but melee power is not. This results in having 90% of monsters rated by melee alone. Monsters with spell casting abilities are simply more dangerous, especially when they can cast in addition to melee output.

                    Mostly I think it works. Here are a few strange outliers:

                    Death quasit < Storm giant
                    Castamir the Usurper < Aranea
                    Smaug the Golden < Elder aranea
                    Azriel, Angel of Death < The Cat Lord

                    I'm not sure what to do about the first one. It might even be right. The other 3, and a few other similar examples, says to me FRIENDS and ESCORTS are probably overvalued. And summon kin, while often dangerous, is non-threatening on a cat. That kinda brings to to Magnate's point:

                    Originally posted by Magnate
                    ideally the power algorithm would be constructed in such a way that we can use the constants for the time being, and replace them with formulae piece by piece, as they become available.
                    I like this and believe figuring some of that out should probably be undertaken before trying to tweak the flags above. You're gonna have arbitrary numbers here and there, but the more that is formulaic the more reference you have for choosing the arbitrary numbers.

                    I think you could calculate the value of summons and summon-esq spells (SHRIEK, TELE_AWAY) by looking at the danger levels of what is likely to be summoned. E.g., the most dangerous thing the cat lord can summon is a sabre-tooth tiger which isn't a major threat on dl66. Saruman can bring a lot of threats to the table on dl60. You would have to run through the list recalculating a few times.

                    Something like HASTE and HEAL probably don't belong with attack spells and can be removed. Some are hard to think about like FORGET but maybe with some thought you could pin it between two formulaic values (e.g., it's less dangerous than a frost bolt but more than ARROW_1). Blow effects like TERRIFY or LOSE_CON would need similar thought.

                    I would be willing to work further on it at some point, depending what people think.
                    Attached Files
                    Last edited by nullfame; September 6, 2010, 04:00. Reason: diffs are for 2041

                    Comment

                    • Derakon
                      Prophet
                      • Dec 2009
                      • 8820

                      #11
                      For your oddities:

                      Death Quasits are less dangerous than Storm Giants, I'll buy that. The quasits are fragile and the only really dangerous things they do are move through walls and drain your dexterity. Storm Giants can actually hurt you, though, with 2x 10d8 melee hits and some moderately dangerous spells (electric ball, teleport-to, though they're grossly outnumbered by 5 useless spells).

                      Azriel is a tricky one; IIRC he's a bit of a glass cannon. That said, he certainly has more killing potential than the Cat Lord. I would say that ESCORT should be scaled by some kind of weighted average of the expected danger level of the monster's buddies a) when he's in-depth, and b) when he's grossly out of depth (i.e. pick the nastiest possible escort). As you noted, the nastiest escort for the Cat Lord is a sabre-toothed tiger, which just isn't particularly scary. The nastiest escorts for Ancalagon are Great Wyrms and Dracoliches, which are fairly powerful in their own right.

                      I don't really get Smaug vs. elder aranea. I thought it was plausible until I saw that elder aranea only cast 1 in 6, which means that their nasty spells just don't show up before they die, even after you rescale that to 1 in 3 for the expected player speed at their native depth (dlvl 48).

                      Castamir vs. ordinary araneas I can't rate because I don't deal with either when they're in-depth.

                      Comment

                      • Magnate
                        Angband Devteam member
                        • May 2007
                        • 4916

                        #12
                        Nullfame, this looks excellent - thank you. I'll try and apply and test these and get back to you - RL is a bit rough at the moment so don't hold your breath, but I will definitely do it.

                        EDIT: without having looked yet, can you tell me if your patches include code to print the power ratings somewhere, like in monster.txt? (without rebalancing!)
                        "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                        Comment

                        • nullfame
                          Adept
                          • Dec 2007
                          • 167

                          #13
                          Originally posted by Magnate
                          can you tell me if your patches include code to print the power ratings somewhere, like in monster.txt? (without rebalancing!)
                          No but the attached (from 2041) includes my patches and debug code. I like to output the various factors of the formula (spell_power, melee_power, and hp_power) to give me an idea of where a creature's power is coming from. I save these values before some further adjustments happen so they aren't perfect, but give an idea. I work around rebalancing by just always calling emit_r_info_index, not just on rebalance. All my debug, which isn't much, is tagged with /*AMFEBUG*/

                          EDIT: The ZIP includes a spreadsheet showing my current monster power calculations.

                          Maybe I am just had some bad experiences on Death Quasits because they can really sneak up on you. My algorithm currently rates Ancalagon over Sauron, I believe because of the escort. Right now it is using a naďve constant multiplier to a monster's power (1.5 for ESCORT, 2 for ESCORTS) which appears too high. A legit calculation from the potential entourage would be a better rating.
                          Attached Files
                          Last edited by nullfame; September 6, 2010, 19:26. Reason: ZIP includes spreadsheet

                          Comment

                          • Magnate
                            Angband Devteam member
                            • May 2007
                            • 4916

                            #14
                            Originally posted by nullfame
                            No but the attached (from 2041) includes my patches and debug code. I like to output the various factors of the formula (spell_power, melee_power, and hp_power) to give me an idea of where a creature's power is coming from. I save these values before some further adjustments happen so they aren't perfect, but give an idea. I work around rebalancing by just always calling emit_r_info_index, not just on rebalance. All my debug, which isn't much, is tagged with /*AMFEBUG*/

                            EDIT: The ZIP includes a spreadsheet showing my current monster power calculations.

                            Maybe I am just had some bad experiences on Death Quasits because they can really sneak up on you. My algorithm currently rates Ancalagon over Sauron, I believe because of the escort. Right now it is using a naďve constant multiplier to a monster's power (1.5 for ESCORT, 2 for ESCORTS) which appears too high. A legit calculation from the potential entourage would be a better rating.
                            Excellent, thanks again. I'm with you on calculating escort power: it shouldn't be too hard, as we can call the summoning routine and do it empirically. What is the difference between ESCORT and ESCORTS?? And FRIENDS, for that matter?

                            I'm with Derakon: storm giants are considerably more dangerous than death quasits. Araneas are tough, but not especially dangerous. Elder araneas *are* pretty dangerous, and a pack is probably tougher than Smaug alone. Azriel/Cat Lord are fairly close IMO, so no worries there.
                            "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                            Comment

                            • Derakon
                              Prophet
                              • Dec 2009
                              • 8820

                              #15
                              Personally, I definitely consider Ancalagon to be more dangerous than Sauron, which is kinda weird now that I think about it. Ancalagon does nothing but bash away at your hitpoints with rather shocking speed. Sauron has a number of nasty tricks, but they're muffled a bit by the sheer number of spells he can cast (blind, brain smash, scare, teleport, icebolt, plasma bolt, summon monsters -- all not very dangerous spells).

                              Sauron also has no escort and only 500 more hitpoints than Ancalagon. For the escort, I generally don't have too much trouble separating a unique from his escort if I have to. Teleport-other is such a handy spell.

                              Comment

                              Working...
                              😀
                              😂
                              🥰
                              😘
                              🤢
                              😎
                              😞
                              😡
                              👍
                              👎