Topic: More reliable citadel/castle-vilage start up

fk
Avatar
Topic Opener
Joined: 2013-07-30, 22:58 UTC+2.0
Posts: 150
Ranking
At home in WL-forums
Posted at: 2014-02-12, 21:03 UTC+1.0

In order to make the citadel/castle start-ups more reliable I have added one line after the line "if not pcall(function()" in each of the files .../widelands/tribes/*/scripting/sc01_{castle,citadel}_village.lua and it seems to work fine:

Empire: place_building_in_region(plr, "lumberjacks_house", sf:region(11))

Barbarians: place_building_in_region(plr, "lumberjacks_hut", sf:region(11))

Atlanteans: place_building_in_region(plr, "woodcutters_house", sf:region(11))

It places a lumberjack/woodcutters hut or house as the second building. For as far as tested no AI-player has got stuck without trunks anymore, nor has any other problem occurred.

Update: perhaps it wasn't obvious, but I made these changes on my own computer.

There is still room for improvement, like a ranger/forester in case there are no trees in the vicinity.

Edited: 2014-02-13, 10:32 UTC+1.0

Top Quote
fk
Avatar
Topic Opener
Joined: 2013-07-30, 22:58 UTC+2.0
Posts: 150
Ranking
At home in WL-forums
Posted at: 2014-02-17, 23:00 UTC+1.0

This script builds both a woodcutters house and a foresters house close to each other in the area around the castle with the most trees and with enough room for these two buildings, this in addition to the buildings that were already included in Castle Village. It works for the Atlanteans only.

The code divides the area around the castle in 7 regions, and tries to select the most suitable region for the buildings.

The gameplay is actually much better if the AI players start with more buildings than in the default set up. Problem was that especially the Atlanteans use enormous amounts of trunks and may often get stuck before they have finished a woodcutters house and a foresters house.

(The code is still messy, but functional:)

-- =========================================================
--                     Wood Village Starting Conditions
--
--                              Fair use policy
-- =========================================================

set_textdomain("tribe_atlanteans")

-- =========================== infrastructure =====================
--(derived from infrastructure.lua)

-- Returns last building:
function _prefilled_buildings(p, ...)
  local building
   for idx,bdescr in ipairs({...}) do
      b = p:place_building(bdescr[1], wl.Game().map:get_field(bdescr[2],
                 bdescr[3]), false, true)
      building = b
      -- Fill with workers
      if b.valid_workers then b:set_workers(b.valid_workers) end
      if bdescr.workers then b:set_workers(bdescr.workers) end
      -- Fill with soldiers
      if b.max_soldiers and b.set_soldiers then
         if bdescr.soldiers then
            b:set_soldiers(bdescr.soldiers)
         else
            b:set_soldiers({0,0,0,0}, b.max_soldiers)
         end
      elseif bdescr.soldiers then -- Must be a warehouse
         b:set_soldiers(bdescr.soldiers)
      end
      -- Fill with wares if this is requested
      if bdescr.wares then b:set_wares(bdescr.wares) end
   end
  return building
end

function _place_building_in_region(
   plr, building, fields, gargs
)
   local idx
   local f
   local args = gargs or {}
   local req_suitability = args.req_suitability or 1

   while #fields > 0 do
      local idx = math.random(#fields)
      local f = fields[idx]

      if plr:get_suitability(building, f) >= req_suitability then
         args[1] = building
         args[2] = f.x
         args[3] = f.y
         return _prefilled_buildings(plr, args)
      end
      table.remove(fields, idx)
   end
   error(string.format(
      "Could not find a suitable position for building '%s' for player %i",
      building, plr.number)
   )
end

-- =========================== scan for objects ====================

function count_trees(fld)
  local imm = fld.immovable
  local amount = 0
  if imm then
    local name = string.sub(imm.name, 1, 4)
    if name == "tree" then
      amount = 1
    end
  end
  return amount
end

function count_trees_in_region(area)
  local i = 1
  local trees = 0
  while i <= #area do
    trees = trees + count_trees(area[i])
    i = i + 1
  end
  return trees
end

-- =============== divide region(12) in seven region(4) ============

function asterisk(fld)
  local point = {
    fld,
    fld.rn.rn.rn.rn.rn.rn.rn.rn,
    fld.brn.brn.brn.brn.brn.brn.brn.brn,
    fld.trn.trn.trn.trn.trn.trn.trn.trn,
    fld.ln.ln.ln.ln.ln.ln.ln.ln,
    fld.bln.bln.bln.bln.bln.bln.bln.bln,
    fld.tln.tln.tln.tln.tln.tln.tln.tln
  }
  return point
end

-- ============================   duo sort    ======================

function sort(array1, array2)
  local i
  local done = false
  while not done do
    i = 1
    done = true
    while i < #array1 do
      if array1[i] < array1[i + 1] then
        local a
        a = array1[i]
        array1[i] = array1[i + 1]
        array1[i + 1] = a
        a = array2[i]
        array2[i] = array2[i + 1]
        array2[i + 1] = a
        done = false
      end
      i = i + 1
    end
  end
  return array1, array2
end

-- ============================               ========================

function get_suitability_in_region(plr, building, fields)
  local flag = false
  local i = 1
  while i <= #fields do
    if plr:get_suitability(building, fields[i]) >= 1 then
      flag = true
      break
    end
    i = i + 1
  end
  return flag
end

-- ============================     main      ======================

return {
  name = _ "Wood Village",
  func =  function(plr, shared_in_start)

  local sf = wl.Game().map.player_slots[plr.number].starting_field
  if shared_in_start then
    sf = shared_in_start
  else
    plr:allow_workers("all")
  end

  local h = plr:place_building("castle", sf, false, true)
  h:set_soldiers{[{0,0,0,0}] = 12}

  local point = asterisk(sf)
  local array1 = {}
  local array2 = {}
  local i = 1
  local j = 1
  local m = 0
  local p
  while i <= #point do
    p = count_trees_in_region(point[i]:region(4))
    array1[i] = p
    array2[i] = point[i]
    if p > m then
      m = p
      j = i
    end
    i = i + 1
  end

  sort(array1, array2)

  local chop
  local drop
  local building
  i = 1
  while i <= #array1 do
    chop = get_suitability_in_region(plr, "woodcutters_house", 
                    array2[i]:region(4))
    if chop then
      building = _place_building_in_region(plr, "woodcutters_house", 
                   array2[i]:region(4))
      drop = get_suitability_in_region(plr, "foresters_house", array2[i]:region(4))
      if building and building.flag then building.flag:remove() end
      if drop then
        _place_building_in_region(plr, "woodcutters_house", array2[i]:region(4))
        _place_building_in_region(plr, "foresters_house", array2[i]:region(4))
        break
      end
    end
    i = i + 1
  end

   if not pcall(function()
      _place_building_in_region(plr, "warehouse", sf:region(7), {
         wares = {
            diamond = 7,
            ironore = 5,
            quartz = 9,
            stone = 50,
            spideryarn = 9,
            trunk = 13,
            goldyarn = 6,
            planks = 45,
            spidercloth = 5,
            blackroot = 5,
            blackrootflour = 12,
            corn = 5,
            cornflour = 12,
            fish = 3,
            meat = 3,
            water = 12,
            bakingtray = 2,
            bucket = 2,
            fire_tongs = 2,
            fishing_net = 4,
            hammer = 11,
            hunting_bow = 1,
            milking_tongs = 2,
            hook_pole = 2,
            pick = 12,
            saw = 9,
            scythe = 4,
            shovel = 9,
            tabard = 5,
            light_trident = 5,
         },
         workers = {
            blackroot_farmer = 1,
            builder = 10,
            burner = 1,
            carrier = 38,
            fish_breeder = 1,
            geologist = 4,
            miner = 4,
            stonecutter = 2,
            toolsmith = 1,
            woodcutter = 3,
            horse = 5,
         },
         soldiers = {
            [{0,0,0,0}] = 23,
         },
      })

      _place_building_in_region(plr, "labyrinth", sf:region(11), {
         wares = {
            bread = 4,
            smoked_fish = 3,
            smoked_meat = 3,
         }
      })

      _place_building_in_region(plr, "dungeon", sf:region(11), {
         wares = {bread = 4, smoked_fish = 3, smoked_meat = 3}
      })

      _place_building_in_region(plr, "armoursmithy", sf:region(11), {
         wares = { coal=4, gold =4 }
      })
      _place_building_in_region(plr, "toolsmithy", sf:region(11), {
         wares = { trunk = 6 }
      })
      _place_building_in_region(plr, "weaponsmithy", sf:region(11), {
         wares = { coal = 8, iron = 8 }
      })

      _place_building_in_region(plr, "sawmill", sf:region(11), {
         wares = { trunk = 1 }
      })
   end) then
      plr:send_message(_"Not enough space", _
[[Some of your starting buildings didn't have enough room and
weren't build. You are at an disadvantage with this; consider restarting
this map with a fair starting condition.]], {popup=true}
      )
   end

end
}
Edited: 2014-02-17, 23:22 UTC+1.0

Top Quote
SirVer

Joined: 2009-02-19, 15:18 UTC+1.0
Posts: 1442
Ranking
One Elder of Players
Location: Germany - Munich
Posted at: 2014-02-18, 06:27 UTC+1.0

The script looks interesting (and complex :)). Could you look into making this work for all tribes by factoring out some common code and making a merge request on launchpad (or opening a bug with the changed files). I think this will make a valuable addition to Widelands.


Top Quote
einstein13
Avatar
Joined: 2013-07-29, 00:01 UTC+2.0
Posts: 1116
Ranking
One Elder of Players
Location: Poland
Posted at: 2014-02-18, 07:48 UTC+1.0

fk, we are also working on good AI which will not make those common mistakes. You can help us face-smile.png Tibor has some ideas, I can see that you too. Then we don't need additional wood production.

But your work is great ! face-smile.png


einstein13
calculations & maps packages: http://wuatek.no-ip.org/~rak/widelands/
backup website files: http://kartezjusz.ddns.net/upload/widelands/

Top Quote
fk
Avatar
Topic Opener
Joined: 2013-07-30, 22:58 UTC+2.0
Posts: 150
Ranking
At home in WL-forums
Posted at: 2014-02-19, 15:52 UTC+1.0

SirVer wrote:

Could you look into making this work for all tribes by factoring out some common code [..]

Certainly, it is only a matter of time, and hopefully I can omit some duplicated code.

einstein13 wrote:

fk, we are also working on good AI which will not make those common mistakes. You can help us face-smile.png Tibor has some ideas, I can see that you too. Then we don't need additional wood production.

I don't know where I can help. face-wink.png

The challenge is to develop a good model for wood production that always works. Perhaps someone is working on that already. I think that the model would fall into two parts, 1) to create a steady production of trunks and 2) to handle the current situation, i.e., is there enough wood to build a woodcutters house, or should we 'steal' some from an existing building? where does the last trunk go? etc.

With the latter you are right, let's say that I couldn't wait. face-wink.png

Edited: 2014-02-19, 16:44 UTC+1.0

Top Quote
fk
Avatar
Topic Opener
Joined: 2013-07-30, 22:58 UTC+2.0
Posts: 150
Ranking
At home in WL-forums
Posted at: 2014-02-20, 13:00 UTC+1.0

The files with the new code can be found here: https://bugs.launchpad.net/widelands/+bug/1282530


Top Quote
einstein13
Avatar
Joined: 2013-07-29, 00:01 UTC+2.0
Posts: 1116
Ranking
One Elder of Players
Location: Poland
Posted at: 2014-02-20, 19:29 UTC+1.0

fk, we are also working on good AI which will not make those common mistakes. You can help us face-smile.png Tibor has some ideas, I can see that you too. Then we don't need additional wood production.

I don't know where I can help. face-wink.png

The challenge is to develop a good model for wood production that always works. Perhaps someone is working on that already.

The model is ready. Math model. I've done some experiments and calculations. The results are here: http://student.agh.edu.pl/~rak/widelands/

But the problem is somewhere else. The AI should only expand and build woodcutters and foresters (maybe one or two sawmill). Other buildings should be prohibited. It shouldn't be so hard to implement. We only want to "get current state of empire". It can be done from statistics: how much buildings we have? 0 woodcutters, foresters & sawmils -> other prohibited (but not the military ones!).

I think that the model would fall into two parts, 1) to create a steady production of trunks

I'm working on that face-wink.png But I have to pass hard exams now, so no time for test :(.

2) to handle the current situation, i.e., is there enough wood to build a woodcutters house, or should we 'steal' some from an existing building? where does the last trunk go? etc.

3 possible situations:

  1. Just beginning of game (explained above)
  2. Expanding the territory/empire (we have no trunks, but we have wood production, so not a huge problem)
  3. After loosing the territory (we have to dismantle some buildings and build up another wood production)

There is only one possibility for 3rd option, where any AI or player would get stuck: all the territory is barren steppe, beach or mountains. On that land trees will not grow (the production is extremely low!). From that situation there is only one option: conquer the attacker. Any power.


einstein13
calculations & maps packages: http://wuatek.no-ip.org/~rak/widelands/
backup website files: http://kartezjusz.ddns.net/upload/widelands/

Top Quote
Adamant

Joined: 2012-10-11, 16:21 UTC+2.0
Posts: 180
Ranking
Widelands-Forum-Junkie
Location: Alemania
Posted at: 2014-03-03, 09:12 UTC+1.0

I did not inspect fk's Code but want to add here some generic Informations about concerning Code Scope that I did for other Reasons reformat Code - concerns to Aim make it readable to me implies Application of own Indention Style (which sounds for other Programmers perhaps odd - I am sure, but I know that my Indention Style got confirmed enought from 3rd to know that it is not just my special Favor to rate it much better than conventional - just factor in that that Work is reasonable if know that indention style) while Reason was to learn how Lua works resp what it can do for Campaign starting with that Init-Scripts. As transformed both Scripts I did identify the Common resp found that HQ-Start is almost pure SubSet of CastleVillage-Start and did consider to combine both but got aware that something works wrong: Init-Scripts need different CFGs for Wares due to Build did not respect Build-Costs. I did not check precisely but Idea (est) was that CV-init did set Wares that lesser which it would consume when buld that Sites, it tries to set manuallly in Game. So Insufficience (it is not a Bug - Func to set without Build Costs is reasonable!!) is Func that triggers MaterialConsumption dependings from BuildCosts.
Would that exist, then CV-init could call the HQ-init-Script to set InitWares and Player wont have clearly DisAdvantages would that Init fail to set some Sites aside of Delay for building that Site manually.


The most significant Change I applied to Logic was that: (PSeudo-Code -- I am not experienced with Lua but can deal with sufficiently now in hours)


local wh; -- warehouse;
local hq; -- headquater
local port; -- guess
local store;

port=setSiteFunc(type=port ,args); store=port;
if not store then hq =setSiteFunc(type=headquater,args); store=hq; end;
if not store then wh =setSiteFunc(type=warehouse,args); store=wh; end;
if not store and not Plan_D then raise Fatal Err end


store.ware_type = val;
...
Soldier freshy = { } -- just defined -- remind Tutorial Campaign where such got used ... Point is reasonable named/preset Soldier-Types adding semantic to script

store.soldier = num * freshy; -- that Way like making also that Item looking mostly same like other store puts.

I did change something siginificant for Placement: I put the Stores Placement with same flexible Func like the other Sites which means that eg HQ does not get placed
exactly at given Player Position but in that Region. Due to unknown Reasons that simple Range Num Attribute did not perform like expected. Short Time later my Stuff
got deleted from new Installation and I felt somewhat disappointed.. btw: CNT for Lose of Work due to this or that got '4' .. I dont point to Causes here but Result was
I did resign on serious Work. Lost Work does represent as Sum about Work of 1/4 Year intensive Work ... that means avg 5 Day Week 8h Work at minimum... that
was Reason why I did decide to focus on Fun for 100% due to I did decide not to face Problems of arbitrary Nature and produce for Null Device..

So above were the most significant Changes resp Design-Decisions to change proofed Init-Scripts. I did indentify for BackUp ShipWreck and Proto-HQ of Barabarians
but did not identify a special Diff for Space-REQs that these appeared to represent reasonable Alternativs - plain said: If HQ and Port fails I wonder what can those do
better than WH and WH REQ medium Build-Space - the both listed Specials appeared unlikly to consume lesser and thus dont promise a Solution if the other fail.

I did intend to add them nevertheless not facrtoring in special Characteristics for healing/housing Troops -- now I would do for sure add them at any Level as Alternative
selected by Random to add that Way Diversity to Game: Player may wonder what Store they get each Time when multiple Types are at same Level. Before doing
that I tried to inspire to clear Issue of somebody can do ArtWork to give ALL Tribes same resp equivalent Meanings -ProtoHQ and Wreck .. another Question I did not
get FeedBack for. Do I blame for that? Do I? Do I? NO I dont! :) Other Reason was I did decide to ask for rnd() of Lua instead doing Research for by Trial and Error
etc resp wait till rnd run cross my Way .... Install did before.


That Thingy:
if not pcall(function()
_place_building_in_region(plr, "warehouse", sf:region(7), {
wares = {
diamond = 7,
ironore = 5,

I did transform Lua-Feature-unspecial to

_place_building_in_region(plr, "warehouse", sf:region(7) ;
_place_building_in_region(plr, "otherSiteTypes", sf:region(7);
...

and

warehouse.ware.diamond = 7;
warehouse.ware.ironore = 5;

due to I consider that as better readable and more important better editable.
Advantages for LVM not excluded but dunno how that Engine works. When
read its SRC Idea was that their Developers did not really had a stunning
Idea beyond adding Nil and bool Evaluation to all basic Types. Also allow
of additional trailing Comma I consider to be respectable but with Resign
for Parnthesis for logical Expression and Curly Brackets to define resp
delimit Scopes but instead use that end Symbol is really disgusting to
me and another Reason why I dont respect Lua as Solution but Draft for.
My Idea is Lua did success due to somebody wrote in Magenta easy at.

I forgot to note its Scope-Addressing, which I did invent as well and was
disappointed seeing Lua doing same similar -- I felt lesser special thus,
Point is I was really (.. means somewhat more) proud about and seeing
that in Lua let me feel that that is just ordinary and give it a lesser Rate
than before.. means I should here stress that Feature significant better.
But it did invent needless another stupid IndentionStyle which make it
impossible to calc analog x++; x-- ; no_nocomment="inc could get dealed but cmnt conflicts with dec..."

I saw often Code like x=x+1;
IIRC Lua can not do x++ but can do x+=1; btw

due to the comment issue I consider lua as (partial intentioal) stupid -- the end Notation fits into that Idea.
Alternative Eplanation is that that is due to is sooo easy. Lua gets written btw like Moon -- LUA is wrong!
Resign for Brackets factor perhaps in that Brackets are not simple. Luuuuuaaaa .. lua is wrong as well. (true Lua Fan)

Edited: 2014-03-03, 09:13 UTC+1.0

Ivan the Terrible is dead .. Genghis Khan is dead .. and I do not feel well, too.

Top Quote
fk
Avatar
Topic Opener
Joined: 2013-07-30, 22:58 UTC+2.0
Posts: 150
Ranking
At home in WL-forums
Posted at: 2014-03-03, 11:27 UTC+1.0

There is already a newer version of the script. When I have more time I will create a trunk for it to enable it's further development. Btw, Lua script does not require semicolons like C.


Top Quote
EgyLynx

Joined: 2010-08-22, 08:51 UTC+2.0
Posts: 40
Ranking
Pry about Widelands
Posted at: 2014-03-03, 20:39 UTC+1.0

C is so old, but also C++ same think?


Top Quote