LCOV - code coverage report
Current view: top level - simulation/ai/common-api - map-module.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 125 0.0 %
Date: 2023-04-02 12:52:40 Functions: 0 20 0.0 %

          Line data    Source code
       1           0 : var API3 = function(m)
       2             : {
       3             : 
       4             : /**
       5             :  * The map module.
       6             :  * Copied with changes from QuantumState's original for qBot, it's a component for storing 8 bit values.
       7             :  */
       8             : 
       9             : /** The function needs to be named too because of the copyConstructor functionality */
      10           0 : m.Map = function Map(sharedScript, type, originalMap, actualCopy)
      11             : {
      12             :         // get the correct dimensions according to the map type
      13           0 :         let map = type == "territory" || type == "resource" ? sharedScript.territoryMap : sharedScript.passabilityMap;
      14           0 :         this.width = map.width;
      15           0 :         this.height = map.height;
      16           0 :         this.cellSize = map.cellSize;
      17           0 :         this.length = this.width * this.height;
      18             : 
      19           0 :         this.maxVal = 255;
      20             : 
      21             :         // sanity check
      22           0 :         if (originalMap && originalMap.length != this.length)
      23           0 :                 warn("AI map size incompatibility with type " + type + ": original " + originalMap.length + " new " + this.length);
      24             : 
      25           0 :         if (originalMap && actualCopy)
      26             :         {
      27           0 :                 this.map = new Uint8Array(this.length);
      28           0 :                 for (let i = 0; i < this.length; ++i)
      29           0 :                         this.map[i] = originalMap[i];
      30             :         }
      31           0 :         else if (originalMap)
      32           0 :                 this.map = originalMap;
      33             :         else
      34           0 :                 this.map = new Uint8Array(this.length);
      35             : };
      36             : 
      37           0 : m.Map.prototype.setMaxVal = function(val)
      38             : {
      39           0 :         this.maxVal = val;
      40             : };
      41             : 
      42           0 : m.Map.prototype.gamePosToMapPos = function(p)
      43             : {
      44           0 :         return [Math.floor(p[0]/this.cellSize), Math.floor(p[1]/this.cellSize)];
      45             : };
      46             : 
      47           0 : m.Map.prototype.point = function(p)
      48             : {
      49           0 :         let q = this.gamePosToMapPos(p);
      50           0 :         q[0] = q[0] >= this.width ? this.width-1 : q[0] < 0 ? 0 : q[0];
      51           0 :         q[1] = q[1] >= this.width ? this.width-1 : q[1] < 0 ? 0 : q[1];
      52           0 :         return this.map[q[0] + this.width * q[1]];
      53             : };
      54             : 
      55           0 : m.Map.prototype.runLoop = function(x0, x1, y0, y1, cx, cy, maxDist2, func)
      56             : {
      57           0 :         for (let y = y0; y < y1; ++y)
      58             :         {
      59           0 :                 const dy2 = (y - cy) * (y - cy);
      60           0 :                 const yw = y * this.width;
      61           0 :                 for (let x = x0; x < x1; ++x)
      62             :                 {
      63           0 :                         const dx = x - cx;
      64           0 :                         const r2 = dx * dx + dy2;
      65           0 :                         if (r2 >= maxDist2)
      66           0 :                                 continue;
      67           0 :                         const w = x + yw;
      68           0 :                         this.set(w, func(w, r2));
      69             :                 }
      70             :         }
      71             : };
      72             : 
      73           0 : m.Map.prototype.addInfluence = function(cx, cy, maxDist, strength, type = "linear")
      74             : {
      75           0 :         strength = strength ? strength : maxDist;
      76             : 
      77           0 :         const x0 = Math.floor(Math.max(0, cx - maxDist));
      78           0 :         const y0 = Math.floor(Math.max(0, cy - maxDist));
      79           0 :         const x1 = Math.floor(Math.min(this.width-1, cx + maxDist));
      80           0 :         const y1 = Math.floor(Math.min(this.height-1, cy + maxDist));
      81           0 :         const maxDist2 = maxDist * maxDist;
      82             : 
      83           0 :         if (type == "linear")
      84             :         {
      85           0 :                 const str = strength / maxDist;
      86           0 :                 this.runLoop(x0, x1, y0, y1, cx, cy, maxDist2, (w, r2) => this.map[w] + str * (maxDist - Math.sqrt(r2)));
      87             :         }
      88           0 :         else if (type == "quadratic")
      89             :         {
      90           0 :                 const str = strength / maxDist2;
      91           0 :                 this.runLoop(x0, x1, y0, y1, cx, cy, maxDist2, (w, r2) => this.map[w] + str * (maxDist2 - r2));
      92             :         }
      93             :         else
      94           0 :                 this.runLoop(x0, x1, y0, y1, cx, cy, maxDist2, (w, r2) => this.map[w] + strength);
      95             : 
      96             : };
      97             : 
      98           0 : m.Map.prototype.multiplyInfluence = function(cx, cy, maxDist, strength, type = "constant")
      99             : {
     100           0 :         strength = strength ? +strength : +maxDist;
     101             : 
     102           0 :         const x0 = Math.max(0, cx - maxDist);
     103           0 :         const y0 = Math.max(0, cy - maxDist);
     104           0 :         const x1 = Math.min(this.width, cx + maxDist);
     105           0 :         const y1 = Math.min(this.height, cy + maxDist);
     106           0 :         const maxDist2 = maxDist * maxDist;
     107             : 
     108           0 :         if (type == "linear")
     109             :         {
     110           0 :                 const str = strength / maxDist;
     111           0 :                 this.runLoop(x0, x1, y0, y1, cx, cy, maxDist2, (w, r2) => str * (maxDist - Math.sqrt(r2)) * this.map[w]);
     112             :         }
     113           0 :         else if (type == "quadratic")
     114             :         {
     115           0 :                 const str = strength / maxDist2;
     116           0 :                 this.runLoop(x0, x1, y0, y1, cx, cy, maxDist2, (w, r2) => str * (maxDist2 - r2) * this.map[w]);
     117             :         }
     118             :         else
     119           0 :                 this.runLoop(x0, x1, y0, y1, cx, cy, maxDist2, (w, r2) => this.map[w] * strength);
     120             : };
     121             : 
     122             : /** add to current map by the parameter map pixelwise */
     123           0 : m.Map.prototype.add = function(map)
     124             : {
     125           0 :         for (let i = 0; i < this.length; ++i)
     126           0 :                 this.set(i, this.map[i] + map.map[i]);
     127             : };
     128             : 
     129             : /** Set the value taking overflow into account */
     130           0 : m.Map.prototype.set = function(i, value)
     131             : {
     132           0 :         this.map[i] = value < 0 ? 0 : value > this.maxVal ? this.maxVal : value;
     133             : };
     134             : 
     135             : /** Find the best non-obstructed tile */
     136           0 : m.Map.prototype.findBestTile = function(radius, obstruction)
     137             : {
     138             :         let bestIdx;
     139           0 :         let bestVal = 0;
     140           0 :         for (let j = 0; j < this.length; ++j)
     141             :         {
     142           0 :                 if (this.map[j] <= bestVal)
     143           0 :                         continue;
     144           0 :                 let i = this.getNonObstructedTile(j, radius, obstruction);
     145           0 :                 if (i < 0)
     146           0 :                         continue;
     147           0 :                 bestVal = this.map[j];
     148           0 :                 bestIdx = i;
     149             :         }
     150             : 
     151           0 :         return { "idx": bestIdx, "val": bestVal };
     152             : };
     153             : 
     154             : /** return any non obstructed (small) tile inside the (big) tile i from obstruction map */
     155           0 : m.Map.prototype.getNonObstructedTile = function(i, radius, obstruction)
     156             : {
     157           0 :         let ratio = this.cellSize / obstruction.cellSize;
     158           0 :         let ix = (i % this.width) * ratio;
     159           0 :         let iy = Math.floor(i / this.width) * ratio;
     160           0 :         let w = obstruction.width;
     161           0 :         let r2 = radius * radius;
     162             :         let lastPoint;
     163           0 :         for (let kx = ix; kx < ix + ratio; ++kx)
     164             :         {
     165           0 :                 if (kx < radius || kx >= w - radius)
     166           0 :                         continue;
     167           0 :                 for (let ky = iy; ky < iy + ratio; ++ky)
     168             :                 {
     169           0 :                         if (ky < radius || ky >= w - radius)
     170           0 :                                 continue;
     171           0 :                         if (lastPoint && (kx - lastPoint.x)*(kx - lastPoint.x) + (ky - lastPoint.y)*(ky - lastPoint.y) < r2)
     172           0 :                                 continue;
     173           0 :                         lastPoint = obstruction.isObstructedTile(kx, ky, radius);
     174           0 :                         if (!lastPoint)
     175           0 :                                 return kx + ky*w;
     176             :                 }
     177             :         }
     178           0 :         return -1;
     179             : };
     180             : 
     181             : /** return true if the area centered on tile kx-ky and with radius is obstructed */
     182           0 : m.Map.prototype.isObstructedTile = function(kx, ky, radius)
     183             : {
     184           0 :         let w = this.width;
     185           0 :         if (kx < radius || kx >= w - radius || ky < radius || ky >= w - radius || this.map[kx+ky*w] == 0)
     186           0 :                 return { "x": kx, "y": ky };
     187           0 :         if (!this.pattern || this.pattern[0] != radius)
     188             :         {
     189           0 :                 this.pattern = [radius];
     190           0 :                 let r2 = radius * radius;
     191           0 :                 for (let i = 1; i <= radius; ++i)
     192           0 :                         this.pattern.push(Math.floor(Math.sqrt(r2 - (i-0.5)*(i-0.5)) + 0.5));
     193             :         }
     194           0 :         for (let dy = 0; dy <= radius; ++dy)
     195             :         {
     196           0 :                 let dxmax = this.pattern[dy];
     197           0 :                 let xp = kx + (ky + dy)*w;
     198           0 :                 let xm = kx + (ky - dy)*w;
     199           0 :                 for (let dx = 0; dx <= dxmax; ++dx)
     200             :                 {
     201           0 :                         if (this.map[xp + dx] == 0)
     202           0 :                                 return { "x": kx + dx, "y": ky + dy };
     203           0 :                         if (this.map[xm + dx] == 0)
     204           0 :                                 return { "x": kx + dx, "y": ky - dy };
     205           0 :                         if (this.map[xp - dx] == 0)
     206           0 :                                 return { "x": kx - dx, "y": ky + dy };
     207           0 :                         if (this.map[xm - dx] == 0)
     208           0 :                                 return { "x": kx - dx, "y": ky - dy };
     209             :                 }
     210             :         }
     211           0 :         return null;
     212             : };
     213             : 
     214           0 : m.Map.prototype.dumpIm = function(name = "default.png", threshold = this.maxVal)
     215             : {
     216           0 :         Engine.DumpImage(name, this.map, this.width, this.height, threshold);
     217             : };
     218             : 
     219           0 : return m;
     220             : 
     221             : }(API3);

Generated by: LCOV version 1.14