program grzybobranie;
(* to mialo byc drzewo bst z wywazaniem -- AVL *)
(* niestety nie zawsz dziala dobrze            *)
 
unit drzewo:class;
 
   unit elem:class;
 
      unit virtual comp:function(e2:elem):integer;
      end comp;
 
   end elem;
 
   unit slowo:class(el:elem);
      var waga:integer,ls,rs:slowo;
      begin
      waga:=0;
      ls,rs:=none;
      inner;
   end slowo;
 
   var korzen:slowo;
 
   unit virtual rysuj_drzewo:procedure;
   end rysuj_drzewo;
 
   unit findc:coroutine(e:elem);
 
      var new_slowo:slowo,waga:integer;
 
      unit lrot:procedure(inout p:slowo);
         var c1,c2:integer;
         var pp,ppp:slowo;
         begin
         pp:=p;
         p:=p.ls;
         ppp:=p.rs;
         p.rs:=pp;
         pp.ls:=ppp;
         c1:=pp.waga-p.waga+1;
         if p.waga>0 then c1:=c1+p.waga; fi;
         c2:=pp.waga;
         if p.waga>0 then c2:=c2+p.waga; fi;
         if p.waga>c2 then c2:=p.waga; fi;
         pp.waga:=c2+1;
         p.waga:=c1;
         waga:=0;
      end lrot;
 
      unit rrot:procedure(inout p:slowo);
         var c1,c2:integer;
         var pp,ppp:slowo;
         begin
         pp:=p;
         p:=p.rs;
         ppp:=p.ls;
         p.ls:=pp;
         pp.rs:=ppp;
         c1:=-1+pp.waga;
         if p.waga>0 then c1:=c1-p.waga; fi;
         c2:=1-pp.waga;
         if p.waga>0 then c2:=c2+p.waga; fi;
         if c2<0 then c2:=0; fi;
         c2:=p.waga-c2-1;
         pp.waga:=c1;
         p.waga:=c2;
         waga:=0;
      end rrot;
 
 
      unit f:procedure(inout s:slowo);
         begin
         if s=none then
            detach;
            s:=new_slowo;
         else
            if e.comp(s.el)<=0 then
               call f(s.ls);
               s.waga:=s.waga-waga;
            else
               call f(s.rs);
               s.waga:=s.waga+waga;
            fi;
            if s.waga<-1 then
               if s.ls.waga>0 then call rrot(s.ls) fi;
               call lrot(s);
            fi;
            if s.waga>1 then
               if s.rs.waga<0 then call lrot(s.rs) fi;
               call rrot(s);
            fi;
         fi;
      end f;
 
      begin
      new_slowo:=none;
      waga:=0;
      return;
      call f(korzen);
   end findc;
 
 
 
   unit wstaw:procedure(e:elem);
 
      var f:findc;
 
      begin
      f:=new findc(e);
      attach(f);
      f.new_slowo:=new slowo(e);
      f.waga:=1;
      attach(f);
      kill(f);
   end wstaw;
 
 
   unit find:function(e:elem):slowo;
 
      unit f:function(s:slowo):slowo;
         begin
         if s=none then result:=none
         else
            if e.comp(s.el)=0 then result:=s
            else
               if e.comp(s.el)<0 then result:=f(s.ls)
               else result:=f(s.rs)
               fi;
            fi;
         fi;
      end f;
 
      begin
      result:=f(korzen)
   end find;
 
 
 
   unit delete:procedure(e:elem);
 
      unit find_last:function(s:slowo):slowo;
         begin
         result:=s;
         if result.rs<>none then
            while result.rs.rs<>none do result:=result.rs; od;
         fi;
      end find_last;
 
      var s,ss:slowo;
 
      begin
      s:=find(e);
      if s<>none then
         if s.ls<>none then
            ss:=find_last(s.ls);
            kill(s.el);
            if ss.rs<>none then
               s.el:=ss.rs.el;
               if ss.rs.ls<>none then
                  ss.rs.el:=ss.rs.ls.el;
                  kill(ss.rs.ls);
               else
                  kill(ss.rs);
               fi;
            else
               s.el:=ss.el;
               if ss.ls<>none then
                  ss.el:=ss.ls.el;
                  kill(ss.ls);
               else
                  kill(ss);
               fi;
            fi;
         else
            if s.rs<>none then
               kill(s.el);
               s.el:=s.rs.el;
               s.ls:=s.rs.ls;
               ss:=s.rs;
               s.rs:=s.rs.rs;
               kill(ss);
            else
               kill(s);
            fi;
         fi;
      fi;
      kill(e);
   end delete;
 
 
   unit porzadek:class;
      var e:elem,x,y,d,nawias:integer,
          czy_korzen,czy_lewy,koniec:boolean,
          w:integer;
      unit virtual next:procedure(s:slowo;i,dx,ix:integer;lewy:boolean);
      end next;
 
      begin
      y:=0;
      koniec:=false;
      return;
      do
         call next(korzen,1,16,40,false);
         koniec:=true;
         detach;
      od;
   end porzadek;
 
 
   unit lex:porzadek coroutine;
 
      unit virtual next:procedure(s:slowo;i,dx,ix:integer;lewy:boolean);
         begin
         if s<> none then
            nawias:=1;
            detach;
            call next(s.ls,i+1,dx div 2,ix-dx,true);
            e:=s.el;
            y:=i;x:=ix;
            nawias:=0;
            czy_korzen:=(s=korzen);
            czy_lewy:=lewy;
            d:=dx;
            detach;
            call next(s.rs,i+1,dx div 2,ix+dx,false);
            nawias:=2;
            detach;
         fi;
      end next;
 
   end lex;
 
   unit pre:porzadek coroutine;
 
      unit virtual next:procedure(s:slowo;i,dx,ix:integer;lewy:boolean);
         begin
         if s<> none then
            nawias:=1;
            detach;
            e:=s.el;
            y:=i;x:=ix;
            nawias:=0;
            czy_korzen:=(s=korzen);
            czy_lewy:=lewy;
            d:=dx;
            w:=s.waga;
            detach;
            call next(s.ls,i+1,dx div 2,ix-dx,true);
            call next(s.rs,i+1,dx div 2,ix+dx,false);
            nawias:=2;
            detach;
         fi;
      end next;
 
   end pre;
 
   unit post:porzadek coroutine;
 
      unit virtual next:procedure(s:slowo;i,dx,ix:integer;lewy:boolean);
         begin
         if s<> none then
            nawias:=1;
            detach;
            call next(s.ls,i+1,dx div 2,ix-dx,true);
            call next(s.rs,i+1,dx div 2,ix+dx,false);
            e:=s.el;
            y:=i;x:=ix;
            nawias:=0;
            czy_korzen:=(s=korzen);
            czy_lewy:=lewy;
            d:=dx;
            detach;
            nawias:=2;
            detach;
         fi;
      end next;
 
   end post;
 
