Program Biblioteka problem z datą - wypożyczenie książki, zwrot książki

0

Witam
Piszę w Lazarusie i mam problem z przeistoczeniem daty wypożyczenia książki w programie Biblioteka tak, żeby data podawana przez człowieka była akceptowalna przez program.
oto kod programu:

//PROGRAM GŁÓWNY:
program biblioteka;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, ProcUnit
  { you can add units after this };

var
  opcja1, opcja2: integer;
  wybor1, wybor2: boolean;

begin
  // menu programu
  repeat
    writeln(PL('Wybierz opcję:'));
    writeln(PL('  1: wypisanie książek z bazy'));
    writeln(PL('  2: dopisanie nowej książki'));
    writeln(PL('  3: usuinięcie książki'));
    writeln(PL('  4: zmiana danych książki'));
    writeln(PL('  5: wypożyczenie ksiazki'));
    writeln(PL('  6: zwrot książki'));
    writeln(PL('  9: zarządzanie osobami'));
    writeln(PL('  0: wyjście z programu'));
    wybor1:=False;
    repeat
      try
        write(PL('Twoj wybór: '));
        readln(opcja1);
        wybor1:=True;
      except
        writeln(PL('**niepoprawny parametr!'));
      end;
    until wybor1=True;
    case opcja1 of
      1: begin
           writeln('WypiszKsiazki');
           WypiszKsiazki();
         end;
      2: begin
           writeln('DodajKsiazke');
           DodajKsiazke();
         end;
      3: begin
           writeln('UsunKsiazke');
           UsunKsiazke();
         end;
      4: begin
           writeln('ZmienKsiazke');
           ZmienKsiazke();
         end;
      5: begin
           writeln('WypozyczKsiazke');
           WypozyczKsiazke(True);
         end;
      6: begin
           writeln('ZwrotKsiazki');
           WypozyczKsiazke(False);
         end;
      9: begin
           // menu programu
           repeat
             writeln(PL(' Wybierz opcję:'));
             writeln(PL('   1: wypisanie osób z bazy'));
             writeln(PL('   2: dopisanie nowej osoby'));
             writeln(PL('   3: usuinięcie osoby'));
             writeln(PL('   4: zmiana danych osoby'));
             writeln(PL('   0: powrót do menu głównego'));
             wybor2:=False;
             repeat
               try
                 write(PL('Twoj wybór: '));
                 readln(opcja2);
                 wybor2:=True;
               except
                 writeln(PL('**niepoprawny parametr!'));
               end;
             until wybor2=True;
             case opcja2 of
               1: begin
                    writeln('WypiszOsoby');
                    WypiszOsoby();
                  end;
               2: begin
                    writeln('DodajOsobe');
                    DodajOsobe();
                  end;
               3: begin
                    writeln('UsunOsobe');
                    UsunOsobe();
                  end;
               4: begin
                    writeln('ZmienOsobe');
                    ZmienOsobe();
                  end;
             else
               writeln(PL('**funkcja niezdefiniowana!'));
             end;
           until opcja2=0;
         end;
      0: writeln(PL('Do widzenia :)'));
    else
      writeln(PL('**funkcja niezdefiniowana!'));
    end;
  until opcja1=0;
  readln();
end.
//FUNKCJE I PROCEDURY W MODULE:

unit ProcUnit;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LazUTF8;

const
  bazaOsob = 'osoby.dat';
  bazaKsiazek = 'ksiazki.dat';

type
  TAdres = record
    miasto: String[80];
    kod: String[6];
    ulica: String[80];
    nr: String[10];
  end;
  TOsoba = record
    nr: integer;
    imie: String[80];
    nazwisko: String[80];
    adres: TAdres;
  end;
  TKsiazka = record
    tytul: String[160];
    autor: String[120];
    rok: integer;
    case wypozyczona: boolean of
      True: (
        dataWyp: TDateTime;
        osoba: TOsoba;
        );
      False: ();
  end;

function PL(tekst: String): String;

function WypiszOsoby(): integer;
procedure DodajOsobe();
function WypiszKsiazki(): integer;
procedure DodajKsiazke();
procedure ZmienOsobe();
procedure UsunOsobe();
procedure UsunKsiazke();
procedure ZmienKsiazke();
procedure WypozyczKsiazke(wypozyczona:boolean);

