IPB
ЛогинПароль:

> Прочтите прежде чем задавать вопрос!

1. Заголовок темы должен быть информативным. В противном случае тема удаляется ...
2. Все тексты программ должны помещаться в теги [code=pas] ... [/code].
3. Прежде чем задавать вопрос, см. "FAQ", если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Паскаля (исключение - только с согласия модератора).
5. НЕ используйте форум для личного общения, все что не относится к обсуждению темы - на PM!
6. Одна тема - один вопрос (задача)
7. Проверяйте программы перед тем, как разместить их на форуме!!!
8. Спрашивайте и отвечайте четко и по существу!!!

 
 Ответить  Открыть новую тему 
> Пройти лабиринт по правилу правой руки.
DarkWishmaster
сообщение 27.03.2011 18:43
Сообщение #1


Бывалый
***

Группа: Пользователи
Сообщений: 168
Пол: Мужской

Репутация: -  3  +


Есть лабиринт, надо его пройти по правилу правой руки.
вот к примеру
7 9
1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 0 1
1 0 1 0 0 1 0 1 1
1 0 0 0 1 0 0 0 1
1 0 1 0 1 0 1 0 1
1 0 0 0 0 0 1 0 1
1 2 1 1 1 1 1 3 1

1- блок
0 - пусто
2- вход
3- выход
Я знаю как должен вести себя робот, но проблема в том что не могу написать его поведение на Паскале, может вы поможете?
Тут надо помнить в какую сторону смотри робот что-бы можно было знать относительно него какая сторона есть - право а какая -лево
для этого я исп. процедуры:
например если робот смотрит вверх то он идет по x=-1, y=0

procedure RotD; //поворачивает направо
begin
if (x=0) and (y=1) then begin x:=1; y:=0; exit; end;
if (x=0) and (y=-1) then begin x:=-1; y:=0; exit; end;
if (x=-1) and (y=0) then begin x:=0; y:=1; exit; end;
if (x=1) and (y=0) then begin x:=0; y:=-1; exit; end;
end;
procedure RotS; // поворачивает налево
begin
if (x=0) and (y=1) then begin x:=-1; y:=0; exit; end;
if (x=0) and (y=-1) then begin x:=1; y:=0; exit; end;
if (x=-1) and (y=0) then begin x:=0; y:=-1; exit; end;
if (x=1) and (y=0) then begin x:=0; y:=1; exit; end;
end;


procedure Move;
begin
i:=i+x;
j:=j+y;
end;



Но тут проблема в том что например робот идёт направо, там тупик и направо тоже тупик он поворачивает налево и он должен придерживаться уже левой стены, это самое главное реализовать.

Ну потом что-бы показать результат для самого короткого пути то все клетки увелечиваем на еденицу если робот по ней прошел, и дальше проходим по меньшим единицам пока доходим до цели.

Сообщение отредактировано: DarkWishmaster - 27.03.2011 19:13
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Freedom
сообщение 27.03.2011 18:57
Сообщение #2


Пионер
**

Группа: Пользователи
Сообщений: 113
Пол: Мужской
Реальное имя: Надир

Репутация: -  6  +


Цитата(DarkWishmaster @ 27.03.2011 18:43) *


Но тут проблема в том что например робот идёт направо, там тупик, он поворачивает налево и он должен придерживаться уже левой стены, это самое главное реализовать.


а что если тупик, то повернуться не один раз налево а два раза?


--------------------
From ZERO to HERO
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
DarkWishmaster
сообщение 27.03.2011 19:12
Сообщение #3


Бывалый
***

Группа: Пользователи
Сообщений: 168
Пол: Мужской

Репутация: -  3  +


Цитата(Freedom @ 27.03.2011 18:57) *

а что если тупик, то повернуться не один раз налево а два раза?

Я имел ввиду что если тупик впереди и нельзя повернуть направо то надо налево, извините, исправил.
А если нигде повернуть нельзя то поворачиваем на 180 и придерживаемся правой стены.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
DarkWishmaster
сообщение 28.03.2011 21:07
Сообщение #4


Бывалый
***

Группа: Пользователи
Сообщений: 168
Пол: Мужской

Репутация: -  3  +


