[html]<!-- Морской бой на базе Deff-лотереи -->
<div id="battleship"></div>
<script>
(function(){
  const topicId = 5;          // ID темы Rusff
  const gameMaster = 'admin'; // Автор поста
  const size = 10;
  const letters = 'ABCDEFGHIJ'.split('');
  const turnDelay = 2*60*1000; // 2 минуты

  const wrap = document.getElementById('battleship');
  wrap.innerHTML = `
    <style>
      #battleship table {border-collapse: collapse; margin:0 auto;}
      #battleship td {width:42px;height:42px;border:1px solid #444;text-align:center;vertical-align:middle;cursor:pointer;background:#b0d4ff;font-weight:bold;}
      #battleship td.hit {background:#f00 url(https://forumstatic.ru/files/0014/cc/0a/39265.png) no-repeat center/70%;}
      #battleship td.miss {background:#9bb;opacity:0.7;}
      #battleship th {background:#e0f0ff;padding:5px;}
      #reset-game {margin-top:10px;display:none;}
    </style>
    <h2>⚓ Морской бой</h2>
    <div id="battle-field"></div>
    <button id="reset-game">Сбросить поле</button>
    <p id="game-status" style="margin-top:10px;font-weight:bold;"></p>
  `;

  // ---------------- Создаем поле ----------------
  function createField(){
    let html = '<table><tr><th></th>';
    for(let i=1;i<=size;i++) html+='<th>'+i+'</th>';
    html+='</tr>';
    for(let r=0;r<size;r++){
      html+='<tr><th>'+letters[r]+'</th>';
      for(let c=1;c<=size;c++){
        html+='<td data-cell="'+letters[r]+c+'"></td>';
      }
      html+='</tr>';
    }
    html+='</table>';
    document.getElementById('battle-field').innerHTML = html;
  }

  // ---------------- Расставляем корабли случайно ----------------
  function placeShips(){
    const shipsLen = [4,3,3,2,2,2,1,1,1,1];
    const taken = new Set();
    function randomDir(){return Math.random()<0.5?'h':'v';}
    function canPlace(r,c,len,dir){
      for(let i=0;i<len;i++){
        let rr=r+(dir==='v'?i:0), cc=c+(dir==='h'?i:0);
        if(rr>=size||cc>=size) return false;
        const key=rr+'_'+cc;
        if(taken.has(key)) return false;
        for(let dr=-1;dr<=1;dr++)
          for(let dc=-1;dc<=1;dc++)
            if(taken.has((rr+dr)+'_'+(cc+dc))) return false;
      }
      return true;
    }
    const ships=[];
    shipsLen.forEach(len=>{
      let placed=false;
      while(!placed){
        let r=Math.floor(Math.random()*size);
        let c=Math.floor(Math.random()*size);
        let dir=randomDir();
        if(canPlace(r,c,len,dir)){
          for(let i=0;i<len;i++){
            let rr=r+(dir==='v'?i:0), cc=c+(dir==='h'?i:0);
            taken.add(rr+'_'+cc);
            ships.push(rr+'_'+cc);
          }
          placed=true;
        }
      }
    });
    return ships;
  }

  // ---------------- Состояние игры ----------------
  let state = {
    ships: [],   // клетки кораблей
    shots: {},   // все выстрелы
    lastShot:{}  // время последнего выстрела игроков
  };

  // ---------------- Конвертируем ячейку ----------------
  function convertCell(cell){
    const row = letters.indexOf(cell[0]);
    const col = parseInt(cell.slice(1))-1;
    return row+'_'+col;
  }

  // ---------------- Отправляем сообщение в тему ----------------
  function postToTopic(msg, hit){
    $.post('/misc.php?item=ajax_lottery', {
      a:'message',
      id: topicId,
      msg: ''+msg+'',
      color: hit?'red':'blue'
    });
    document.getElementById('game-status').textContent = msg;
  }

  // ---------------- Рендер ----------------
  function render(){
    document.querySelectorAll('#battleship td[data-cell]').forEach(td=>{
      const cell=td.dataset.cell;
      td.className='';
      if(state.shots[cell]==='miss') td.classList.add('miss');
      else if(state.shots[cell]==='hit') td.classList.add('hit');
    });
  }

  // ---------------- Обработка кликов ----------------
  function activate(){
    document.querySelectorAll('#battleship td[data-cell]').forEach(td=>{
      td.addEventListener('click', e=>{
        const user = FORUM.user.name;
        const now = Date.now();
        if(state.lastShot[user] && now - state.lastShot[user]<turnDelay){
          alert('Можно стрелять раз в 2 минуты.');
          return;
        }
        const cell = e.target.dataset.cell;
        if(state.shots[cell]) return;
        const hit = state.ships.includes(convertCell(cell));
        state.shots[cell] = hit ? 'hit':'miss';
        state.lastShot[user]=now;
        render();
        saveState();
        postToTopic('Игрок '+user+' выстрелил в '+cell+' — '+(hit?'Попал!':'Мимо.'), hit);
      });
    });

    if(FORUM.user.name===gameMaster){
      const btn=document.getElementById('reset-game');
      btn.style.display='inline-block';
      btn.onclick=function(){
        if(confirm('Сбросить поле и расставить корабли заново?')){
          state.ships=[]; state.shots={}; state.lastShot={};
          state.ships=placeShips();
          render(); saveState();
          postToTopic('⚓ Поле сброшено администратором!', false);
        }
      };
    }
  }

  // ---------------- Сохраняем и загружаем ----------------
  function saveState(){
    $.post('/misc.php?item=ajax_lottery', {
      a:'save',
      id: topicId,
      data: JSON.stringify(state)
    });
  }

  function loadState(cb){
    $.get('/misc.php?item=ajax_lottery&id='+topicId+'&action=get', function(res){
      try { state=JSON.parse(res); } catch(e){ state={ships:[],shots:{},lastShot:{}}; }
      if(!state.ships.length) state.ships=placeShips();
      if(cb) cb();
    });
  }

  // ---------------- Инициализация ----------------
  createField();
  loadState(function(){
    render();
    activate();
  });
})();
</script>
[/html]