implementation

function PL(tekst: String): String;
begin
  result:=UTF8ToConsole(tekst);
end;

function WypiszOsoby(): integer;
var
  osoba: TOsoba;
  licz: integer;
  plik: file of TOSoba;
begin
  licz:=0;
  if FileExists(bazaOsob) then
    begin
      assign(plik,bazaOsob);
      reset(plik);
      while not EoF(plik) do
        begin
          read(plik,osoba);
          writeln(licz:4,' : (',format('%.4d',[osoba.nr]),') ',osoba.imie,' ',osoba.nazwisko);
          writeln('     ',osoba.adres.ulica,' ',osoba.adres.nr,', ',
            osoba.adres.kod,' ',osoba.adres.miasto);
          inc(licz);
        end;
      close(plik);
    end
  else
    writeln(PL('Nie ma pliku z bazą osób!'));
  result:=licz;
end;

procedure DodajOsobe();
var
  osoba: TOsoba;
  plik: file of TOsoba;
  recCount: integer;
begin
  writeln(PL('Podaj dane osoby:'));
  write(PL('Podaj numer karty: ')); readln(osoba.nr);
  write(PL('Podaj imię: ')); readln(osoba.imie);
  write(PL('Podaj nazwisko: ')); readln(osoba.nazwisko);
  write(PL('Podaj ulicę: ')); readln(osoba.adres.ulica);
  write(PL('Podaj numer domu: ')); readln(osoba.adres.nr);
  write(PL('Podaj kod pocztowy: ')); readln(osoba.adres.kod);
  write(PL('Podaj miasto: ')); readln(osoba.adres.miasto);
  assign(plik,bazaOsob);
  if FileExists(bazaOsob) then
    begin
      FileMode:=2; // R/W
      reset(plik);
      recCount:=FileSize(plik);
      seek(plik,recCount);
    end
  else
    rewrite(plik);
  write(plik,osoba);
  close(plik);
end;

function WypiszKsiazki(): integer;
var
  ksiazka: TKsiazka;
  licz: integer;
  plik: file of TKsiazka;
begin
  licz:=0;
  if FileExists(bazaKsiazek) then
    begin
      assign(plik,bazaKsiazek);
      reset(plik);
      while not EoF(plik) do
        begin
          read(plik,ksiazka);
          writeln(licz:4,' : ', ksiazka.autor,' "',ksiazka.tytul,' [',
            ksiazka.rok,']');
          if ksiazka.wypozyczona then
            writeln('     wypozyczona dnia: ',DateToStr(ksiazka.dataWyp),
              ' przez (',format('%.4d',[ksiazka.osoba.nr]),') ',
              ksiazka.osoba.imie,' ',ksiazka.osoba.nazwisko);
          inc(licz);
        end;
      close(plik);
    end
  else
    writeln(PL('Nie ma pliku z bazą książek!'));
  result:=licz;
end;

procedure DodajKsiazke();
var
  ksiazka: TKsiazka;
  plik: file of TKsiazka;
  recCount: integer;
begin
  writeln(PL('Podaj dane książki:'));
  write(PL('Podaj autora: ')); readln(ksiazka.autor);
  write(PL('Podaj tytuł: ')); readln(ksiazka.tytul);
  write(PL('Podaj rok wydania: ')); readln(ksiazka.rok);
  ksiazka.wypozyczona:=False;
  assign(plik,bazaKsiazek);
  if FileExists(bazaKsiazek) then
    begin
      FileMode:=2; // R/W
      reset(plik);
      recCount:=FileSize(plik);
      seek(plik,recCount);
    end
  else
    rewrite(plik);
  write(plik,ksiazka);
  close(plik);
end;

procedure ZmienOsobe();
var
  nrOsoby, liczbaOsob: integer;
  plik: file of TOsoba;
  osoba: TOsoba;