Вообщем вот что получилось:

Program Robot; Uses Crt;
var a:array[1..100,1..100] of integer;
i,j,n,m,x,y,flag:integer; F:text; Q:boolean;
procedure Enter;
begin
for i:=1 to n do
for j:=1 to m do
if a[i,j]=2 then exit;
end; {Enter}
procedure Initiare;
begin
assign(F, 'C:\In.TXT'); reset(F);
read(F, n); readln(F, m);
for i:=1 to n do begin
for j:=1 to m do begin
read(F,a[i,j]);
end;
readln(F);
end;
close(F);
end; {Initiare}
procedure Print;
var i,j:byte;
begin
for i:=1 to n do begin
for j:=1 to m do begin
write(a[i,j]); end;
writeln;
end; {Print} end;
function Block(i,j:integer):boolean; // смотрим если можно идти вперёд
begin
if (a[i,j]=1) or (i>n) or (j>m) then Block:=True
else Block:=False;
end; (*BlocK*)
procedure RotD; // поворот направо
begin
if (x=0) and (y=1) then begin x:=1; y:=0; exit; end;
if (x=0) and (y=-1) then begin x:=-1; y:=0; exit; end;
if (x=-1) and (y=0) then begin x:=0; y:=1; exit; end;
if (x=1) and (y=0) then begin x:=0; y:=-1; exit; end;
end;
procedure RotS; // поворот налево
begin
if (x=0) and (y=1) then begin x:=-1; y:=0; exit; end;
if (x=0) and (y=-1) then begin x:=1; y:=0; exit; end;
if (x=-1) and (y=0) then begin x:=0; y:=-1; exit; end;
if (x=1) and (y=0) then begin x:=0; y:=1; exit; end;
end;
procedure Move(var i,j:integer); // шаг вперед
begin
i:=i+x;
j:=j+y;
end; {move}
function Exit(i,j:integer):boolean; // проверка на выход
begin
if a[i+x,j+y]=3 then Exit:=True else Exit:=False;
end;
Begin ClrScr;
Initiare;
Enter;
x:=-1; y:=0;
flag:=1;
repeat
if Block(i+x,j+y)=True then //если впереди блок тогда
begin
RotD; // поворачиваем направо
if Block(i+x,j+y) // если и на право блок то
then while Block(i+x,j+y)=True do // поворачиваем налево до тех пор пока найдем свободное пространство
RotS
else Move(i,j); // если после поворота направо нету блока то шаг вперед
end else Move(i,j); //если впереди нету блока то шаг вперед
until Exit(i,j)=True; // выполнять пока не найдем выход
readln;
end.



