Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > разработка игр, графический дизайн и моделирование > Gamedev - cоздание игр: Unity, OpenGL, DirectX
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.05.2016, 21:43   #1
Armageddets
Форумчанин
 
Регистрация: 30.06.2012
Сообщений: 145
По умолчанию Делаю игру - аналог морского боя.Зависает игра и не присваются данные

Всем привет, уважаемые эксперты. Пишу игру, которая похожа на морской бой. Генерируется поле 8х8, на котором нужно вместить все корабли. В ней три уровня сложности. Первый и третий я реализовал.А вот со вторым проблемы. На втором уровне сложности должен генерироваться не один вараинт правильной расстановки, а два. То есть я использую два массива одного размера. Первый массив у меня на всех уровнях заполняется нормально. А вот на втором программа виснет. Так и мало того - еще и не изменяются переменные, когда я заношу в них данные. Я например присваиваю u:=true; И это дложно заставить выйти из цикла вайл, но переменная остается равной false, хотя я нигде ей не присваиваю такое значение внутри цикла. Еще я использую рекурсии. Поэтому подозреваю либо дело в рекурсиях, либо дело в самом компиляторе - однажды компилятор выдавал чудеса...

Проблемный код тут:
Код:
u:=False;
      while (u=false) do
      begin
      n:=Random(2);
      i:=Random(8);
      j:=Random(8);

        if (u=False) and (n=0) and (i+3<=7) and (map2[i,j]=0) and (map2[i+1,j]=0) and (map2[i+2,j]=0) and (map2[i+3,j]=0) then
        begin
        u:=True;
        map2[i,j]:=2;
        map2[i+1,j]:=2;
        map2[i+2,j]:=2;
        map2[i+3,j]:=2;
        //volni;
        end;
        if (u=false) and (n=1) and (j+3<=7) and (map2[i,j]=0) and (map2[i,j+1]=0) and (map2[i,j+2]=0) and (map2[i,j+3]=0) then
        begin
        u:=True;
        map2[i,j]:=2;
        map2[i,j+1]:=2;
        map2[i,j+2]:=2;
        map2[i,j+3]:=2;
        //volni;
        end;
      end;
Заранее спасибо всем, кто откликнется - вы меня не раз уже спасали. Спасибо вам.
Так же прилагаю весь проект, так как логически в этом коде все правильно вроде. Пароль вроде не ставил на архив, но если поставил по привычке, то пароль 1:
https://yadi.sk/d/4IbT9hpIrYxZr
Armageddets вне форума Ответить с цитированием
Старый 08.05.2016, 02:21   #2
rok_9
 
Регистрация: 10.11.2012
Сообщений: 7
По умолчанию

Цитата:
Сообщение от Armageddets Посмотреть сообщение
Всем привет, уважаемые эксперты. Пишу игру, которая похожа на морской бой. Генерируется поле 8х8, на котором нужно вместить все корабли. В ней три уровня сложности. Первый и третий я реализовал.А вот со вторым проблемы. На втором уровне сложности должен генерироваться не один вараинт правильной расстановки, а два. То есть я использую два массива одного размера. Первый массив у меня на всех уровнях заполняется нормально. А вот на втором программа виснет. Так и мало того - еще и не изменяются переменные, когда я заношу в них данные. Я например присваиваю u:=true; И это дложно заставить выйти из цикла вайл, но переменная остается равной false, хотя я нигде ей не присваиваю такое значение внутри цикла. Еще я использую рекурсии. Поэтому подозреваю либо дело в рекурсиях, либо дело в самом компиляторе - однажды компилятор выдавал чудеса...