begin
  writeln(PL('Wybierz osobę do zmiany danych:'));
  liczbaOsob:=WypiszOsoby();
  if (liczbaOsob>0) then
    begin
      repeat
        writeln('Podaj numer osoby: '); readln(nrOsoby);
      until (nrOsoby>=0) and (nrOsoby<liczbaOsob);
      assign(plik,bazaOsob);
      FileMode:=2;
      reset(plik);
      seek(plik,nrOsoby);
      read(plik,osoba);
      writeln(PL('Podaj dane osoby:'));
      write(PL('Podaj numer karty: ')); readln(osoba.nr);
      write(PL('Podaj imię ['),osoba.imie,']: '); readln(osoba.imie);
      write(PL('Podaj nazwisko ['),osoba.nazwisko,']: '); readln(osoba.nazwisko);
      write(PL('Podaj ulicę: ')); readln(osoba.adres.ulica);
      write(PL('Podaj numer domu: ')); readln(osoba.adres.nr);
      write(PL('Podaj kod pocztowy: ')); readln(osoba.adres.kod);
      write(PL('Podaj miasto: ')); readln(osoba.adres.miasto);
      seek(plik,nrOsoby);
      write(plik,osoba);
      close(plik);
    end;
end;

procedure UsunOsobe();
var
  nrOsoby, liczbaOsob, recCount, i: integer;
  plik: file of TOsoba;
  tablicaOsob: array of TOsoba;
begin
  writeln(PL('Wybierz osobę do usunięcia:'));
  liczbaOsob:=WypiszOsoby();
  if (liczbaOsob>0) then
    begin
      repeat
        writeln('Podaj numer osoby: '); readln(nrOsoby);
      until (nrOsoby>=0) and (nrOsoby<liczbaOsob);
      assign(plik,bazaOsob);
      FileMode:=2;
      reset(plik);
      recCount:=FileSize(plik);
      SetLength(tablicaOsob,recCount);
      for i:=0 to recCount-1 do
        read(plik,tablicaOsob[i]);
      close(plik);
      for i:=nrOsoby to recCount-2 do
        tablicaOsob[i]:=tablicaOsob[i+1];
      SetLength(tablicaOsob,recCount-1);
      rewrite(plik);
      for i:=0 to Length(tablicaOsob)-1 do
        write(plik,tablicaOsob[i]);
      close(plik);
    end;
end;

procedure UsunKsiazke();
var
  nrKsiazki, liczbaKsiazek, recCount, i: integer;
  plik: file of TKsiazka;
  tablicaKsiazek: array of TKsiazka;
begin
  writeln(PL('Wybierz książkę do usunięcia:'));
  liczbaKsiazek:=WypiszKsiazki();
  if (liczbaKsiazek>0) then
    begin
      repeat
        writeln('Podaj numer ksiazki: '); readln(nrKsiazki);
      until (nrKsiazki>=0) and (nrKsiazki<liczbaKsiazek);
      assign(plik,bazaKsiazek);
      FileMode:=2;
      reset(plik);
      recCount:=FileSize(plik);
      SetLength(tablicaKsiazek,recCount);
      for i:=0 to recCount-1 do
        read(plik,tablicaKsiazek[i]);
      close(plik);
      for i:=nrKsiazki to recCount-2 do
        tablicaKsiazek[i]:=tablicaKsiazek[i+1];
      SetLength(tablicaKsiazek,recCount-1);
      rewrite(plik);
      for i:=0 to Length(tablicaKsiazek)-1 do
        write(plik,tablicaKsiazek[i]);
      close(plik);
    end;
end;

procedure ZmienKsiazke();
  var
    nrKsiazki, liczbaKsiazek: integer;
    plik: file of TKsiazka;
    ksiazka: TKsiazka;
  begin
    writeln(PL('Wybierz książkę do zmiany danych:'));
    liczbaKsiazek:=WypiszKsiazki();
    if (liczbaKsiazek>0) then
      begin
        repeat
        writeln(PL('Podaj numer książki: ')); readln(nrKsiazki);
        until (nrKsiazki>=0) and (nrKsiazki<liczbaKsiazek);
        assign(plik,bazaKsiazek);
        FileMode:=2;
        reset(plik);
        seek(plik,nrKsiazki);
        read(plik,ksiazka);
        writeln(PL('Podaj dane książki:'));
        write(PL('Podaj autora: ')); readln(ksiazka.autor);
        write(PL('Podaj tytuł: ')); readln(ksiazka.tytul);
        write(PL('Podaj rok wydania: ')); readln(ksiazka.rok);
        seek(plik,nrKsiazki);
        write(plik,ksiazka);
        close(plik);
      end;
  end;