Для примера массива что я написал выше, он идёт наверх, поворачивает, видет что там тупик, и идёт в обратном направлении пока дойдёт до входа, и опять всё заново sad.gif((

З.Ы , как тут спойлер написать? что-бы можно было свернуть весь код.

Там откуда я взял задачу, она по техники Greedy, и есть Подсказка: Выбирать из Множество [Вниз, Вверх, Направо, Налево] так что-бы робот двигался вдоль одной стены.

Сообщение отредактировано: DarkWishmaster - 28.03.2011 21:12
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 29.03.2011 9:20
Сообщение #5


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Ну и жесть вы понаписали.
Я так и не понял, а где вы храните, в какую сторону смотрит робот?


const
dx : array [0 .. 3] of integer = (1, 0, -1, 0);
dy : array [0 .. 3] of integer = (0, 1, 0, -1);

var
robot: record
x, y, direction: integer;// текущее направление тоже надо помнить
end;

begin
...
for d := robot.direction - 1 to robot.direction + 2 do begin // перебор по направлениям, начиная с того, что направо от текущего
robot.direction := (d + 4) mod 4; // просто переводим счётчик цикла к интервалу 0..3
if free[x+dx[robot.direction], y+dy[robot.direction]] then break; // если туда можно пойти, значит мы нашли нужное направление, выходим из цикла
end;
end.



> if Block(i+x,j+y)=True then

Да чего уж там, давай сразу
if true=(true=((Block((i+x+0)*1, (j+y+1-1)*1)=true)=true))

Не надо писать =true, ясно? Это тавтология потому что.

Сообщение отредактировано: TarasBer - 29.03.2011 9:23


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
DarkWishmaster
сообщение 29.03.2011 13:38
Сообщение #6


Бывалый
***

Группа: Пользователи
Сообщений: 168
Пол: Мужской

Репутация: -  3  +


Цитата(TarasBer @ 29.03.2011 9:20) *

Ну и жесть вы понаписали.
Я так и не понял, а где вы храните, в какую сторону смотрит робот?


const
dx : array [0 .. 3] of integer = (1, 0, -1, 0);
dy : array [0 .. 3] of integer = (0, 1, 0, -1);

var
robot: record
x, y, direction: integer;// текущее направление тоже надо помнить
end;

begin
...
for d := robot.direction - 1 to robot.direction + 2 do begin // перебор по направлениям, начиная с того, что направо от текущего
robot.direction := (d + 4) mod 4; // просто переводим счётчик цикла к интервалу 0..3
if free[x+dx[robot.direction], y+dy[robot.direction]] then break; // если туда можно пойти, значит мы нашли нужное направление, выходим из цикла
end;
end.



> if Block(i+x,j+y)=True then

Да чего уж там, давай сразу
if true=(true=((Block((i+x+0)*1, (j+y+1-1)*1)=true)=true))

Не надо писать =true, ясно? Это тавтология потому что.


У меня там переменые x и y меняются в зависимости от того куда смотрит робот
например
если x=-1 y=0 тогда когда мы вызываем процедуру Move(i,j); то он идёт наверх на 1 единицу (i-1, j+0)
т.е он смотри на север.

З.Ы если мы делаем так: IF Ok then то оператор сразу понимает что Ok(boolean) должен быть True?
а для False как? If not ok then ?

Сообщение отредактировано: DarkWishmaster - 29.03.2011 13:41
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 29.03.2011 13:46
Сообщение #7


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> У меня там переменые x и y меняются в зависимости от того куда смотрит робот

Я понял. У тебя x, y - это вектор сдвига, а i, j - координаты.
Плохие названия, неговорящие.

Обычно x, y - координаты, а dx, dy - вектор сдвига.
Но в данном случае как раз проще хранить в качестве направления именно число от 0 до 3.

> З.Ы если мы делаем так: IF Ok then то оператор сразу понимает что Ok(boolean) должен быть True?
а для False как? If not ok then ?

Ну да.
Это должно быть очевидно, если понимать, что заголовок оператора if - это любое выражение типа boolean. Это может быть как переменная этого типа ( if b then ... ), так и оператор, возвращающий значение этого типа ( if x>y then ... ).

Добавлено через 1 мин.
> if (a[i,j]=1) or (i>n) or (j>m) then Block:=True
else Block:=False;

Тоже типичный бульщит (bool shit)

А сразу почему не написать

Block := (a[i,j]=1) or (i>n) or (j>m);


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
DarkWishmaster
сообщение 29.03.2011 13:54
Сообщение #8


Бывалый
***

Группа: Пользователи
Сообщений: 168
Пол: Мужской

Репутация: -  3  +


Tarasber, спасибо, исправлюсь, пока в привычку не вошло.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
DarkWishmaster
сообщение 30.03.2011 18:17
Сообщение #9


Бывалый
***

Группа: Пользователи
Сообщений: 168
Пол: Мужской

Репутация: -  3  +



Program Robot_Greedy; Uses Crt;
const
dx : array [0 .. 3] of integer = (1, 0, -1, 0);
dy : array [0 .. 3] of integer = (0, 1, 0, -1);
type matrice=array[1..100,1..100] of integer;
var
a,b:matrice;
i,j,n,m,x,y,d,flag:integer; F:text;
Robot: record
x, y, direction: integer;
end;
procedure Enter; {Find Entrance}
begin
for i:=1 to n do
for j:=1 to m do
if a[i,j]=2 then exit;
end; {Enter}
procedure Initiare;
begin
assign(F, 'C:\In.TXT'); reset(F);
read(F, n); readln(F, m);
for i:=1 to n do begin
for j:=1 to m do begin
read(F,a[i,j]);
end;
readln(F);
end;
close(F);
for i:=1 to n do
for j:=1 to n do
if a[i,j]=0 then b[i,j]:=0 else b[i,j]:=-1; end; {Initiare}
procedure Print(var a:matrice);
var i,j:byte;
begin
for i:=1 to n do begin
for j:=1 to m do begin
write(a[i,j],' '); end;
writeln;
end; {Print} end;
function Free(i,j:integer):boolean;
begin
Free:=(a[i,j]=0) and (i<n) and (j<m);
end; {Free}
procedure GO;
begin
i:=i+dx[robot.direction];
j:=j+dy[robot.direction];
b[i,j]:=b[i,j]+1;
end;
procedure Back;
begin
i:=i-dx[robot.direction];
j:=j-dy[robot.direction];
b[i,j]:=b[i,j]+1;
end;
procedure Right90;
begin
if robot.direction=3 then robot.direction:=-1;
robot.direction:=robot.direction+1;
end;
procedure Left90;
begin
if robot.direction=0 then robot.direction:=4;
robot.direction:=robot.direction-1;
end;
Begin ClrScr; {Main Program}
Initiare;
Print(a);
readln;
Enter;
x:=i; y:=j;
robot.direction:=2;
while Free(i,j) do
Go;
while flag=0 do begin
Right90;
Go;
if a[i,j]=3 then flag:=1 else
if not(Free(i,j))then begin
Back;
Left90;
Go;
if not(free(i,j))then begin
Back;
Left90;
end
end
end;

Print(b);
readln;
end.


//File In.TXT
7 9
1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 0 1
1 0 1 0 0 1 0 1 1
1 0 0 0 1 0 0 0 1
1 0 1 0 1 0 1 0 1
1 0 0 0 0 0 1 0 1
1 2 1 1 1 1 1 3 1
// Matrix B
-1 1 0 -1 1 0 0 1 0
0 5 6 4 4 2 3 6 2
0 4 4 4 1 -1 2 4 0
0 3 2 1 -1 0 1 4 2
0 2 -1 0 -1 0 -1 2 1
0 2 0 0 0 0 -1 3 1
0 0 -1 -1 -1 -1 -1 2 0





Вот что получилось, робот находит выход, только он идёт по очень длиному пути.
Пробовал использовать матрицу B для генерации ответа ( надо пройти по минимальным числам ), но это не получилось...

Сообщение отредактировано: DarkWishmaster - 30.03.2011 18:22
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
-TarasBer-
сообщение 30.03.2011 18:42
Сообщение #10


Гость






Так если ты хочешь кратчайший путь, то это тебе не правая рука нужна, а "обход в ширину" (в википедии поищи).
 К началу страницы 
+ Ответить 
-TarasBer-
сообщение 30.03.2011 18:44
Сообщение #11


Гость






> i:=i+dx[robot.direction];
j:=j+dy[robot.direction];


Вот нахрена я заводил поля robot.x и robot.y , если ты всё равно координаты хранишь в i, j?
 К началу страницы 
+ Ответить 
DarkWishmaster
сообщение 30.03.2011 18:53
Сообщение #12


Бывалый
***

Группа: Пользователи
Сообщений: 168
Пол: Мужской

Репутация: -  3  +


Цитата(-TarasBer- @ 30.03.2011 18:44) *

> i:=i+dx[robot.direction];
j:=j+dy[robot.direction];
Вот нахрена я заводил поля robot.x и robot.y , если ты всё равно координаты хранишь в i, j?


Мне просто так удобнее, не путаюсь )
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
-TarasBer-
сообщение 30.03.2011 18:56
Сообщение #13


Гость






Через год ты проклянёшь себя при попытке понять, почему i,j - это координаты робота и для чего заведены поля x и y.
 К началу страницы 
+ Ответить 
Lapp
сообщение 1.04.2011 8:06
Сообщение #14


Уникум
*******

Группа: Модераторы
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


Нн-дя...
DarkWishmaster, ты извини, но ТАК программировать НЕЛЬЗЯ..
Я впервые вижу такое.. Возвращаемый результат процедуры - параметры цикла!! Где ты это почерпнул?? Я имею в виду сейчас, как ты находишь вход (процедура Enter). Давай разберем. По возрастанию важности ошибок:
1. Зачем делать процедурой кусок кода, который будет использован один раз?
2. Зачем проходить по масиву повторно? Ты мог сделать это при вводе.
3. Нельзя использовать значения параметров цикла вне цикла. Их значения не гарантируются.
4. Параметры цикла должны быть ЛОКАЛЬНЫМИ, то есть описаны внутри процедуры. Только ТР может пропустить такое, всякий нормальный современный компилятор выдаст ошибку.
5. При выполнении п.4 значения i и j будут недоступны в вызывающем модуле.
Я даже и не знаю, что тут еще добавить и какие рекомедации дать. Постарайся сделать выводы сам.
Так, пойду смотреть дальше..

Слушай, DarkWishmaster, ну я же просил тебя уже, кажется: пожалуйста, форматируй код! Ну это же не стихи, где ты можешь писать лесенкой, как тебе вздумается, под Маяковского. Процедура Print - энды пляшут танец с саблями что ли?

Ладно, с меня пока хватит. Я совершенно не понимаю, как можно ТАК УСЛОЖНИТЬ простейшую задачу. Вот тебе код - надеюсь, ты его разберешь. Заметь, что собственно решение занимает в нем 8 строк (в конце).
type
tDir= array [0..3] of integer;

const
u: tDir = (-1,0,1,0);
v: tDir = (0,1,0,-1);

var
maze: array of array of byte;
d,d0,i,j,m,n,x,y,fx,fy: integer;
s: string;
f: text;

begin
// reading the file
Assign(f,'maze.dat');
Reset(f);
n:=0;
while not EoF(f) do begin
ReadLn(f,s);
Inc(n)
end;
m:= Length(s);
SetLength(maze,n+2,m+2);
for i:=0 to n+1 do for j:=0 to m+1 do maze[i,j]:=1;
Reset(f);
for i:=1 to n do begin
ReadLn(f,s);
for j:=1 to m do begin
case s[j] of
'2': begin
x:= i;
y:= j;
end;
'3': begin
fx:= i;
fy:= j;
end
end;
if s[j]<>'1' then maze[i,j]:= 0
end
end;
Close(f);

// printing a picture
for i:=0 to n+1 do begin
for j:=0 to m+1 do Write(maze[i,j]);
WriteLn
end;

// passing the maze
d:= 0;
repeat
d:=(d+1) mod 4;
while maze[x+u[d],y+v[d]]<>0 do d:= (d+3) mod 4;
Inc(x,u[d]);
Inc(y,v[d]);
WriteLn(x:4,y:4)
until (x=fx) and (y=fy);
end.

Пример входного файла:
   1111111
1 11
1 1 11
1 11 1 1
1 1 1
1111111 1
1 1 3
1121111

Размеры прямоугольника - любые. Пробелы (или нули) обязательны (даже в конце строк). В конце файла не должно быть пустых строк!!


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 1.04.2011 8:50
Сообщение #15


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> 1. Зачем делать процедурой кусок кода, который будет использован один раз?

Ну это-то как раз правильно.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Lapp
сообщение 1.04.2011 10:17
Сообщение #16


Уникум
*******

Группа: Модераторы
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


Цитата(TarasBer @ 1.04.2011 9:50) *
> 1. Зачем делать процедурой кусок кода, который будет использован один раз?

Ну это-то как раз правильно.
Ситуации, когда это оправдано, безусловно, бывают, и нередко. Но всегда полезно спросить (себя) - зачем? Так вот, в данном случае я не нахожу ответа на этот вопрос no1.gif. Достаточно было выделить этот кусок комментариями. Это не ошибка в прямом смысле слова. Тут это сыграло даже положительную роль. Как всегда, диалектика: не сделал бы он этого, никто бы сказал ему про остальные ошибки, и они бы остались надолго.. А сейчас, надеюсь, выводы будут сделаны smile.gif.


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
DarkWishmaster
сообщение 1.04.2011 14:47
Сообщение #17


Бывалый
***

Группа: Пользователи
Сообщений: 168
Пол: Мужской

Репутация: -  3  +


Спасибо, Lapp и TarasBer, буду исправляться по тихоньку.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



- Текстовая версия 19.04.2024 2:07
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"