end drzewo;
 
unit  SetCursor : procedure(row, column : integer);
   var c,d,e,f  : char,
       i,j : integer;
   begin
   i := row div 10;
   j := row mod 10;
   c := chr(48+i);
   d := chr(48+j);
   i := column div 10;
   j := column mod 10;
   e := chr(48+i);
   f := chr(48+j);
   write( chr(27), "[", c, d, ";", e, f, "H")
end SetCursor;
 
 
unit drzewo_liczb:drzewo class;
 
   unit liczba:elem class(i:integer);
 
      unit virtual comp:function(e2:liczba):integer;
         begin
         if  i < e2.i  then result:=-1
         else if  i > e2.i  then result:=1
            else result:=0
            fi;
         fi;
      end comp;
 
   end liczba;
 
   unit wstaw_liczbe:procedure(i:integer);
      begin
      call wstaw(new liczba(i));
   end wstaw_liczbe;
 
   unit del_liczba:procedure(i:integer);
      begin
      call delete(new liczba(i));
   end del_liczba;
 
   unit virtual rysuj_drzewo:procedure;
      var l:pre,i:integer;
      begin
      write(chr(27),"[2J");
      l:=new pre;
      attach(l);
      while( ( l.nawias<>0 ) and ( not l.koniec ) )do attach(l); od;
      while not l.koniec do
         call SetCursor(4*l.y,l.x);
         write(l.e qua liczba.i:3);
         call SetCursor(4*l.y-1,l.x-1);
         if l.czy_korzen then write("ÚÄÄÄ¿ "); else write("ÚÄÁÄ¿ "); fi;
         call SetCursor(4*l.y+1,l.x-1);
         write("ÀÄÄÄÙ ");
         call SetCursor(4*l.y,l.x-1);
         write("³");
         call SetCursor(4*l.y,l.x+3);
         write("³");
         if not l.czy_korzen then
            if l.czy_lewy then
               call SetCursor(4*l.y-2,l.x+1);
               write("Ú");
               for i:=1 to 2*l.d-2 do write("Ä"); od;
               write("Ù");
               call SetCursor(4*l.y-3,l.x+2*l.d);
               write("Â");
            else
               call SetCursor(4*l.y-2,l.x+1);
               write("¿");
               call SetCursor(4*l.y-3,l.x-2*l.d+2);
               write("Â");
               call SetCursor(4*l.y-2,l.x-2*l.d+2);
               write("À");
               for i:=1 to 2*l.d-2 do write("Ä"); od;
            fi;
         fi;
         attach(l);
         while( ( l.nawias<>0 ) and ( not l.koniec ) )do attach(l); od;
      od;
      kill(l);
   end rysuj_drzewo;
 
   unit rysuj_porz:procedure(i:integer);
      var l:porzadek;
      begin
      write(chr(27),"[2J");
      case i
         when 2:l:=new lex;
         when 3:l:=new pre;
         when 4:l:=new post;
      esac;
      attach(l);
      while not l.koniec do
         case l.nawias
            when 0:write(l.e qua liczba.i);
            when 1:write("(");
            when 2:write(")");
         esac;
         attach(l);
      od;
      kill(l);
   end rysuj_porz;
 
end drzewo_liczb;
 
var d:drzewo_liczb;
var i:integer;
var screen:integer;
 
begin
screen:=1;
d:=new drzewo_liczb;
while screen<>0 do
   write(chr(27),"[2J");
   writeln("aby wstawic wpisz liczbe, aby skasowac minus liczbe, zero konczy!");
   writeln;
   writeln("0-KONIEC");
   writeln("1-postac drzewa");
   writeln("2-porzadek infiksowy");
   writeln("3-porzadek prosty");
   writeln("4-porzadek odwrotny");
   call SetCursor(23,1);
   write(">");
   read(screen);
   write(chr(27),"[2J");
   if screen<0 or screen>4 then screen:=0; fi;
   i:=1;
   while screen*i<>0 do
      if screen=1 then call d.rysuj_drzewo;
                  else call d.rysuj_porz(screen);
      fi;
      call SetCursor(23,1);
      write(">");
      read(i);
      if i<>0 then
         if i>0 then call d.wstaw_liczbe(i);
         else call d.del_liczba(-i);
         fi;
      fi;
   od;
od;
end.
 
