Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Oracle > Шахматы в PL\SQL


Автор: Golar 16.5.2006, 16:05
Добрый день, мне нужен совет по процедурам в  PL\SQL. Можно ли писать commit и roolback внутри процедур и функций? Мне необходимо проверить можно ли сделать ход из одной клетки (x1,y1) в другую (x2,y2) на шахматной доске. Я примерно набросала функцию, пожалуйста посмотрите.
У меня есть таблица Chess, хранящая ситуацию на досках:
Код
/* col = 1 - white; 0 - ничего, -1 - черная */
Create table Chess
( Doska integer,
  St integer CHECK ((st>=1) and (st<=8)),  
  Str integer CHECK ((str>=1) and (str<=8)),
  Fig varchar2(1),
  Col integer
);

Процедура проверки (здесь rek=true, если вошли по рекурсии):
Код
CREATE OR REPLACE FUNCTION Mozhno(d in integer,x1 in integer,y1 in integer,x2 in integer,y2 in integer,rek in boolean) RETURN boolean
IS

Cursor SearchF( d,x,y integer) IS /*по коорд ищет фигуру и цвет*/
 Select fig, col
 From Chess
 where (Doska = d) and (st = x) and (str = y);

Cursor SearchK( d integer, f varcar2(1), c integer) IS /*по фигуре и цвету ищет коорд*/
 Select st, str
 From Chess
 where (Doska = d) and (fig = f) and (col = c);

Cursor Search(d integer,c integer) IS /* ищет все занятые координаты опр цветом*/ 
 Select st,str
 From Chess
 where (Doska = d) and (col=c);

 x,y integer;
 fig1,fig2 varchar2(1);
 col1,col2 integer;
 boy,vs boolean;
BEGIN
/*ищем клетку с кот надо делать ход*/
open SearchF (d, x1,y1);
fetch SearchF into fig1,col1;
vs:= (col1 = 0)
close SEarchF;
if vs then 
        if not rek DBMS_OUTPUT.put_line('Nechem xodit');
        end if;
        return false;        
else
/*смотрим клетку, куда идем*/
   open SearchF(d, x2,y2);
   fetch SearchF into fig2,col2;
   vs:=not(col2 = 0);
   close SEarchF;