procedure WypozyczKsiazke(wypozyczona:boolean);
var
   nrKsiazki, liczbaKsiazek,liczbaOsob,nrOsoby: integer;
   plik: file of TKsiazka;
   ksiazka: TKsiazka;
begin
  case wypozyczona of
    True:
      begin
      writeln(PL('Wybierz książkę, którą wypożyczamy: '));
      liczbaKsiazek:=WypiszKsiazki();

      if (liczbaKsiazek>0) then
      begin
        repeat
        writeln(PL('Podaj numer książki: ')); readln(nrKsiazki);
        until (nrKsiazki>=0) and (nrKsiazki<liczbaKsiazek);
        assign(plik,bazaKsiazek);
        FileMode:=2;
        reset(plik);
        seek(plik,nrKsiazki);
        read(plik,ksiazka);
        writeln(PL('Podaj datę wypożyczenia książki:')); readln(ksiazka.dataWyp);
        liczbaOsob:=WypiszOsoby();
        repeat
        writeln(PL('Podaj numer osoby, która wypożycza: ')); readln(nrOsoby);
        until (nrOsoby>=0) and (nrOsoby<liczbaOsob);
      //dataWyp: TDateTime;
      //osoba: TOsoba;

      end;
       end;

    False:
      //begin

     end;

end;

end.

Proszę o pomoc w ostatniej Procedurze, WypozyczKsiazke, którą piszę , bo niby mam koncepcję ale nie wiem czy zadziała.

3

A nie możesz po prostu pobrać aktualnej daty zamiast pytać o nią użytkownika?

var
  today : TDateTime;
begin
  today := Now;

1

@karpov: poniekąd można pobrać aktualną datę z systemu (dlatego dałem Ci plusika), ale żeby móc przetestować działanie programu, trzeba by wyłączyć w systemie usługę aktualizowania daty i czasu i modyfikować systemowy zegar w trakcie testów manualnych. Albo testować program kilka dni, żeby mieć różne daty w systemie. ;)

@brotomasz: wczytuj datę jako zwykły ciąg znaków i konwertuj go na TDate za pomocą funkcji TryStrToDate. Jeśli wejściowy ciąg znaków zawiera poprawnie zapisaną datę, funkcja uzupełni parametr Value i zwróci True. W przeciwnym razie zwróci False. Funkcja ta posiada wiele wersji różniących się parametrami, więc możesz sobie dobrać odpowiednią do swoich potrzeb.

0

W zakresie wprowadzania daty - to, co napisał @furious programming ma sens, ale... pamiętajmy, że ludzie z założenia to idioci ;)
W związku z tym podejrzewam, że w większości przypadków podana funkcja zwróci false. Zwłaszcza, że podany program nie daje użytkownikowi żadnych wskazówek (coś w stylu "wprowadź datę w formacie DD-MM-RRRR") odnośnie sposobu podania daty, więc pewnie będą wpisywać różne wynalazki w stylu 12/12/2010 albo 13 luty 18, dlatego moim zdaniem, jeśli opcja pobierania daty bieżącej nie jest odpowiednia i rzeczywiście chcemy, żeby użytkownik wprowadził samodzielnie datę, powinniśmy go prowadzić za rączkę.

Logika nakazuje najpierw zapytać o dzień miesiąca, a potem sprawdzić, co takiego wpisał. Jeśli poda 3 albo 18 to przyjąć to i przejść do kolejnego etapu (czyli określenie miesiąca), a jeśli wpisze coś nieodpowiedniego (np. 54435 albo kaszanka) to poinformować o błędnym wpisaniu i prosić o powtórkę - do skutku, czyli do chwili wprowadzenia poprawnej daty.
Następnie analogicznie postąpić z miesiącem i rokiem.

