On Sun, 2006-04-02 at 14:52 +0200, Jérémy Rosen wrote:
> (note : this is code I don't know well)
> 
> all this sound nice and good, I have seen your patch on savannah, at it 
> looks promising...
> 
> 
> Xan, rusty, do you want to merge it or shall I ?

I'd prefer to go through in detail and merge it myself.  The current
attack_prediction API was a first guess: but looking at the way it's
used I might decide to modify it.

BTW, Xan rewrote healing as part of this stuff (my changes clashed with
his), and it a little broken at the moment WRT allied healing and cure
vs. heal poisoning.  I'll fix this first.

(Not criticising Xan: over 2000 lines of new code in 44 files is going
to have bugs!)

Thanks!
Rusty.

> 
> I don't know the code well enough to comment much more than "work for 
> me" so I think it would be better if one of you took care of that patch
> 
> 
> Laurent Birtz wrote:
> > 
> 
> 
> Hello,
> > 
> > some time ago I've worked on improving the "Damage Calculations" dialog 
> > that is
> > shown when the user is considering to attack an enemy unit. I've also 
> > tweaked
> > the code to improve the selection of the defense weapon when a unit is 
> > attacked.
> > Unfortunatly, I had to stop development for a while since I've been kept 
> > busy
> > with other projects (my apologies to Rusty for disappearing). Now that 
> > I've got
> > some time, here's a resume of the modifications:
> > 
> > 
> > --------------------------------------------------
> > Damage Calculations dialog:
> > 
> > The new dialog shows the damage computations and the hit points 
> > distribution of
> > the units after the battle. Here's a sketch:
> > 
> > Damage Calculations
> > 
> >            Attacker                                     Defender
> >   Base damage                 10            Base damage                   4
> > Morning                     +25%          Morning                       
> > -25%
> >                                          Attacker resistance vs blade  * 
> > 0.5
> > Damage per strike           12
> > Summary                     12-3 (40%)    Damage per strike             2
> > Chance of being unscathed   9.0%          Summary                       
> > 2-2 (70%)
> >                                          Chance of being unscathed     
> > 21.6%
> > 
> > 
> >    Expected Battle Result (hp)                  Expected Battle Result (hp)
> > -------------------------------------     
> > --------------------------------------
> > | 51|==                       | 9.0%|     | 39|====                      
> > |21.6%|
> > | 49|===========              |42.0%|     | 27|=========                 
> > |43.2%|
> > | 47|============             |49.0%|     | 15|======                    
> > |28.8%|
> > -------------------------------------     |  3|=                         
> > | 6.4%|
> >                                          
> > --------------------------------------
> > 
> > 
> > --------------------------------------------------
> > Battle simulator:
> > 
> > Rusty made a great battle simulator that can predict all the possible 
> > outcomes
> > of a battle. The simulator handles drain, slow, first strike, berserk and
> > swarm. I use this simulator to obtain the hit points distribution of the 
> > units
> > after the battle. However, the simulator can also be used by the AI to
> > accuratly predict the outcome of a battle (rather than relying on 50 dry 
> > runs
> > like it is done currently). Remarkably, Rusty's simulator can "chain" many
> > attacks against a defender unit. Example: pikeman attacks wolfrider, then
> > shaman attacks wolfrider. After the first battle, the wolfrider will have
> > different possible HP values (e.g. 24, 10, 0 [bogus values]). The simulator
> > takes those values (and slow state) into account when it computes the 
> > possible
> > states after the second battle. The final HP values of the wolfrider could
> > thus be (24, 15, 10, 5, 0). Since the simulator computes the probability 
> > that
> > each unit remain unscathed (not touched by any blow), it is possible to get
> > the probability of a unit getting poisoned/slowed by an attack.
> > 
> > Rusty spent much time optimizing his simulator. I *believe* that using the
> > simulator is faster than performing 50 dry runs, but I've conducted no
> > benchmarks. Rusty is the guy who would know.
> > 
> > Possible caveat: due to the necessity of handling "slow + drain" properly,
> > Rusty had to use a slower implementation that involves a two-dimensions
> > matrix. The length and width of this matrix is determined by the maximum 
> > HP of
> > the units that fight. So, while the computations are fast for units that 
> > have
> > ~75 HP (?), they will get much slower as the health of the units increase
> > [O(n^2)]. Hence, if Wesnoth is to allow units that have lots of HP, the
> > simulator will probably be too slow for heavy usage by the AI (perhaps the
> > current approximation code can be used in those cases). Also, the 
> > simulator is
> > slower to simulate battles involving 'berserk'.
> > 
> > 
> > --------------------------------------------------
> > "battle_context" object:
> > 
> > To create the new dialog, I had to get the HP distributions and present the
> > different factors influencing the damage computations. In Wesnoth SVN 
> > code (not
> > my code), evaluate_battle_stats() is used to get the strings explaining 
> > those
> > factors and get the XX/XX/XX probability outcome string. However, I had 
> > a number
> > of issues with evaluate_battle_stats() and its associated "battle_stats"
> > object:
> > 
> > Firstly, before I designed the new dialog, I wanted to improve the 
> > heuristic
> > used to select the weapon used on defense. evaluate_battle_stats() does 
> > not make
> > this easy since some information such as the amount of damage dealt by the
> > attacker / defender are computed after the defense weapon has been chosen.
> > 
> > Secondly, the information contained in "battle_stats" is derived from the
> > current tactical situation (in other words, evaluate_battle_stats() 
> > looks at the
> > map and sees that it is day, that a leadership bonus applies to the 
> > attacker,
> > etc). However, I considered using Rusty's simulator eventually to 
> > compute the
> > outcome of many attacks on a single defender (when the AI is planning). 
> > For the
> > second and subsequent attacks, the tactical situation is not the same as 
> > the
> > "former" tactical situation (perhaps a unit will have leveled and provide
> > leadership, etc). Thus, I wanted to be able to manually set some factors 
> > like
> > the leadership bonus and the time of day both for the attacker and the 
> > defender.
> > Currently, evaluate_battle_stats() provides support for overriding the 
> > terrain
> > used for the attacker (attacker_terrain_override) but it is not possible to
> > override other factors.
> > 
> > Finally, I wasn't fond of the way evaluate_battle_stats() mixes GUI 
> > stuff with
> > the battle computations. If 'strings' isn't NULL, 
> > evaluate_battle_stats() fills
> > it out with strings describing the computations. Of course, this 
> > approach may
> > avoid code duplication. However I feel it would be cleaner if there was 
> > a clear
> > separation between the GUI and the actual computations.
> > 
> > For these reasons, at the time I started writing the new dialog code, I 
> > used
> > the "battle_context" object I had made to fix the (perceived) issues 
> > mentionned
> > above. "battle_context" is designed to replace "battle_stats" 
> > altogether. Here's
> > a quick rundown of the API:
> > 
> > The "battle_context" object has some fields that are mandatory and some 
> > fields
> > that are optional. Initially, the user sets the mandatory field with
> > 
> > void init(const gamemap& map, std::vector<team>& teams, 
> > std::map<gamemap::location,unit>& units,
> >      const gamestatus& status, const gamemap::location& attacker_loc, 
> > const gamemap::location& defender_loc,
> >          const attack_type& attacker_weapon);
> > 
> > The arguments are equivalent to the arguments used with 
> > evaluate_battle_stats().
> > 
> > Then, the user may optionally specify the 
> > leadership/slowed/poisoned/time of
> > day/backstab state of the attacker and the defender, by setting those 
> > fields
> > directly in the "battle_context" object.
> > 
> > Afterward, the user calls compute_battle_stats() to compute the battle
> > statistics. This method first looks at the optional fields and obtains 
> > the value
> > of any unitialized field by observing the current situation on the 
> > battlefield,
> > like evaluate_battle_stats() does. Then, the method determines which 
> > weapon will
> > be used on defense, if any. To do this, the method generates a 
> > "battle_context"
> > object for each defense weapon that matches the attacker weapon's range. 
> > Each of
> > those "battle_context" objects computes the stats of the attacker and 
> > defender
> > weapons used (damage dealt, number of strikes, drain amount, etc).
> > 
> > Then, an heuristic function is used to determine which is the best defense
> > weapon. The heuristic compares the current "best" defense weapon with 
> > the next
> > available defense weapon and specifies which is the best weapon. At the 
> > end of
> > the process, the original "battle_context" object contains the complete 
> > stats of
> > the battle with the best defense weapon. Since the heuristic function 
> > has access
> > to the complete battle stats when it compares two defense weapons, it 
> > can make
> > an enlightened choice. For instance, the heuristic function could elicit 
> > not to
> > use a low-damage poisoning attack if the attacker is already poisoned or is
> > undead. I know that some developers do not want a clever heuristic 
> > though :)
> > For now, the heuristic of "battle_context" is compatible with the 
> > heuristic used
> > in evaluate_battle_stats().
> > 
> > Obviously the "battle_context" object is slower than 
> > evaluate_battle_stats() due
> > to the extra work to select the defender's weapon. However, in most 
> > cases, only
> > one defense weapon is available. I expect "battle_context" to be perhaps 
> > 2 times
> > slower than evaluate_battle_stats() (just guessing, I didn't benchmark).
> > "battle_context" doesn't fill out 'strings' with the strings describing the
> > compution it makes. However, all the necessary information can be 
> > obtained by
> > looking at the fields of "battle_context".
> > 
> > Last minute note: "battle_context" no longer exactly matches the actual
> > computations done by evaluate_battle_stats() since Xan has been 
> > modifying the
> > code extensively today. I've updated my code so that it compiles with 
> > the new
> > interfaces. However, some of Xan's stuff is a work in progress and is 
> > likely to
> > change in the next few days. Because of this I didn't update my code to 
> > reflect
> > Xan's changes on backstab, charge, swarm and steadfast.
> > 
> > 
> > --------------------------------------------------
> > "battle_prediction_preview_pane" object:
> > 
> > I modified attack_enemy() to compute the battle stats with 
> > "attack_context", in
> > addition to the usual evaluate_battle_stats(). The logic doesn't change 
> > much:
> > 
> > // If set to 1, the new dialog is shown, otherwise the old dialog is shown.
> > #if 1
> > attack_prediction_displayer ap_displayer(gui_, bc_vector);
> > std::vector<gui::dialog_button> buttons;
> > buttons.push_back(gui::dialog_button(&ap_displayer, _("Damage 
> > Calculations")));
> > #else
> > attack_calculations_displayer calc_displayer(gui_,stats);
> > std::vector<gui::dialog_button> buttons;
> > buttons.push_back(gui::dialog_button(&calc_displayer,_("Damage 
> > Calculations")));
> > #endif
> > 
> > "battle_prediction_preview_pane" is the object used to show the dialog. It
> > generates the graphics, obtains the strings describing the computations and
> > displays the dialog (straightforward code).
> > 
> > Some notes about the graphics. HP values >= initial HP are shown in 
> > green, 0 HP
> > is shown red, otherwise it's yellow. At most 10 lines are displayed in the
> > graphs. The lines with the highest probability values are retained when the
> > limit is exceeded. Thus, when two scuttlefishes or berseckers fight, it's
> > possible that some values with a low probability are not shown.
> > 
> > 
> > --------------------------------------------------
> > Code modifications:
> > 
> > Rusty made a file called "attack_prediction.cpp" that contains his 
> > simulator.
> > I've modified the file to extract the header "attack_prediction.hpp" 
> > from it.
> > "Makefile.am" was modified to add "attack_prediction.cpp". The file
> > "playturn.cpp" was modified to contain the dialog code as described 
> > above. The
> > files "actions.{cpp|hpp}" were modified to add the "battle_context" 
> > code. The
> > file "font.hpp" was modified to add a prototype for the function
> > draw_text_line() (I needed this to draw text in a SDL surface directly).
> > 
> > 
> > --------------------------------------------------
> > Summary:
> > 
> > The damage computations dialog code shouldn't cause problems. My
> > "battle_context" code probably will, since it aims at replacing existing 
> > code.
> > The question is wheter you guys are happy with evaluate_battle_stats() 
> > or if
> > you'd prefer "battle_context". In the former case, some work would have 
> > to be
> > spent on reworking the dialog so that it uses evaluate_battle_stats() (I 
> > guess
> > it would be possible to add "battle_context" just for the dialog but 
> > that would
> > be a maintenance nightmare). Otherwise, evaluate_battle_stats() would 
> > have to be
> > progressively phased out. The functions attack() and 
> > attack_analysis::analyze()
> > use it and would need to be updated. In the process, analyze() could 
> > make use of
> > Rusty's simulator to get rid of the dry runs and enhance the accuracy of 
> > the
> > predictions (for instance, the current dry runs do not currently take 
> > 'berserk'
> > into account as far as I can see).
> > 
> > Last minute note: I spoke with Xan regarding my "battle_context" code 
> > and it
> > seems there is hope that it might be integrated. Therefore I've posted 
> > my patch
> > on Gna since Xan is updating evaluate_battle_stats() and I'm updating my 
> > patch
> > in response to those changes. I'll try to keep my code compiling as the 
> > various
> > interfaces are updated. However, the sooner my patch is accepted (or 
> > rejected),
> > the less time I'll spend maintaining :) Hence here is the code. It doesn't
> > replace "battle_stats" in the AI and attack() yet, but if the developers 
> > give
> > me the authorisation, I'll perform the conversion to battle_context 
> > thoroughly
> > in the code.
> > 
> > 
> > I await your comments, thanks for your time!
> > Laurent Birtz
> > 
> > 
> > _______________________________________________
> > Wesnoth-dev mailing list
> > [email protected]
> > https://mail.gna.org/listinfo/wesnoth-dev
> 
> 
> _______________________________________________
> Wesnoth-dev mailing list
> [email protected]
> https://mail.gna.org/listinfo/wesnoth-dev
-- 
 ccontrol: http://ozlabs.org/~rusty/ccontrol


_______________________________________________
Wesnoth-dev mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-dev

Reply via email to