Announcement

Collapse
No announcement yet.

The revised Diplomacy Model: Coding Discussion

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • The revised Diplomacy Model: Coding Discussion

    I think it would be better to have the coding discussions separate from the concept discussions, because that way the people, who just care about the ideas, and do not want to concern themselves with the specifics of code, do not have to sort through the technical posts.

    First of all, I would like to respond in more detail to Laurent:

    Originally posted by LDiCesare
    Having attitudes/status ranked between -10 and 10 is OK if we need figures, but objects might be more appropriate.
    OK, I have thought about it, and here is how I think it is going to work:
    There will be a certain abstract class DiplomaticStatus, which will contain constant definitions for the name of the diplomatic status and the weight, or strength, of it, and possibly a short description. It will also have definitions for accessors (getters, I think they are also called) for these fields. It will also have subclasses, which will actually have the constants initialized to specific values. That way, we have diplomatic statuses represented as objects, and yet preserve the wieghts. The structure will also be the same for attitudes.

    As a little side note: I think that weights are, in fact, important for such a model because that would make the coding of other things much simpler. For instance: let us say I am coding some method gaveGift(), which will handle the attitude of one nation towards another if the latter gave the former a big gift of whatever. In the code I really don't want to say something like:
    Code:
    if currentAttitude == DeepHatered
        setAttitude(Fury)
    else if currentAttitude == Fury
        setAttitude(Anger)
    
          ...
    
    else if currentAttitude == Philantropy
        setAttitude(BrotherlyLove)
    That is ugly, annoying, and if we choose to add / remove an attitude, I would have to edit the code. Note also, that since there will be more than one method that affects attitude, I would have to edit this stuff in each and every one of them. In addition to me being lazy, there is another reason for not doing things that way: you can easily miss stuff, when editing code like that. And that would lead to nasty bugs, that will be really hard to track. What I really want to say is:
    Code:
    setAttitude(currentAttitude.getStrength() + 2)
    That is more robust, less code, and I don't have to edit it any more if we choose to redefine the attitudes.

    That's how I see the attitudes and diplomatic status implemented. What do you think of such model, Laurent? (I would certainly appreciate comments from other people, too, if you are interested.)
    Last edited by vovan; January 11, 2003, 16:36.
    XBox Live: VovanSim
    xbox.com (login required)
    Halo 3 Service Record (I fail at FPS...)
    Spore page

  • #2
    The design seems OK. I just want to avoid having figures instead of objects when they are not needed. If they are indeed useful, just go ahead.
    Though you could code it thus:
    setAttitude(currentAttitude.nextBetterAttitude());

    This allows managing limit situations like avoiding an attitude of 10 reaching 12 and eventually 999.

    Of course, the nextBetterAttitude() method I suggest requires either a table somewhere based on figures or a sorted list of sorts.
    I also think the 0 figure is important in some cases and we may often check things in the code like (attitude > 0) which would be easier to read if it was (attitude.isFriendly()).
    Clash of Civilization team member
    (a civ-like game whose goal is low micromanagement and good AI)
    web site http://clash.apolyton.net/frame/index.shtml and forum here on apolyton)

    Comment


    • #3
      Originally posted by LDiCesare
      I just want to avoid having figures instead of objects when they are not needed. <snip> I also think the 0 figure is important in some cases and we may often check things in the code like (attitude > 0) which would be easier to read if it was (attitude.isFriendly()).
      Makes perfect sense. I will make it so
      XBox Live: VovanSim
      xbox.com (login required)
      Halo 3 Service Record (I fail at FPS...)
      Spore page

      Comment


      • #4
        OK, so as I am moving closer to the point where I have to make the diplomacy model work with the existing code, I am wondering about one point.

        So, we have this concept of diplomatic relations. Or, rather the status of diplomatic relations. As in war, peace, and alliance. Now, that is all fine and dandy, but I am wondering, what would be an efficient way of storing that information? There are several ways I can think of, but I don't particularly like any of them.

        Of course, we can have a certain structure as a property of each civilization, which would hold the data about diplomatic statuses with every other nation. Although with this approach it might be a little faster to fetch the data, this is not good in terms of storing efficiency. For one thing, we are storing twice as much information as we actually should (after all, if civA is in war with civB, isn't the reverse also necessarily true? Therefore, why store that info twice - once in civA's attribute, and the second time in civB's attribute.). Secondly, when a state changes, when need to make sure to change it in two places instead of one.

        So, then we need to have a single object , and have it store the relations of all civs.

        Then the question arises: how is this repository going to store the data?

        Well, the easiest idea is to have a 2-D array, and have it stored something like this:

        Code:
        +------+------+------+------+-----+------+
        | ---- | civ1 | civ2 | civ3 | ... | civN |
        +------+------+------+------+-----+------+
        | civ1 | ---- | peace| war  | ... | peace|
        +------+------+------+------+-----+------+
        | civ2 | ---- | ---- | ally | ... | war  |
        +------+------+------+------+-----+------+
        | civ3 | ---- | ---- | ---- | ... | ally |
        +------+------+------+------+-----+------+
        | ...  | ---- | ---- | ---- | --- | peace|
        +------+------+------+------+-----+------+
        | civN | ---- | ---- | ---- | ... | ---- |
        +------+------+------+------+-----+------+
        Of course, with that set-up, only half of the matrix is used. The other half just wastes space. Concerning that, we can institute a fix like this:

        Code:
        +------+------+
        | civ2 | peace|
        +------+------+------+
        | civ3 | war  | ally |
        +------+------+------+------+
        | ...  | ...  | ...  | ...  |
        +------+------+------+------+-----+
        | civN | peace| peace| ally | ... |
        +------+------+------+------+-----+
        Since with Java, 2-D arrays don't have to be square, that is technically possible.

        And finally, yet another possible way would be to implement a hashtable, in which for every value - diplomatic state - there are two keys - the civs between which the state exists. That might be the most elegant solution, but I am not quite sure about it.

        So, if any of you coders out there have any ideas, feel free to share.
        Last edited by vovan; January 14, 2003, 23:32.
        XBox Live: VovanSim
        xbox.com (login required)
        Halo 3 Service Record (I fail at FPS...)
        Spore page

        Comment


        • #5
          Hi Vovan:

          Originally posted by vovansim
          Of course, we can have a certain structure as a property of each civilization, which would hold the data about diplomatic statuses with every other nation.
          I think this one is best. The size of diplomatic state storage is such an infinitesimal fraction of program memory that it is really IMO a) irrelevant and b) premature optimization.

          I can also see cases where CivA may want to have a state of War with civ B, but doesn't want to tell B until the surprise attack is launched. In such a case Civ A would for one phase, have War with B while B might have peace with A.

          Anyway that's my $0.02!
          Project Lead for The Clash of Civilizations
          A Unique civ-like game that will feature low micromanagement, great AI, and a Detailed Government model including internal power struggles. Demo 8 available Now! (go to D8 thread at top of forum).
          Check it out at the Clash Web Site and Forum right here at Apolyton!

          Comment


          • #6
            I think this one is best. The size of diplomatic state storage is such an infinitesimal fraction of program memory that it is really IMO a) irrelevant and b) premature optimization.
            Indeed the size of data is irrelevant BUT the other point made by vovan is much more important: you have to do the same thing twice. And that is EVIL.

            Now,
            I can also see cases where CivA may want to have a state of War with civ B, but doesn't want to tell B until the surprise attack is launched. In such a case Civ A would for one phase, have War with B while B might have peace with A.
            this is the important question. And, Mark, I disagree. You can prepare for war while being in peace. While your internal agenda says you are going to go to war, you probably want to be in peace with your opponent. So to me, the diplomatic state is bilateral, whereas the internal opinion and choices are not reciprocal. I am not sure the internal state of relation needs be checked.
            Now if not being bilateral had some use (other than for the ai, and I think the ai doesn't need it), what use zould it have for the player? I can't see any.

            And finally, yet another possible way would be to implement a hashtable, in which for every value - diplomatic state - there are two keys - the civs between which the state exists. That might be the most elegant solution, but I am not quite sure about it.
            I must confess I really like hashtables (though in java, HashMap is the name, as HashTables are synchronized, which we don't need). Considering civs can be added dynamically during the game, and some disappear, I think it is the most flexible data structure in order to add/remove new entries. Plus it is fast, and actually won't take much more space than any other solution, maybe even less.
            Clash of Civilization team member
            (a civ-like game whose goal is low micromanagement and good AI)
            web site http://clash.apolyton.net/frame/index.shtml and forum here on apolyton)

            Comment


            • #7
              I agree with Laurent in that we need to decide what we are going to use the diplomatic state for. On the one hand, we can use it for almost purely diplomatic purposes, as he suggested, and as I had originally thought. That way, it is clear that the notion of diplomatic state is strictly two-way: if one nation is in war with another, it necessarily follows that the latter is in war with the former. Or, civA is in war with civB iff (if-and-only-if) civB is in war with civA.

              On the other hand, we could use the diplomatic status data mostly for the AI's use, as Mark suggests. That would work for the AI's advantage like this: some high-level AI class decides that it is time to kick the behind of a neighbor. It then uses the diplomatic status to essentially tell the low-level military AI to gather forces and move them towards the neighbor's borders. Then, when the class that issues unit orders calls some findEnemy() method, it will get the neighbor's civ in return, since it thinks that the state of affairs is now war. Of course, the neighbor has no clue about the coming attack, since he thinks that the state of affairs is peace. Then, once the aggressor's forces attack, the victim changes his diplomatic status to war also.

              I can see how this can be useful for the Ai to make sneak attacks and what not. But this raises one important concern: the problem comes in when there appears a human player. (Well, as a matter of fact, not necessarily a human player, but rather a third party.) This third nation is also making some plans for dominance, and is thinking of who to attack first. Now, they look at the state of affairs between the two earlier nations, and what do they see? One nation thinks they are in war, the other - that they are in peace. Well, if it's a player, he'll just say that the AI's gone nuts. But seriously, with such a situation, how do we determine what kind of information a third party gets?

              There might also be some other difficulties with such approach, so I think we shouldn't mix the concepts here, leave the AI alone for now, and assume that the diplomatic state between two nations is the same from both points of view.
              XBox Live: VovanSim
              xbox.com (login required)
              Halo 3 Service Record (I fail at FPS...)
              Spore page

              Comment


              • #8
                Originally posted by LDiCesare
                I must confess I really like hashtables (though in java, HashMap is the name, as HashTables are synchronized, which we don't need). Considering civs can be added dynamically during the game, and some disappear, I think it is the most flexible data structure in order to add/remove new entries. Plus it is fast, and actually won't take much more space than any other solution, maybe even less.
                So, I suppose then you would recommend this approach? See, I was also thinking it would be the best, but then of course, I wouldn't be able to use the HashMap provided with java, since there is only one key for each value. What we need is a combination of two keys for each value, since each diplomatic state involves two nations. So, I was wondering how would we combine two Civ classes into one, so that the result conforms to the following rules necessary to preserve the functionality:
                1. civA + civB produces the same output as civB + civA
                2. No two combinations produce the same result.

                After we got the combination, we can use that as a key for the table and be done with it. But since I don't quite see how that would work - though if somebody came up with an idea of how to add civs, that'd be cool, - I suppose what I would need to do is just implement a hashtable on my own, that uses two keys for each value instead of one. It's not that complicated, but might be quite a bit less efficient than the java hashtable. Then again, I can try to inherit from the built-in hashtable, and try to tweak just the appropriate functions, but once again, I am not quite sure yet how that would work. Any way, suggestions on the implementation of that would be great.
                XBox Live: VovanSim
                xbox.com (login required)
                Halo 3 Service Record (I fail at FPS...)
                Spore page

                Comment


                • #9
                  I guess Laurent is right that for a sneak attack you will indeed be at peace, but have an internal AI knowledge that you are preparing for a sneak attack. That does seem the right way to work it. As for the implemenation details, I'm agnostic.
                  Project Lead for The Clash of Civilizations
                  A Unique civ-like game that will feature low micromanagement, great AI, and a Detailed Government model including internal power struggles. Demo 8 available Now! (go to D8 thread at top of forum).
                  Check it out at the Clash Web Site and Forum right here at Apolyton!

                  Comment


                  • #10
                    Originally posted by vovansim
                    So, I suppose then you would recommend this approach?
                    Yes
                    See, I was also thinking it would be the best, but then of course, I wouldn't be able to use the HashMap provided with java, since there is only one key for each value. What we need is a combination of two keys for each value, since each diplomatic state involves two nations. So, I was wondering how would we combine two Civ classes into one, so that the result conforms to the following rules necessary to preserve the functionality:
                    1. civA + civB produces the same output as civB + civA
                    2. No two combinations produce the same result.
                    Exactly. The same result means both hashcode and equals method are consistent.
                    After we got the combination, we can use that as a key for the table and be done with it. But since I don't quite see how that would work - though if somebody came up with an idea of how to add civs, that'd be cool, - I suppose what I would need to do is just implement a hashtable on my own, that uses two keys for each value instead of one. It's not that complicated, but might be quite a bit less efficient than the java hashtable. Then again, I can try to inherit from the built-in hashtable, and try to tweak just the appropriate functions, but once again, I am not quite sure yet how that would work. Any way, suggestions on the implementation of that would be great.
                    NO!! (abuse but I like that smiley)
                    You just use HashMap with a clever key, it is as you described, it looks like that:
                    You just have to take care with the equal (or is it equals?) method:
                    public class Key
                    {
                    private Civilization civ1;
                    private Civilization civ2;
                    public Key(Civilization civA, Civilization civB)
                    {
                    civ1 = civA;
                    civ2 = civB;
                    }
                    public int hashcode()
                    {
                    return civ1.hashcode() + civ2.hashcode();
                    }
                    public boolean equal(Object other)
                    {
                    if (other instanceof Key)
                    {
                    if (other == this)
                    return true;
                    if ((civ1 == other.civ1) && (civ2 == other.civ2))
                    return true;
                    if ((civ1 == other.civ2) && (civ2 == other.civ1))
                    return true;
                    }
                    return false;
                    }
                    }
                    Change Key by something meaningful, put it into a HashMap, don't bother what order civ1 and civ2 are fed to you and voila.
                    It is MUCH simpler than recoding a HashMap.
                    Clash of Civilization team member
                    (a civ-like game whose goal is low micromanagement and good AI)
                    web site http://clash.apolyton.net/frame/index.shtml and forum here on apolyton)

                    Comment


                    • #11
                      Yes, that's exactly what I meant when I said we could combine the two civs and use that as a key. Thanks, Laurent
                      XBox Live: VovanSim
                      xbox.com (login required)
                      Halo 3 Service Record (I fail at FPS...)
                      Spore page

                      Comment


                      • #12
                        Just a quick note:

                        We need to change the diplo panel into a scrollable pane. In the Ancient Middle East scenario I'm working on (which has 26 civs), the panel extends so far south I wouldn't be able to use it were it active.

                        Comment


                        • #13
                          That one should be fairly simple to do. It's more of a placeholder than anything right now though, as it just gives statuses which, I believe, don't change during the game.
                          Clash of Civilization team member
                          (a civ-like game whose goal is low micromanagement and good AI)
                          web site http://clash.apolyton.net/frame/index.shtml and forum here on apolyton)

                          Comment


                          • #14
                            Diplomacy AI

                            I'm just writing to get some discussion on how to handle the diplomacy AI. To have any sort of realism and intelligence in diplomacy, you're going to have to track several "attitude" variables, in addition to ranking variables and a few other misc. variables. Some will need to be tracked locally by each civ, some globally for all AI civs to use, and some tracked both locally and globally

                            Attitude Variables
                            Attitude variables are used to measure the AI's “feelings” towards other civs. The variable names are pretty self-explanatory. Following are some obvious ones:
                            Generosity
                            Aggressiveness
                            Trustworthiness
                            Loyalty

                            Each AI civ will need to track these for each civ they have contact with. These variables will be biased by the civ in question. For example a non-generous civ will view other civ's generosity less favorably than a civ with high generosity would. Because of the bias, we need to track a “second opinion” as well – that is an unbiased global record of these “attitude” variables. Therefore each civ will store it's own, accurate, global record, with aggressiveness rising for each aggressive action, generosity rising for generosity, trustworthiness lowering for traitorous acts, etc. This will allow CivA, a non-generous civ (which it gets from the global generosity variable it stores of it's own actions), to view another civ's generosity (a gift in diplomacy, for example), less favorably than a civ with high generosity would (i.e. It now sees the gift giver as +1 generosity than it did the turn before, whereas a more generous civ would see the gift giver as +5 greater than the previous turn). Access to the global variables should probably be considered 'low-level' spying by the diplomacy model, and there should be some minimal charge for it. If the AI has contact with only one civ, it should not be able to access (nor get charged, obviously) the global variables, since it knows of no other civ to ask, “Hey, is that other civ loyal? Aggressive?” etc. The human player should have access to these values as well.

                            Ranking Variables
                            Ranking variables simply give the power level of a civ in a single area. For example, a civ might rank #1 in military, #3 in economy, #9 in unrest, etc. This gives the AI (and players for that matter), a single variable to look at to judge relative differences between civs. If you've ever played a RTS game, you've seen ranking before. These are global variables, tracked once in the game. The number of areas ranked, should be relatively small (Military, Diplomacy, Economy, Technology, etc.), and these ranked areas should also be broken into ranked sub-areas (Military – Air, Navy, Army, etc.). This information should probably be considered 'low-level' spying by the diplomacy model, and there should be some minimal charge for it.

                            Misc. Variables
                            I've only got one at the moment, though I'm sure there are others I'm forgetting.

                            Priorities
                            Priority variables are very important to giving each Civ (can be extended to leaders as well) it's own personality. Basically, each civ will start with a set of priorities for each of the Attitude Variables, but they change throughout the course of the game based on in-game conditions. So at the start, CivA might rank Generosity 5, Aggressiveness 0, Trustworthiness 3 and Loyalty 4. This civ would naturally gravitate towards a friendly relationship with civs that share these “values”, or priorities. Priorities will act as multipliers to the bonuses and minuses given as explained under Attitude Variables. These can be, initially, derived from a civs cultural & religious values, sometimes directly, sometimes indirectly.

                            Comment


                            • #15
                              I generally agree with attitude variables, but I don't like rankings. I would rather get a score system than a rank system, but even then, the perceived score (military might:1000) is something that would depend on spendings.
                              The current system I have keeps track of all values of a civ that another civ saw, but doesn't extrapolate in time. I mean: Economic value of a square is known if the square is seen. If it has been seen once, then the value is know, and an extrapolation can be made, which, averaged over all squares, provides the economic value of a given civ.
                              Clash of Civilization team member
                              (a civ-like game whose goal is low micromanagement and good AI)
                              web site http://clash.apolyton.net/frame/index.shtml and forum here on apolyton)

                              Comment

                              Working...
                              X