Проблемный код тут:
Код:
u:=False;
      while (u=false) do
      begin
      n:=Random(2);
      i:=Random(8);
      j:=Random(8);

        if (u=False) and (n=0) and (i+3<=7) and (map2[i,j]=0) and (map2[i+1,j]=0) and (map2[i+2,j]=0) and (map2[i+3,j]=0) then
        begin
        u:=True;
        map2[i,j]:=2;
        map2[i+1,j]:=2;
        map2[i+2,j]:=2;
        map2[i+3,j]:=2;
        //volni;
        end;
        if (u=false) and (n=1) and (j+3<=7) and (map2[i,j]=0) and (map2[i,j+1]=0) and (map2[i,j+2]=0) and (map2[i,j+3]=0) then
        begin
        u:=True;
        map2[i,j]:=2;
        map2[i,j+1]:=2;
        map2[i,j+2]:=2;
        map2[i,j+3]:=2;
        //volni;
        end;
      end;
Заранее спасибо всем, кто откликнется - вы меня не раз уже спасали. Спасибо вам.
Так же прилагаю весь проект, так как логически в этом коде все правильно вроде. Пароль вроде не ставил на архив, но если поставил по привычке, то пароль 1:
https://yadi.sk/d/4IbT9hpIrYxZr
Во-первых от такой конструкции (u=false) , надо избавляться.
правильно так (not u).
А вообще проще так:
Код:
while (true) do
begin
  //Какой-то код
  if(надо выйти) 
  begin
    //Какойто код
    break;
   //Тут код не будет выполнен

  end;
end;
А во-вторых все симптомы указывают на то что этот код зацикливается.
rok_9 вне форума Ответить с цитированием
Старый 08.05.2016, 05:35   #3
challengerr
Участник клуба
 
Аватар для challengerr
 
Регистрация: 30.07.2008
Сообщений: 1,605
По умолчанию

Числа random не случайные, а псевдослучайные. На каждой итерации могут генерироваться одни и те же числа, поэтому цикл становится бесконечным. Зерно для генерации псевдослучайных чисел нужно менять на каждой итерации.
"SPACE.THE FINAL FRONTIER.This's a voyage of starship Enterprise. It's 5-year mission to explore strange new worlds,to seek out new life and civilizations,to boldly go where no man has gone before"
challengerr вне форума Ответить с цитированием
Старый 09.05.2016, 01:22   #4
Armageddets
Форумчанин
 
Регистрация: 30.06.2012
Сообщений: 145
По умолчанию

Спасибо за советы. Учел Ваши просьбы и есть некоторые сдвиги - код стал выполняться хоть иногда. Иногда зависает, но иногда и срабатывает. Правда при срабатывании ставит 2-3 корабля четырехпалубных почему-то. В Коде изменил на такого вида циклы, которые должны ставить 1 корабль:

Код:
//sluchayno stavim 4 palubi
  while (true) do
  begin
  Randomize;
  n:=Random(2);
  i:=Random(8);
  j:=Random(8);
    if (n=0) and (i+3<=7) and (map1[i,j]=0) and (map1[i+1,j]=0) and (map1[i+2,j]=0) and (map1[i+3,j]=0) then
    begin
    map1[i,j]:=2;
    map1[i+1,j]:=2;
    map1[i+2,j]:=2;
    map1[i+3,j]:=2;
    volni;
    Break;
    end;
    if (n=1) and (j+3<=7) and (map1[i,j]=0) and (map1[i,j+1]=0) and (map1[i,j+2]=0) and (map1[i,j+3]=0) then
    begin
    map1[i,j]:=2;
    map1[i,j+1]:=2;
    map1[i,j+2]:=2;
    map1[i,j+3]:=2;
    volni;
    Break;
    end;
  end;