ALE miesiące mają różną długość, do tego bywają lata przestępne. W związku z tym, ja bym odpytywanie zaczął od drugiej strony - czyli najpierw rok i miesiąc. Tutaj za wiele kombinacji nie ma, można co najwyżej jakoś wprowadzić ograniczenie dostępnych lat - np. między 2010 a 2030 (to już do wyboru przez OP'a). Następnie, mając rok i miesiąc, możemy sprawdzić, czy wprowadzony dzień ma sens. Bo np. dając 30 jako dzień miesiąca wszystko będzie OK dla grudnia, ale już niekoniecznie dla lutego. Co 4 lata mamy rok przestępczy ;), więc także wypadałoby to uwzględnić i dodać jeden dodatkowy dzień do lutego.

A mając już wprowadzoną datę w postaci 3 liczb, składasz ją do stringa zgodnie z wymaganym formatem i przekazujesz do funkcji konwertującej.

0

Nie ma sensu się męczyć z wprowadzaniem daty – wystarczy podpowiedź co do formatu. Co prawda funkcja konwertująca posiada pewne ograniczenia, np. brak wsparcia słownych nazw miesięcy (choć nie jestem pewien jak to wygląda w tej chwili, dawniej takiego wsparcia nie było), ale do tak prostego zadania to co podałem spokojnie wystarczy.

Natomiast do aplikacji okienkowych są specjalne kontrolki, jak TDateTimePicker, których dane nie wymagają walidacji za strony programisty – to dzieje się w kodzie komponentu.

0

Chyba nie dam sobie rady... Kombinuję jak to zrobić i mi nie wychodzi... Nawet nie wiem co oznacza to
seek(plik,nrKsiazki); (w domyśle uważam, że tutaj szuka tego całego rekordu dla danego numeru książki) i nie wiem co oznacza to read(plik,ksiazka); (read to przecież z angielska czytaj a tutaj chyba to read coś zmienia w pliku (?)).

Napisałem coś takiego co nie działa poprawnie:

procedure WypozyczKsiazke(wypozyczona:boolean);
var
  nrKsiazki, liczbaKsiazek,liczbaOsob,nrOsoby: integer;
  plik: file of TKsiazka;
  plikOsoby:file of TOsoba;
  ksiazka: TKsiazka;
  today:TDateTime;
begin
 today:=Now;
 case wypozyczona of
   True:
     begin
     writeln(PL('Wybierz numer książki, którą wypożyczamy: '));
     liczbaKsiazek:=WypiszKsiazki();

     if (liczbaKsiazek>0) then
     begin
       repeat
       writeln(PL('Podaj numer książki: ')); readln(nrKsiazki);
       until (nrKsiazki>=0) and (nrKsiazki<liczbaKsiazek);
       assign(plik,bazaKsiazek);
       FileMode:=2;
       reset(plik);
       seek(plik,nrKsiazki);
       read(plik,ksiazka);
       writeln(PL('Zapisano dzisiejszą datę wypożycznia książki:'));
       ksiazka.dataWyp:=today;
       liczbaOsob:=WypiszOsoby();
       repeat
       writeln(PL('Podaj numer osoby, która wypożycza: ')); readln(nrOsoby);
       until (nrOsoby>=0) and (nrOsoby<liczbaOsob);
       assign(plikOsoby, bazaOsob);
       seek(plikOsoby,nrOsoby);
       read(plik,ksiazka.osoba);

     //dataWyp: TDateTime;
     //osoba: TOsoba;
      close(plik);
      close(plikOsoby);
     end;
      end;

   False:
     //begin

    end;       

Bardzo proszę o pomoc w napisaniu tej procedury żeby działała, doceniam wszelkie sugestie i rady.

0
brotomasz napisał(a):

Nawet nie wiem co oznacza to seek(plik,nrKsiazki);

Od tego jest dokumentacja, nie domysły. Seek – przesuwa kursor w pliku na pozycję określoną przez patametr (dla plików typowanych jest to numer rekordu, nie numer bajtu).

FileMode nie ruszaj – wystarczy, że używasz Reset/ReWrite.

brotomasz napisał(a):

Napisałem coś takiego co nie działa poprawnie:

Ta procedura modyfikuje dane wczytane z pliku (w pamięci), ale ich do pliku nie zapisuje.

0

Pytanie- czy chociaż szukałeś odpowiedzi w necie?

To są podstawy, pełno jest informacji, artykułów, poradników itp. odnośnie operacji na plikach w Pascalu. Jeśli szukałeś i czegoś nie rozumiesz to pomożemy, ale mam wrażenie, że po prostu stwierdziłeś, w nie rozumiesz i czekasz na wyjaśnienia :(

1 użytkowników online, w tym zalogowanych: 0, gości: 1