end if;
   if (vs and (col1=col2)) 
        if not rek DBMS_OUTPUT.put_line('Nelzya,tam nawa figura');
        end if;
        return false;
   else
   if vs and (col1<>col2)
              boy:=true;
   else boy:=false;
   end if;
      case fig1 
      when 'p','P' then begin
                 res:=( ((x1=x2)and((y2=y1+col1)or(y2=y1+2*col1)and((y1=1+col1)or(y1=8+col1))))
                 or(boy and ((x1=x2+1)or(x1=x2-1))and(y2=y1+clo1)));
                 if not rek
                     if res DBMS_OUTPUT.put_line('Mozhno xodit');
                     else DBMS_OUTPUT.put_line('Nelzya xodit');
                     end if;
                 end if;
                 return res;
                end;
     when  'l','L' then begin
                 if (y1=y2)
                   if (x2-x1)<0
                           l:=-1;
                   else  l:=1;
                   end if;
                   k=0; 
                else
                if (x1=x2)
                    if  (y2-y1)<0
                           k:=-1;
                    else   k:=1;
                    end if;
                    l=0; 
                else
                 if not rek DBMS_OUTPUT.put_line('Nelzya xodit');
                 end if;
                 return false; /*расположена не по направлению*/ 
                end if;
               end if;
               vs:= true;/*нет др. фигуры на пути*/
               x:=x1;
               y:=y1;
              while vs and not((y<>y2)and(x<>x2))
                 loop
                  x:=x+l;
                  y:= y+k;
                  open SearchF(d,x,y);
                  fetch Search in fig2,col2;
                  close Search;
                  vs:= col2=0;
                 end loop;
              if (y = y2)and(x = x2)
                  if not rek DBMS_OUTPUT.put_line('Mozhno xodit');
                  end if;
                  return true;
              else 
                  if not rek DBMS_OUTPUT.put_line('Nelzya xodit');
                  end if;
                  return false;
              end if;
            end;

   when 'h','H'  then  begin
             res:=((x1=x2-1)and((y1=y2-2)or(y1=y2+2)))or
                  ((x1=x2+1)and((y1=y2-2)or(y1=y2+2)))or
                  ((x1=x2-2)and((y1=y2-1)or(y1=y2+1)))or 
                  ((x1=x2+2)and((y1=y2-1)or(y1=y2+1)));
             if not rek
                     if res DBMS_OUTPUT.put_line('Mozhno xodit');
                     else DBMS_OUTPUT.put_line('Nelzya xodit');
                     end if;
                 end if;     
             return res;                     
           end;

   when 's','S' then 
           begin
            k:=0;l:=0;
            if (x2-x1>0)and(y2-y1>0)   
                   k:=1;l:=1;end if;
            if (x2-x1>0)and(y2-y1<0)   
                   k:=-1;l:=1;end if;
            if (x2-x1<0)and(y2-y1>0)   
                   k:=1;l:=-1;end if;
            if (x2-x1<0)and(y2-y1<0)   
                   k:=-1;l:=-1;end if;
            if (k=0)and(l=0)
                   if not rek DBMS_OUTPUT.put_line('Nelzya xodit');
                   end if;
                   return false;/*расположена не по направлению*/
            end if;
            vs:= true;/*нет др. фигуры на пути*/
            x:=x1;
            y:=y1;
            while vs and not((y<>y2)and(x<>x2))
                 loop
                  x:=x+l;
                  y:= y+k;
                  open SearchF(d,x,y);
                  fetch Search in fig2,col2;
                    close Search;
                  vs:= col2=0;
                 end loop;
            if (y = y2)and(x = x2)
                if not rek DBMS_OUTPUT.put_line('Mozhno xodit');
                  end if;
                return true;
            else 
                if not rek DBMS_OUTPUT.put_line('Nelzya xodit');
                  end if;
                return false;
            end if;
           end;

    when  'k','K' then
            begin
            res:= ((x1=x2)and((y2=y1+1)or(y2=y1-1)))or
                  ((y1=y2)and((x2=x1+1)or(x2=x1-1)))or
                  ((x2=x1+1)and((y2=y1+1)or(y2=y1-1)))or
                  ((x2=x1-1)and((y2=y1+1)or(y2=y1-1)));
             if not rek
                     if res DBMS_OUTPUT.put_line('Mozhno xodit');
                     else DBMS_OUTPUT.put_line('Nelzya xodit');
                     end if;
                 end if;           
            return res;
           end;
     when  'f','F'  then
            begin
            k:=0;l:=0;
            if (x2-x1>0)and(y2-y1>0)   
                   k:=1;l:=1;end if;
            if (x2-x1>0)and(y2-y1<0)   
                   k:=-1;l:=1;end if;
            if (x2-x1<0)and(y2-y1>0)   
                   k:=1;l:=-1;end if;
            if (x2-x1<0)and(y2-y1<0)   
                   k:=-1;l:=-1;end if;
            if (str1=str2)
                if (x2-x1)<0
                           l:=-1;
                else
                  l:=1;
                end if;
               k=0; 
            else
            if (x1=x2)
                if  (y2-y1)<0
                           k:=-1;
                else
                    k:=1;
                end if;
                 l=0; 
             end if;
            end if;
            if (k=0)and(l=0)
                  if not rek DBMS_OUTPUT.put_line('Nelzya xodit');
                  end if;
               return false; /*расположена не по направлению*/ 
            end if;
             x:=x1;
             y:=y1;
             vs:= true;/*нет др. фигуры на пути*/
            while vs and not((x<>x2)and(y<>y2))
                 loop
                  x:=x+l;
                  y:= y+k;
                  open SearchF(d,x,y);
                  fetch Search in fig2,col2;
                    close Search;
                  vs:= col2=0;
                 end loop;
            if (x = x2)and(y = y2)
                if not rek DBMS_OUTPUT.put_line('Mozhno xodit');
                  end if;
                return true;
            else 
                if not rek DBMS_OUTPUT.put_line('Nelzya xodit');
                  end if;
                return false;
            end if;
           end;

           end;
       end//case
      
  end if;