А некоторые циклы оставил таки через переменные, так как они должны выполниться несколько раз. Собственно эта часть кода и зацикливается. Через точки прерывания оказалось, что я присваивая переменным нужные значение при следующей итерации цикла все сбивается. То есть мои значения пропадают. Помогите, может кто-то с таким сталкивался?
Код:
//esli slozhnost srednyaya
  if Slozhnost=2 then
  begin
    Num:=0;
    //rasstavlyaem po drugomu korabli
    w:=False; //schitaem chto pole tak zhe zapolnilo ili ne zapolnilo eshe
    //while w=False do
    //begin

      //sluchayno stavim 4 palubi
      while (Num=0) do
      begin
      Randomize;
      n:=Random(2);
      i:=Random(8);
      j:=Random(8);

        if (n=0) and (i+3<=7) and (map2[i,j]=0) and (map2[i+1,j]=0) and (map2[i+2,j]=0) and (map2[i+3,j]=0) then
        begin
        u:=True;
        map2[i,j]:=2;
        map2[i+1,j]:=2;
        map2[i+2,j]:=2;
        map2[i+3,j]:=2;
        volni;
        inc(Num);
        Break;
        end;
        if (n=1) and (j+3<=7) and (map2[i,j]=0) and (map2[i,j+1]=0) and (map2[i,j+2]=0) and (map2[i,j+3]=0) then
        begin
        u:=True;
        map2[i,j]:=2;
        map2[i,j+1]:=2;
        map2[i,j+2]:=2;
        map2[i,j+3]:=2;
        volni;
        inc(Num);
        Break;
        end;

      end;
  end;
В общем опять уповаю на Ваши советы... с таким не сталкивался просто. Заранее спасибо Вам.

Сам измененный проект прилагаю. Зависания происходят и неправильное количество кораблей становится если выбрать сложность среднюю в меню.

https://yadi.sk/d/SSuYsejNrZzZF
Armageddets вне форума Ответить с цитированием
Старый 09.05.2016, 03:10   #5
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,356
По умолчанию

Код:
const
  pole_size = 8;
  MAX_ERR = 250;

type
  pole = array [0 .. pole_size - 1, 0 .. pole_size - 1] of Integer;

...

procedure volna(var m: pole);
var
  i, j, k1, k2, i1, j1: Integer;
begin
  for i := 0 to pole_size - 1 do
    for j := 0 to pole_size - 1 do
    begin
      if m[i, j] <> 2 then
        continue;
      for k1 := -1 to 1 do
        for k2 := -1 to 1 do
        begin
          if (k1 = 0) and (k2 = 0) then
            continue;
          i1 := i + k1;
          j1 := j + k2;
          if (i1 < 0) or (i1 >= pole_size) or (j1 < 0) or (j1 >= pole_size) then
            continue;
          if m[i1, j1] <> 0 then
            continue;
          m[i1, j1] := 1;
        end;
    end;
end;

...

procedure Rasstanovka;
const
  // X - dlina korablia
  // Y - colichestvo
  ships: array [0 .. 3] of TPoint = ((X: 4; Y: 1), (X: 3; Y: 2), (X: 2; Y: 3),
    (X: 1; Y: 4));
var
  map: pole;
  i, j, N, k, count, err_count, z: Integer;
begin
  Randomize;
  for i := 0 to pole_size - 1 do
    for j := 0 to pole_size - 1 do
      map[i, j] := 0;
  err_count := 0;
  for k := low(ships) to high(ships) do
  begin
    if err_count >= MAX_ERR then
      break;
    for count := 1 to ships[k].Y do
      while err_count < MAX_ERR do
      begin
        N := random(2);
        i := pole_size - (ships[k].X - 1) * (1 - N);
        j := pole_size - (ships[k].X - 1) * N;
        if (i < 0) or (j < 0) then
        begin
          err_count := MAX_ERR;
          break;
        end;
        i := random(i);
        j := random(j);
        z := 0;
        while (z < ships[k].X) and (map[i + z * (1 - N), j + z * N] = 0) do
          inc(z);
        if z = ships[k].X then
        begin
          for z := 0 to ships[k].X - 1 do
            map[i + z * (1 - N), j + z * N] := 2;
          volna(map);
          break;
        end
        else
          inc(err_count);
      end;
  end;
  if err_count >= MAX_ERR then
    // Oshibka
  else
    // V "map" karta korabley
end;
Не разбирался, что вы еще проверяете в расстановке. В этом коде только расстановка кораблей на поле map.
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )

Последний раз редактировалось BDA; 09.05.2016 в 03:50.
BDA вне форума Ответить с цитированием
Старый 09.05.2016, 15:47   #6
Armageddets
Форумчанин
 
Регистрация: 30.06.2012
Сообщений: 145
По умолчанию

Поставил Ваши процедуры и переделал код именно под эти процедуры, но всеравно при заполнении одного массива все нормально, а при заполнении двух (при средней сложности) - пишет Stack is overflow. То есть переполняется стек, насколько я понимаю. Я подозреваю что тоже идет зацикливание (так как процедуры перезапускаются в случае если нельзя поставить нужное количество кораблей). Пока застрял на этом же моменте, что и в моем алгоритме (зависает или выдает ошибку при расстановке на втором поле).

Я не знаю как решить данную проблему. Компьютеру сложнее найти варианты расстановки еще и потому, что некоторые клетки запрещаются по краям карты для расстановки (а них заносится -1 и они рисуются черным цветом).

Если не зацикливать процедуры, тогда часто на поле появляется меньше кораблей чем положено (ведь просто негде поставить).

При клике по началу игры срабатывает следующий код:
Код:
VidFormi;
  Rasstanovka(map1);
  if Slozhnost=2 then
  Rasstanovka(map2);
  Form1.Timer1.Enabled:=True;
VidFormi; - там происходит обнуление всех массивов и по краям карты во всех массивах запрещаются некоторые клетки:

Код:
procedure VidFormi;
var i,j,proc,min,max:integer;
begin
  Current:=0; //postavleno korabley
  for i:=1 to 10 do
  begin
  Ochered[i].N:=0;
    for j:=1 to 4 do
    begin
    Ochered[i].K[j].X:=-1;
    Ochered[i].K[j].Y:=-1;
    end;
  end;

  Activ:=0;
  Povorot:=0;
  //vse figuri sprava dostupni dlya vibora
  for i:=1 to 10 do
  Figura[i]:=True;

  for i:=0 to 7 do
  for j:=0 to 7 do
  begin
  map[i,j]:=0;
  map1[i,j]:=0;
  map2[i,j]:=0;
  end;
  Randomize;
  proc:=30;
  min:=5;

  //sluchayno zadaem formu
  //sboku zakrivaem lishnie granitsi
  for i:=0 to 7 do
  begin
    j:=random(100);
    if j<=proc then
    begin
    map[i,0]:=-1;
    map1[i,0]:=-1;
    map2[i,0]:=-1;
      j:=random(100);
      if j<=min then
      begin
      map[i,1]:=-1;
      map1[i,1]:=-1;
      map2[i,1]:=-1;
      end;
    end;
    j:=random(100);
    if j<=proc then
    begin
    map[0,i]:=-1;
    map1[0,i]:=-1;
    map2[0,i]:=-1;
      j:=random(100);
      if j<=min then
      begin
      map[1,i]:=-1;
      map1[1,i]:=-1;
      map2[1,i]:=-1;
      end;
    end;
    j:=random(100);
    if j<=proc then
    begin
    map[i,7]:=-1;
    map1[i,7]:=-1;
    map2[i,7]:=-1;
      j:=random(100);
      if j<=min then
      begin
      map[i,6]:=-1;
      map1[i,6]:=-1;
      map2[i,6]:=-1;
      end;
    end;
    j:=random(100);
    if j<=proc then
    begin
    map[7,i]:=-1;
    map1[7,i]:=-1;
    map2[7,i]:=-1;
      j:=random(100);
      if j<=min then
      begin
      map[6,i]:=-1;
      map1[6,i]:=-1;
      map2[6,i]:=-1;
      end;
    end;
  end;

  //proverka na zakritie oblasti esli oni na 2 i bolee kvadrata v dlinu
  for i:=0 to 7 do
  begin
    if (map1[i,1]=-1) and (map1[i,0]=0) then begin map1[i,0]:=-1; map[i,0]:=-1; map2[i,0]:=-1; end;
    if (map1[i,6]=-1) and (map1[i,7]=0) then begin map1[i,7]:=-1; map[i,7]:=-1; map2[i,7]:=-1; end;
    if (map1[1,i]=-1) and (map1[0,i]=0) then begin map1[0,i]:=-1; map[0,i]:=-1; map2[0,i]:=-1; end;
    if (map1[6,i]=-1) and (map1[7,i]=0) then begin map1[7,i]:=-1; map[7,i]:=-1; map2[7,i]:=-1; end;
  end;
