Announcement

Collapse
No announcement yet.

Turn management

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

  • Turn management

    The present turn management system just sort of evolved.

    Essentially, the latest version works as follows:

    1. Scan the list of units and make moves and resolve combat. [Scans the unit list]

    2. Do all the economics calculations, these cover production, trade and government orders (that I know of). The social model used to be resolved here, it is currently partially inactivated. [Scans the map squares and also the civilizations]

    3. Production. This is entirely road building at present. [Scans the civilizations]

    4. Population increase. [Scans the map squares]

    5. Check end of game.

    There are some changes to this that I would propose. I would like to resolve matters at the level that is required, rather than in an arbitrary order.

    We have three "scan levels". The units are scanned. This is outside the normal scanning mechanism - a complete list of units is maintained, and the units moved, more or less in order of age, until there is a conflict. There is a small possibility of an incorrect result here - if a unit is moving from square 1 to square 2 to square 3, and an enemy unit is moving from square 3 to square 2 to square 1, the possible conflict will be detected (and dealt with) at the square 2/3 boundary. If the second unit is faster, the conflict may have been more correctly resolved at the square 1/2 boundary. However, when the first unit is moved, the code doesn't know about the other unit, until the conflict happens, so it might get it wrong. Fixing this is on the list in place 1328.

    The second scan level is the individual squares. This is required for population growth and for resource production, and perhaps trade.

    The third level is the civilization scan, where things are done per civilization. This covers the whole social model and some economic decisions, as well as the AI.

    As a policy, I prefer to put loops in positions where the code knows what it is looping over, rather than passing mysterious iterators around the place. There are a variety of advantages to this - it reduces dependencies (my battlecry!), and means that many changes are restricted to a single java file.

    For example, at present the civilization iterator is called (from whereever) to get the list of civilizations, then a specific method called on each of them. It is my view that the iteration should be done in a loop in a static method in the civilization file.

    The system I would propose is as follows:

    1. Military phase Scan the list of units and make moves and resolve combat. [Scans the unit list] Unchanged.

    2. End of game phase Check end of game. Can only happen as a result of military action anyway.

    3. Square phase Scan the squares (once only), do the resource production, the population feeding, and the population growth, and store any surplus resources for action by the owning civilization. Trade may be dealt with at this point also. Infrastructure will be stored at the square level and checked here.

    4. Civilization phase Scan the civilization list. For each civilization perform the following:

    4.1 Province phase Scan at the province level:

    4.1.1 Grab any taxes.
    4.1.2 Perform any government purchases.
    4.1.3 Assess the social aspects of the province (storing some results at the government level).
    4.1.4 Implement any riot events.

    4.2 Government phase Perform government level actions:

    4.2.1 Build roads
    4.2.2 Implement any government level social events (such as assassinating the ruler).
    4.2.3 Interactive phase Make decisions relating to social matters, purchase or other economic decisions, military decisions.

    The interactive phase, for the human player, is section 4.2.3. For computer controlled civilizations, these decisions will be made by the AI before the interactive phase begins.

    I rather think that the only changes of any significance will be in storing resources for use later in the same move, but Mark will have a better idea of this than I. The advantage of that is it clearly separates the production aspect from the use aspect.

    Cheers

  • #2
    Hi Gary:

    I'm not really worth much mentally at the moment, so I won't comment in depth. I need to think about what you are saying in depth and compare it to what I was going with.

    But I have two items I want to bring up that IMO are worth injecting into the discussion early. The model that at least I was assuming is one in which the models are run in a prescribed sequence. That is the one with iterators over civs that you dislike. It was orginally formulated quite a while ago, and is described in the second post of the Turn Handler dev discussion thread. There are reasons that I feel rather strongly about for having the models run in something like the order given in the link, although some places in the sequence are less important than others. At present I think getting the models all working in an order that promotes good gameplay should take precedence over what makes the code more bulletproof. If we can satisfy the latter, consistent with not making a horrible mess of the former, then I guess that'd be ok with me.

    Whatever the decision we should come to, I would prefer to wait quite a bit to let the dust settle on all the other changes before moving into yet another major refactoring...
    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


    • #3
      This is not a major refactoring at all. It is a rather minor change, rather aimed at bringing similar things together.

      The actual implementation of all the civilization related things is by calls in the civilization object. The code which does this is all in the Economics model at present. This is certainly not the place for many of these methods.

      In the code list I have removed the code which relates to displaying the human player's data. Clearly, if it were done by civilization, sorting out the extra display material for just that civilization will be much easier if the loop is by civilization. Also, such a system would allow for a later expansion to multiple players without modification. The end of turn check is also remived, since it is used only for the human player.

      I have also removed the movement method which is the same in both versions.

      Here is the present code (with some debugging code removed).

      In TurnManager.java: (40 lines)

      Code:
        /**
         * Thread running method.
         */
        public void run() {
          socialModel();
          movement();
          economics();
          production();
          population();
          TurnId.increment(5);
        }
      
        /**
         * Perform the economics operations for a turn.
         */
        private void economics() {
          Economics.allEconomicsTurns();
        }
      
        /**
         * Perform the social model operations for a turn.  Includes
         * primarily government and ethnic group operations.
         */
        private void socialModel() {
          SocialModel.allSocialModelTurns();
        }
      
        /**
         * Perform the production operations for a turn.
         */
        private void production() {
          Economics.allProduction();
        }
      
        /**
         * Perform the population operations for a turn.
         */
        private void population() {
          Economics.allPopulationTurns();
        }
      And the code in Ecomonics.java: (74 lines)

      Code:
        /**
         * Perform one turn's economics for all civilizations.
         */
        static public void allEconomicsTurns() {
          for (Iterator iterator = Civilization.iterator(); iterator.hasNext(); ) {
            Civilization civ = (Civilization)iterator.next();
            civ.economicsTurn();
            civ.getCivEconomy().econTurnCompleted();// to update frames
          }
      
          allMerchantActions();
      
          // Set orders for new units
          Units.issueOrders();
      
          SocialModel.allSocialModelTurns();
        }
      
        /** Handle merchant bookeeping and contract search activities here*/
        static public void allMerchantActions(){
      
          Merchant tempMerchant;
          Civilization pCiv = Player.getCiv();
      
          for (Iterator iterator = Civilization.iterator(); iterator.hasNext(); ) {
            Civilization civ = (Civilization)iterator.next();
      
            collectMerchantProfitsInCiv(civ);
      
             Iterator merchantIter =
            civ.getCivEconomy().getAllMerchantsWithHomeHere() ;
      
            // find new contracts
            while(merchantIter.hasNext()){
              tempMerchant = (Merchant) merchantIter.next();
      
              if(Rand.nextFloat() > 0.5) tempMerchant.findNewContract();
            }
      
          }// iter over civs
        }
      
          static private void collectMerchantProfitsInCiv(Civilization civ){
            Merchant tempMerchant;
      
            Iterator merchantIter =
            civ.getCivEconomy().getAllMerchantsWithHomeHere() ;
      
            // collect profits
            while(merchantIter.hasNext()){
              tempMerchant = (Merchant) merchantIter.next();
              tempMerchant.collectProfitsFromAllMerchantContracts();
            }
          }
      
        /**
         * Perform one turn of population change.
         */
        static public void allPopulationTurns() {
          for (Iterator iterator = Civilization.iterator(); iterator.hasNext(); ) {
            Civilization civ = (Civilization)iterator.next();
            civ.populationTurn();
          }
        }
      
        /**
         * Perform one turn of production.
         */
        static public void allProduction() {
          for (Iterator iterator = Civilization.iterator(); iterator.hasNext(); ) {
            Civilization civ = (Civilization)iterator.next();
            civ.getGovernment().productionCycle();
          }
        }
      Placing all this in a single loop leads to code like this.

      In TurnManager.java: (8 lines)

      Code:
        /**
         * Thread running method.
         */
        public void run() {
          movement();
          Civilization.turn();
          TurnId.increment(5);
        }
      And in Civilization.java: (30 lines)

      Code:
        /**
         * Perform one turn for all civilizations. Static method in Civilization.java
         */
        static public void turn() {
          for (Iterator iterator = Civilization.iterator(); iterator.hasNext(); ) {
            Civilization civ = (Civilization)iterator.next();
            civ.economicsTurn();
            civ.getCivEconomy().econTurnCompleted();// to update frames
      
           // Something like this shoud be done immediately, it will require rewriting. It should not be in economics.
            // Set orders for new units
            Units.issueOrders(civ);
      
            collectMerchantProfitsInCiv(civ);
            Iterator merchantIter =
                civ.getCivEconomy().getAllMerchantsWithHomeHere() ;
            // find new contracts
            while(merchantIter.hasNext()){
               Merchant tempMerchant = (Merchant) merchantIter.next();
               if(Rand.nextFloat() > 0.5) tempMerchant.findNewContract();
           }
      
            // Should not be in economics
            civ.populationTurn();
            // Should not be in economics
            civ.getGovernment().productionCycle();
      
            // Should not be in economics
            civ.socialModelTurn();
        }
      This does not change the order of operations. Actual civilization operations do not impinge on any other civilization, and do not need to know about any other civilization. In my view this code (which will need a bit of tidying up in detail) is much cleaner than the existing code.

      The order of operations recommended in the thread Mark referred to does not seem to bear much relation to the order of operations actually used in the code.

      I do not, for example, see any justification for the social model to be before the military movement. I would also put population changes straight after movement, because they are square based, rather than civilization based, and actually remove them from the civilization scan. It seems rather silly to iterate over all squares in all civilizations when it is much simpler to iterate over all squares.

      Cheers

      Comment


      • #4
        I second Gary here.
        It is a good idea to loop only once on squares if possible (and civs and what not).
        This can have an effect on gameplay: If we have 10 models, each of them iterating on provinces, we will spend 10 times less time iterating if we do it the way Gary suggests. That, on the long run, may be visible by the player in terms of performance of the program (waiting between turns).
        I think the sequencing is essentially a matter internal to a model, rather than between models, with the exception of military which has drastic effects like shutting the economy off or changing ownership. Maybe riots should come in early too, but I don't know at what level they are computed.
        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


        • #5
          What I agree on:

          The stuff that I just put in economics temporarily for my use clearly should not be there.

          An approach of the general sort outlined by Gary is ok by me, with the modifications noted below.

          My issues:

          As I said above, I do not think it wise to trump Game Design issues for code design purposes. I don't have time now to come up with a good example of where that might occur with the proposed approach. However I consider it not unlikely that a whole model will need to be run over all civs before the turn phasing moves on to other things in all the civs. If there is no problem putting in a second "turn" in civ, like civ.diplomacyTurn if needed then I don't have a problem with the proposed approach.

          I think it is Really Silly and contrary to what little I know of OO to put Merchant stuff, which is a detailed sub-model of economics into Civilization. (See "And in Civilization.java: (30 lines)" ) To my mind, this should be run in the economics package perhaps by calling CivEconomy.merchantTurn or some such. There is also the practical matter that I don't want to need to mess with Civilization when changing the currently-crude merchant turn-handling stuff.

          Hi Gary:

          The order of operations recommended in the thread Mark referred to does not seem to bear much relation to the order of operations actually used in the code.
          That's because when you got the code with the previous turn handling approach, which followed that doc, you tore it apart because you didn't like it for a variety of reasons, some quite justified. Admittedly there was not much implemented anyway, but everything was there with uncoded bits having comments for where they were supposed to go. When you made the changes you removed all the comments of what goes when. Then as new things were added they went in the sequence wherever it made sense to whoever was coding. Because it is not that way now says nothing either way on which way it should be. Our process over the last year for what goes where in the turn sequence has been rather haphazard, at least its appeared so to me... We should discuss again what should happen when in the turn sequence. Although I'd be in favor of putting that off until demo 7.
          Last edited by Mark_Everson; March 18, 2002, 13:59.
          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 it is Really Silly and contrary to what little I know of OO to put Merchant stuff, which is a detailed sub-model of economics into Civilization. (See "And in Civilization.java: (30 lines)" ) To my mind, this should be run in the economics package perhaps by calling CivEconomy.merchantTurn or some such. There is also the practical matter that I don't want to need to mess with Civilization when changing the currently-crude merchant turn-handling stuff.
            Actually, it is possible to do it cleanly:
            The civ has a set of visitors and it visits them. Each model that wants to iterate on the civs during a turn calls something like Civilization.addVisitor(visitor), where visitor will be called on each civ during the turn. That way, the civ iterator doesn't know anything about who it calls, but it can make the loop only once, calling each visitor in turn.
            We can also add a priority to the visitor, like Civilization.addVisitor(visitor,1) so they are processed in a given order.
            You would have a in Civilization a static void turn() nethod which would do a loop on the civs, and call each visitor by order of priority on it. If loops on civ then units then civ are needed for gameplay, so be it, we can add a parameter to turn() and addVisitor. I agree that, if needed for gameplay, we can have several civ iterations, I just think that currently it is not needed, and a proper reworking of the code can lead to faster and easier to maintain program (typically, adding a new model wouldn't require changing the turn handler).
            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
              Now that is really an excellent idea. It also is implemented using a standard design pattern. I have two comments.

              First, I am not all that keen on a priority integer, which adds dependencies - you have to check all the existing values, and maybe shift them sideways to insert a new call. I would just use the order in which the visitors are added to the list.

              The second comment is that this same approach could be used for squares and units.

              Cheers

              Comment


              • #8
                That's because when you got the code with the previous turn handling approach, which followed that doc, you tore it apart because you didn't like it for a variety of reasons, some quite justified. Admittedly there was not much implemented anyway, but everything was there with uncoded bits having comments for where they were supposed to go. When you made the changes you removed all the comments of what goes when. Then as new things were added they went in the sequence wherever it made sense to whoever was coding.
                I just took out what wasn't implemented, without, I think, changing the order. As far as I am aware the only new bit is the social model which you put at the beginning, before movement. The unfortunate effect of that is the the player (and AI) plans the moves. Then the riots or revolutions take place. Then the possibly obsolete moves take place. The social model should be somewhere after movement, and before the plans for the next lot of movement. In effect, with everything else.

                As far as the general order of events, I can't really understand the post that you referenced, perhaps because of the confusing indenting, and the numbering order (1, 3, 2, 4, 5...).

                Cheers

                Comment


                • #9
                  Ok, well everyone seems moderately happy!

                  Gary: On the govt being first thing, I just wanted the player to be able to be militarily surprised by a revolt. I'm comfortable doing it your way, and seeing how it works. In that case I would prefer to put the social/govt/riots stuff right at the end of the turn so the people can react to bad economic news, plagues etc. But again, we can discuss all this longer-term stuff at a later date.

                  I have gone ahead and edited the old post so the weird formatting doesn't disturb you . I haven't updated anything except changing the numbers so they're all in sequence, and gotten rid of the indent thing, which interestingly enough was caused by the last forum upgrade. Switching between BB software packages made some of the old codes obsolete.
                  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

                  Working...
                  X