end if;

if (not rek) then //т.е еще можно ходить и не рекурсия, тогда ходим
    Update Chess /*ушли с клетки*/
    set fig= ' ',col = 0
    where (doska = d)and(st = x1)and(str = y1);
              
    Update Chess /*пришли в клетку*/
    set fig= fig1,col = col1
    where (doska = d)and(st = x2)and(str = y2);

    /*теперь смотрим, есть ли шах нашему королю*/
    if col1 = 1 
       open SearchK(d,'k',col1);
    else open SearchK(d,'K',col1);
    end if;   
    fetch SearchK in x,y;
    close SearchK;

    open Search(d,col1*(-1));/*нашли все ф-ры др цвета*/
    fetch Search in x1,y1;
    vs:= true;
    while (Search%found) and vs /*пока есть ф-ра и не нашли шах*/
     loop
        /*можно ли ходить ф-рой др цвета на нашего короля*/
        vs=  Mozhno(d,x1,y1,x,y, true); 
        fetch Search in x1,y1;
     end loop;
    
    if vs then /*если вышли из цикла, потому что нашли ф-ру, дающую шах*/
           return false;
    else 
      return true;
    end if;
   Rollback;
end if;
end Mozhno;
    

Автор: batigoal 16.5.2006, 16:21
Цитата(Golar @  16.5.2006,  17:05 Найти цитируемый пост)
Можно ли писать commit и roolback внутри процедур и функций?

Можно. Но вот оправданно ли это в данной ситуации, судить не берусь (про себя думаю, что нет: всё-таки откат транзакции - это не инструмент программной логики). 

Автор: Golar 16.5.2006, 16:29
А как Вы посоветуете здесь "откатиться"? Просто, заранее оправдаюсь, с  PL\SQL  имею дело не больше недели и поэтому есть большие пробелы в умении им пользоваться. Не посоветуете, может в корне по-другому сделать?  smile  

Автор: Sqlninja 16.5.2006, 16:35
Совершенно верно - COMMIT и ROLLBACK - это просто операторы управления транзакциями. Использовать их для описания логики - плохая практика. Опишите все ситуации явно, через CASE или IF THEN. В крайнем случае через исключения. И еще смените стиль. Ваш код ужжжасен.  smile  

Автор: Golar 16.5.2006, 16:40
я не спорю, был бы прекрасен - за помощью бы не обращалась! smile как его сменить - поконкретней! 

Автор: Sqlninja 16.5.2006, 16:41
Просто сделайте так, чтобы откатываться не пришлось. ROLLBACK - это звучит гордо, но не используйте его не в исключительных ситуациях.

Кроме того, оставьте в покое базу! Создайте структуры типа RECORD и меняйте их динамически, если уж хотите написать шахматы на PL\SQL. Он вообще мало для этого подходит.  smile  

Автор: Golar 16.5.2006, 16:48
Конечно! Знаете, я поняла уже, что Pl\SQL для этого мало подходит!!! Но задание сделать это все  на нем, родимом!   smile  хотя, прикольно! smile  А как без отката проверить нет ли угрозы королю?  

Автор: Sqlninja 16.5.2006, 16:55
Ладно, вот вам советы:

1)  Давайте всем переменным осмысленные имена. Ничего, если они будут немного длиннее.
2)  Не используйте таблицы, это нерационально в Вашем случае.
3)  Используйте записи и коллекции.
4)  Разбейте Ваш код на маленькие процедуры и функции.
5)  Остальные советы сводятся к общим best practices по программированию.
 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)