end;
Виснет, понятное дело, на моменте расстановке тут:
Код:
procedure Rasstanovka(var map:TPole);
const
  // X - dlina korablia
  // Y - colichestvo
  ships: array [0 .. 3] of TPoint = ((X: 4; Y: 1), (X: 3; Y: 2), (X: 2; Y: 3),
    (X: 1; Y: 4));
var
  i, j, N, k, count, err_count, z: Integer;
begin
  Win:=false;
  //VidFormi;
  {
  for i := 0 to pole_size - 1 do
    for j := 0 to pole_size - 1 do
      map[i, j] := 0;
  }
  err_count := 0;
  for k := low(ships) to high(ships) do
  begin
    if err_count >= MAX_ERR then
      break;
    for count := 1 to ships[k].Y do
      while err_count < MAX_ERR do
      begin
        Randomize;
        N := random(2);
        i := pole_size - (ships[k].X - 1) * (1 - N);
        j := pole_size - (ships[k].X - 1) * N;
        if (i < 0) or (j < 0) then
        begin
          err_count := MAX_ERR;
          break;
        end;
        i := random(i);
        j := random(j);
        z := 0;
        while (z < ships[k].X) and (map[i + z * (1 - N), j + z * N] = 0) do
          inc(z);
        if z = ships[k].X then
        begin
          for z := 0 to ships[k].X - 1 do
            map[i + z * (1 - N), j + z * N] := 2;
          volni(map);
          break;
        end
        else
          inc(err_count);
      end;
  end;
  if err_count >= MAX_ERR then
    // perezausk
    Rasstanovka(map)
  else
    // V "map" karta korabley
    
end;
Измененный проект прилагаю. И прошу Вашей помощи:
Проект
Armageddets вне форума Ответить с цитированием
Старый 09.05.2016, 23:04   #7
Armageddets
Форумчанин
 
Регистрация: 30.06.2012
Сообщений: 145
По умолчанию

Все. Проблема решена. При расстановке я закомментировал код обнуления. А мне нужно было обнулять ячейки, которые больше чем -1. Всем спасибо за советы. Тема закрыта. Еще раз спасибо всем огромное!
Armageddets вне форума Ответить с цитированием
Старый 11.05.2016, 06:46   #8
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,889
По умолчанию

Вот мой морской бой, заготовочка с как бы игрой от/на 1 игрока (так изначально задумывалось), но наиболее проработанная часть это расстановка, которая может варьировать свои параметры, написана без кучи вложенных циклов с постоянным рандомом, а с вумной алгоритмизацией на классах. Код могу дать лично, но не публично, спрашивайте кому надо (форумчане, а не новички).

В демке есть опция ViewShips для показа расстановки. Настройки расстановки позволяют менять размер поля (длина стороны квадрата и размер кораблей Н (от 1го Н-палубника до Н 1-палубников). Можно покликать по кораблям, "стреляя" в них.
Вложения
Тип файла: zip SeaFight.zip (271.5 Кб, 10 просмотров)
phomm вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Делаю игру крестики на 19х19 Nemfoman Общие вопросы Delphi 11 13.04.2012 00:29
Игра - аналог Pacman Гром Gamedev - cоздание игр: Unity, OpenGL, DirectX 32 16.03.2012 22:34
Делаю 3d игру Alex2009 Gamedev - cоздание игр: Unity, OpenGL, DirectX 135 18.09.2009 15:11
Делаю простую игру, есть вопросы Sergeu Общие вопросы Delphi 19 25.01.2009 22:46