 |
|  |
 |
|
Gary Thomas
|
 |
New Zealand
Mar 2001 time: 17:18
|
|
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
|
|
|  |
 |
|
Gary Thomas
|
 |
New Zealand
Mar 2001 time: 17:18
|
|
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
|
|
|  |
 |
|
LDiCesare
|
|
La Ferté sous Jouarre France
Jan 2001 time: 05:18
|
|
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.
|
|
|  |
 |
|
Mark_Everson
|
 |
Canton, MI
Jan 1970 time: 00:18
|
|
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:
quote: 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 on 18-03-2002 at 22:59
|
|
|  |
 |
|
LDiCesare
|
|
La Ferté sous Jouarre France
Jan 2001 time: 05:18
|
|
quote: 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).
|
|
|  |
 |
|
Gary Thomas
|
 |
New Zealand
Mar 2001 time: 17:18
|
|
quote: 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
|
|
|  |
 |
|  |
 |
|  |
All times are GMT. The time now is 05:18. Apolyton Time is 00:18. |
top of page
|
|
|
Forum Rules:
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is ON
vB code is ON
Smilies are ON
[IMG] code is ON
|
|
|
|
|
|