function решить(в) {
  const N = 15;
  const INF = 1e9;
  const ход = в.ход;
  const я = в.я;
  const п = в.память || {};
  const о = в.общая || {};
  const bx = в.моя_база.x, by = в.моя_база.y;
  const ex = в.чужая_база.x, ey = в.чужая_база.y;
  const myIdStr = String(я.id);
  const myNum = parseInt(myIdStr.replace(/\D/g, ''), 10) || 0;
  const role = myNum % 4;
  const selfIdx = (я.y * N) + я.x;

  function idx(x, y) { return y * N + x; }
  function key(x, y) { return x + ',' + y; }
  function out(x, y) { return x < 0 || y < 0 || x >= N || y >= N; }
  function man(x1, y1, x2, y2) { return Math.abs(x1 - x2) + Math.abs(y1 - y2); }
  function dirTo(sx, sy, nx, ny) {
    if (nx === sx && ny === sy - 1) return 'С';
    if (nx === sx && ny === sy + 1) return 'Ю';
    if (nx === sx + 1 && ny === sy) return 'В';
    if (nx === sx - 1 && ny === sy) return 'З';
    return null;
  }
  function parseKey(k) {
    let i = k.indexOf(',');
    return [+k.slice(0, i), +k.slice(i + 1)];
  }

  if (!о.к || typeof о.к !== 'string' || о.к.length !== N * N) {
    let s = '';
    for (let i = 0; i < N * N; i++) s += '?';
    о.к = s;
  }
  о.еда = о.еда || {};
  о.еда_сим = о.еда_сим || {};
  о.видел = о.видел || {};
  о.цели = о.цели || {};
  о.анты = о.анты || {};
  о.враги = о.враги || {};
  о.зоны = о.зоны || {};
  о.удары = о.удары || {};

  function setOne(з, x, y, isWall) {
    if (out(x, y)) return;
    let i = idx(x, y);
    if (з.к[i] !== '?') return;
    з.к = з.к.substring(0, i) + (isWall ? '#' : '.') + з.к.substring(i + 1);
  }

  function setMapSym(з, x, y, isWall) {
    setOne(з, x, y, isWall);
    setOne(з, N - 1 - x, N - 1 - y, isWall);
  }

  о.анты[myIdStr] = [я.x, я.y, я.здоровье, я.груз, ход].join('|');

  let враги = [];
  let свои = [];
  let виделВрага = {};
  let виделСоюзника = {};
  let currentFood = 0;

  for (let vi = 0; vi < в.видно.length; vi++) {
    let кл = в.видно[vi];
    let x = кл.x, y = кл.y;
    let k = key(x, y);
    о.видел[k] = ход;

    setMapSym(о, x, y, кл.что === 'стена');

    if (кл.еда > 0) {
      о.еда[k] = кл.еда + ',' + ход;
      delete о.еда_сим[k];
      if (x === я.x && y === я.y) currentFood = кл.еда;

      let mx = N - 1 - x, my = N - 1 - y;
      let mk = key(mx, my);
      if (!о.еда[mk] && !о.видел[mk]) {
        о.еда[mk] = кл.еда + ',' + ход;
        о.еда_сим[mk] = ход;
      }
    } else {
      delete о.еда[k];
      delete о.еда_сим[k];
    }

    if (кл.что === 'враг') {
      if (!виделВрага[k]) {
        виделВрага[k] = true;
        враги.push({ x: x, y: y });
      }
      о.враги[k] = ход;
      for (let dx = -2; dx <= 2; dx++) {
        for (let dy = -2; dy <= 2; dy++) {
          let nx = x + dx, ny = y + dy;
          if (!out(nx, ny) && Math.abs(dx) + Math.abs(dy) <= 2) {
            о.зоны[key(nx, ny)] = ход;
          }
        }
      }
    } else if (кл.что === 'свой') {
      if (x !== я.x || y !== я.y) {
        if (!виделСоюзника[k]) {
          виделСоюзника[k] = true;
          свои.push({ x: x, y: y });
        }
      }
    }
  }

  let blocked = {};
  for (let i = 0; i < враги.length; i++) blocked[key(враги[i].x, враги[i].y)] = true;
  for (let i = 0; i < свои.length; i++) blocked[key(свои[i].x, свои[i].y)] = true;
  for (let id in о.анты) {
    if (id === myIdStr) continue;
    let p = о.анты[id].split('|');
    if (p.length < 5) continue;
    let ax = +p[0], ay = +p[1], at = +p[4];
    if (ход - at <= 1 && !out(ax, ay)) blocked[key(ax, ay)] = true;
  }

  for (let id in о.цели) {
    let p = о.цели[id];
    if (!p) continue;
    let arr = String(p).split(',');
    if (arr.length >= 3 && ход - (+arr[2]) > 8) delete о.цели[id];
  }
  for (let id in о.анты) {
    let p = о.анты[id].split('|');
    if (p.length >= 5 && ход - (+p[4]) > 30) delete о.анты[id];
  }
  for (let k in о.враги) {
    if (ход - о.враги[k] > 3) delete о.враги[k];
  }
  for (let k in о.зоны) {
    if (ход - о.зоны[k] > 5) delete о.зоны[k];
  }
  for (let k in о.удары) {
    let p = String(о.удары[k]).split(',');
    if (p.length >= 2 && ход - (+p[1]) > 20) delete о.удары[k];
  }

  function dangerAt(nx, ny) {
    let d = 0;
    for (let k in о.зоны) {
      let age = ход - о.зоны[k];
      if (age < 0 || age > 3) continue;
      let q = parseKey(k);
      let md = man(nx, ny, q[0], q[1]);
      if (md <= 2) d += (3 - md) * (age === 0 ? 12 : 6);
    }
    for (let k in о.враги) {
      let age = ход - о.враги[k];
      if (age < 0 || age > 1) continue;
      let q = parseKey(k);
      let md = man(nx, ny, q[0], q[1]);
      if (md <= 2) d += (3 - md) * 18;
    }
    return d;
  }

  function reconstructStart(ci, startIdx, prev) {
    if (ci === startIdx) return startIdx;
    let cur = ci;
    let guard = 0;
    while (prev[cur] !== -1 && prev[cur] !== startIdx && guard < 300) {
      cur = prev[cur];
      guard++;
    }
    return cur;
  }

  function findPaths(sx, sy, targetFn, blockedMap, ctx) {
    let startIdx = idx(sx, sy);
    let dist = new Array(N * N);
    let prev = new Array(N * N);
    let done = new Array(N * N);
    for (let i = 0; i < N * N; i++) {
      dist[i] = INF;
      prev[i] = -1;
      done[i] = 0;
    }
    dist[startIdx] = 0;

    let heap = [{ i: startIdx, d: 0 }];

    function heapPush(node) {
      heap.push(node);
      let i = heap.length - 1;
      while (i > 0) {
        let p = (i - 1) >> 1;
        if (heap[p].d <= heap[i].d) break;
        let t = heap[p]; heap[p] = heap[i]; heap[i] = t;
        i = p;
      }
    }
    function heapPop() {
      let top = heap[0];
      let last = heap.pop();
      if (heap.length) {
        heap[0] = last;
        let i = 0;
        while (true) {
          let l = i * 2 + 1, r = i * 2 + 2, m = i;
          if (l < heap.length && heap[l].d < heap[m].d) m = l;
          if (r < heap.length && heap[r].d < heap[m].d) m = r;
          if (m === i) break;
          let t = heap[i]; heap[i] = heap[m]; heap[m] = t;
          i = m;
        }
      }
      return top;
    }

    function cellCost(nx, ny, ch) {
      let c = 1;
      if (ch === '?') c += ctx.unknownPenalty || 3;
      let dng = dangerAt(nx, ny);
      if (dng > 0) {
        if (ctx.cargo) c += dng * 3;
        else if (ctx.hp <= 1) c += dng * 5;
        else if (ctx.hp === 2) c += dng * 2;
        else c += dng;
      }
      return c;
    }

    let results = [];
    let dirs4 = [[0, -1], [0, 1], [-1, 0], [1, 0]];

    while (heap.length && results.length < ctx.max) {
      let cur = heapPop();
      let ci = cur.i;
      if (done[ci]) continue;
      done[ci] = 1;

      let cx = ci % N;
      let cy = (ci / N) | 0;

      if (targetFn(cx, cy) && !blockedMap[key(cx, cy)]) {
        let next = reconstructStart(ci, startIdx, prev);
        results.push({ x: cx, y: cy, cost: cur.d, next: next });
        if (results.length >= ctx.max) break;
      }

      for (let d = 0; d < 4; d++) {
        let nx = cx + dirs4[d][0];
        let ny = cy + dirs4[d][1];
        if (out(nx, ny)) continue;
        let ni = idx(nx, ny);
        if (done[ni]) continue;
        let ch = о.к[ni];
        if (ch === '#') continue;
        if (!ctx.allowUnknown && ch === '?') continue;
        let nk = key(nx, ny);
        if (blockedMap[nk]) continue;

        let nd = cur.d + cellCost(nx, ny, ch);
        if (nd < dist[ni]) {
          dist[ni] = nd;
          prev[ni] = ci;
          heapPush({ i: ni, d: nd });
        }
      }
    }

    return results;
  }

  function actionFromNext(nextIdx) {
    if (nextIdx === undefined || nextIdx === null || nextIdx < 0) return null;
    if (nextIdx === selfIdx) return null;
    let nx = nextIdx % N;
    let ny = (nextIdx / N) | 0;
    let d = dirTo(я.x, я.y, nx, ny);
    if (!d) return null;
    return { тип: 'идти', куда: d };
  }

  function countSupport(enemy) {
    let cnt = 0;
    if (man(я.x, я.y, enemy.x, enemy.y) === 1) cnt++;
    for (let i = 0; i < свои.length; i++) {
      if (man(свои[i].x, свои[i].y, enemy.x, enemy.y) === 1) cnt++;
    }
    return cnt;
  }

  let adjacentEnemies = [];
  for (let i = 0; i < враги.length; i++) {
    if (man(я.x, я.y, враги[i].x, враги[i].y) === 1) adjacentEnemies.push(враги[i]);
  }

  function chooseFight() {
    let best = null;
    let bestScore = -9999;
    for (let i = 0; i < adjacentEnemies.length; i++) {
      let e = adjacentEnemies[i];
      let ek = key(e.x, e.y);
      let dmg = 0;
      if (о.удары[ek]) {
        let p = String(о.удары[ek]).split(',');
        if (p.length >= 2 && ход - (+p[1]) <= 10) dmg = +p[0] || 0;
      }
      let support = countSupport(e);
      let dBase = man(e.x, e.y, bx, by);
      let score = support * 3 + dmg * 5;
      if (dBase <= 3) score += 4;
      if (я.груз) score -= 4;
      if (я.здоровье === 1) score -= 6;
      else if (я.здоровье === 2) score -= 2;
      if (score > bestScore) {
        bestScore = score;
        best = e;
      }
    }
    if (!best) return null;

    let ek = key(best.x, best.y);
    let dmg = 0;
    if (о.удары[ek]) {
      let p = String(о.удары[ek]).split(',');
      if (p.length >= 2 && ход - (+p[1]) <= 10) dmg = +p[0] || 0;
    }
    let support = countSupport(best);
    let dBase = man(best.x, best.y, bx, by);

    if (support >= 2 || dmg >= 2) return best;
    if (support >= 1 && я.здоровье >= 3 && !я.груз && dBase <= 4) return best;
    if (support >= 1 && я.здоровье >= 3 && !я.груз && dmg >= 1) return best;
    return null;
  }

  function goDangerAway() {
    let dirs = [[0, -1, 'С'], [0, 1, 'Ю'], [-1, 0, 'З'], [1, 0, 'В']];
    let bestDir = null;
    let bestDanger = Infinity;
    let bestTie = 999;
    for (let d = 0; d < 4; d++) {
      let nx = я.x + dirs[d][0];
      let ny = я.y + dirs[d][1];
      if (out(nx, ny)) continue;
      let ni = idx(nx, ny);
      if (о.к[ni] === '#') continue;
      if (blocked[key(nx, ny)]) continue;
      let dng = dangerAt(nx, ny);
      let tie = (nx * 5 + ny * 7 + myNum * 3) % 11;
      if (dng < bestDanger || (dng === bestDanger && tie < bestTie)) {
        bestDanger = dng;
        bestTie = tie;
        bestDir = dirs[d][2];
      }
    }
    return bestDir ? { тип: 'идти', куда: bestDir } : null;
  }

  function goToBase(carrying) {
    let baseKey = key(bx, by);
    let destKeys = [];
    if (!blocked[baseKey]) destKeys.push(baseKey);

    let dirs = [[0, -1], [0, 1], [-1, 0], [1, 0]];
    for (let d = 0; d < 4; d++) {
      let nx = bx + dirs[d][0];
      let ny = by + dirs[d][1];
      if (out(nx, ny)) continue;
      let ni = idx(nx, ny);
      if (о.к[ni] === '#') continue;
      let nk = key(nx, ny);
      if (blocked[nk]) continue;
      if (destKeys.indexOf(nk) < 0) destKeys.push(nk);
    }
    if (!destKeys.length) return null;

    let found = findPaths(
      я.x,
      я.y,
      function (x, y) { return destKeys.indexOf(key(x, y)) !== -1; },
      blocked,
      {
        allowUnknown: true,
        cargo: !!carrying,
        hp: я.здоровье,
        max: 8,
        unknownPenalty: carrying ? 4 : 2
      }
    );

    if (!found.length) return null;
    return actionFromNext(found[0].next);
  }

  function targetFood(x, y) {
    let f = о.еда[key(x, y)];
    if (!f) return false;
    let amt = parseInt(String(f).split(',')[0], 10);
    return amt > 0;
  }

  function goFood() {
    let found = findPaths(
      я.x,
      я.y,
      targetFood,
      blocked,
      {
        allowUnknown: true,
        cargo: false,
        hp: я.здоровье,
        max: 25,
        unknownPenalty: 2
      }
    );
    if (!found.length) return null;

    let best = null;
    let bestScore = Infinity;
    let bestKey = '';

    for (let i = 0; i < found.length; i++) {
      let cand = found[i];
      let ck = key(cand.x, cand.y);
      let f = String(о.еда[ck]);
      let arr = f.split(',');
      let amt = +arr[0] || 0;
      let last = +arr[1] || ход;
      let age = ход - last;
      let homeD = man(cand.x, cand.y, bx, by);
      let enemyD = man(cand.x, cand.y, ex, ey);

      let bias = (role % 2 === 0) ? 2.5 : -2.5;
      let score = cand.cost * 2 + homeD * 1.2 - amt * 3;
      score += bias * (homeD - enemyD);
      score += Math.min(age, 20) * 0.3;

      let claimed = 0;
      for (let id in о.цели) {
        if (id === myIdStr) continue;
        let c = о.цели[id];
        if (!c) continue;
        let p = String(c).split(',');
        if (p.length >= 3 && p[0] == cand.x && p[1] == cand.y) {
          if (ход - (+p[2]) <= 8) claimed++;
        }
      }
      if (amt >= 3) score += claimed * 6;
      else if (amt === 2) score += claimed * 25;
      else score += claimed * 60;

      score += (cand.x * 7 + cand.y * 11 + myNum * 3) % 9;

      if (score < bestScore || (score === bestScore && ck < bestKey)) {
        best = cand;
        bestScore = score;
        bestKey = ck;
      }
    }

    if (!best) return null;
    п.цель = best.x + ',' + best.y + ',' + ход;
    о.цели[myIdStr] = п.цель;

    if (best.next === selfIdx) return { тип: 'взять' };
    return actionFromNext(best.next);
  }

  function goExplore() {
    let found = findPaths(
      я.x,
      я.y,
      function (x, y) { return о.к[idx(x, y)] === '?'; },
      blocked,
      {
        allowUnknown: true,
        cargo: false,
        hp: я.здоровье,
        max: 25,
        unknownPenalty: 2
      }
    );
    if (!found.length) return null;

    let best = null;
    let bestScore = Infinity;
    let bestKey = '';

    for (let i = 0; i < found.length; i++) {
      let cand = found[i];
      let ck = key(cand.x, cand.y);
      let unknownCnt = 0;
      let dirs = [[0, -1], [0, 1], [-1, 0], [1, 0]];
      for (let d = 0; d < 4; d++) {
        let nx = cand.x + dirs[d][0];
        let ny = cand.y + dirs[d][1];
        if (!out(nx, ny) && о.к[idx(nx, ny)] === '?') unknownCnt++;
      }

      let homeD = man(cand.x, cand.y, bx, by);
      let enemyD = man(cand.x, cand.y, ex, ey);
      let bias = (role % 2 === 0) ? 2.0 : -2.0;
      let score = cand.cost * 2 - unknownCnt * 4 + bias * (enemyD - homeD);

      let claimed = 0;
      for (let id in о.цели) {
        if (id === myIdStr) continue;
        let c = о.цели[id];
        if (!c) continue;
        let p = String(c).split(',');
        if (p.length >= 3 && p[0] == cand.x && p[1] == cand.y) {
          if (ход - (+p[2]) <= 8) claimed++;
        }
      }
      score += claimed * 30;
      score += (cand.x * 5 + cand.y * 13 + myNum * 7) % 11;

      if (score < bestScore || (score === bestScore && ck < bestKey)) {
        best = cand;
        bestScore = score;
        bestKey = ck;
      }
    }

    if (!best) return null;
    п.цель = best.x + ',' + best.y + ',' + ход;
    о.цели[myIdStr] = п.цель;
    return actionFromNext(best.next);
  }

  if (я.груз === 1 && я.x === bx && я.y === by) {
    return { действие: { тип: 'положить' }, память: п, общая: о };
  }

  let fight = chooseFight();
  if (fight) {
    let ek = key(fight.x, fight.y);
    let old = 0;
    if (о.удары[ek]) {
      let p = String(о.удары[ek]).split(',');
      old = +p[0] || 0;
    }
    о.удары[ek] = (old + 1) + ',' + ход;
    let fightDir = dirTo(я.x, я.y, fight.x, fight.y);
    if (fightDir) {
      return { действие: { тип: 'бить', куда: fightDir }, память: п, общая: о };
    }
  }

  let remaining = в.всего_ходов - ход;

  if (я.груз === 1) {
    let baseAct = goToBase(true);
    if (baseAct) return { действие: baseAct, память: п, общая: о };

    if (man(я.x, я.y, bx, by) === 1 && blocked[key(bx, by)]) {
      return { действие: { тип: 'ждать' }, память: п, общая: о };
    }

    let awayAct = goDangerAway();
    if (awayAct) return { действие: awayAct, память: п, общая: о };

    if (adjacentEnemies.length) {
      let d = dirTo(я.x, я.y, adjacentEnemies[0].x, adjacentEnemies[0].y);
      if (d) return { действие: { тип: 'бить', куда: d }, память: п, общая: о };
    }

    return { действие: { тип: 'ждать' }, память: п, общая: о };
  }

  if (currentFood > 0) {
    return { действие: { тип: 'взять' }, память: п, общая: о };
  }

  if (remaining > 0 && remaining < man(я.x, я.y, bx, by) + 2) {
    let baseAct = goToBase(false);
    if (baseAct) return { действие: baseAct, память: п, общая: о };
  }

  let foodAct = goFood();
  if (foodAct) return { действие: foodAct, память: п, общая: о };

  let exploreAct = goExplore();
  if (exploreAct) return { действие: exploreAct, память: п, общая: о };

  let fallback = goToBase(false) || goDangerAway();
  if (fallback) return { действие: fallback, память: п, общая: о };

  return { действие: { тип: 'ждать' }, память: п, общая: о };
}
