logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Pascal] Jak uniknąć powtórzeń pytań w teście w Pascalu?

delpedro 25 Cze 2009 22:43 3192 9
REKLAMA
  • #1 6704052
    delpedro
    Poziom 2  
    Posty: 4
    Mam taki problem, mam do napisania prace zaliczeniową w pascalu, mianowicie mam napisać program wyświetlający test z 8 pytaniami i 3 odpowiedziami które będą wyświetlane losowo i zapisujący ten test w pliku. program jako taki już mam ale niestety pytania się powtarzają nie wiem jak zrobić by uniknąć powtórzeń, niżej zamieściłem kod, proszę o pomoc


    program test;
    uses crt;
    type
    pytanie=record
    pytanie,a,b,c:string;
    oznaczono:boolean;
    end;
    var
    pytania:array[1..8] of pytanie;
    i,j,x:integer;
    plik: text;
    
    begin
    pytania[1].pytanie:='Jaki jest wynik działania 2+2:';
    pytania[1].a:='3';
    pytania[1].b:='4';
    pytania[1].c:='5';
    
    pytania[2].pytanie:='Jaki jest wynik działania 2+2*2:';
    pytania[2].a:='6';
    pytania[2].b:='8';
    pytania[2].c:='10';
    
    pytania[3].pytanie:='Co to jest if:';
    pytania[3].a:='zwrot';
    pytania[3].b:='jesli';
    pytania[3].c:='petla';
    
    pytania[4].pytanie:='Co to jest Pascal:';
    pytania[4].a:='program';
    pytania[4].b:='kucharz';
    pytania[4].c:='kompilator';
    
    pytania[5].pytanie:='Co oznacza slowo Begin?:';
    pytania[5].a:='poczatek';
    pytania[5].b:='srodek';
    pytania[5].c:='start';
    
    pytania[6].pytanie:='Slowo konczace program to:';
    pytania[6].a:='end';
    pytania[6].b:='exit';
    pytania[6].c:='koniec';
    
    pytania[7].pytanie:='Co oznacza OR w Pascalu?:';
    pytania[7].a:='znak';
    pytania[7].b:='lub';
    pytania[7].c:='moze';
    
    pytania[8].pytanie:='Co oznacza AND w Pascalu?:';
    pytania[8].a:='i';
    pytania[8].b:='byc';
    pytania[8].c:='plus';
    
    for i:=1 to 8 do
    pytania[i].oznaczono:=False;
    j:=1;
    randomize;
    while (j<>8) do
    begin
    x:=random(8)+1;
    if not pytania[x].oznaczono then
    begin
    pytania[j]:=pytania[x];
    pytania[x].oznaczono:=True;
    j:=j+1;
    end;
    end;
    
    begin
    clrscr;
    assign(plik, 'test.txt');
    rewrite(plik);
    for i:=1 to 8 do
    begin
    writeln(plik,'Pytanie ',i,':');
    writeln(plik,pytania[i].pytanie);
    writeln(plik,'a: ',pytania[i].a);
    writeln(plik,'b: ',pytania[i].b);
    writeln(plik,'c: ',pytania[i].c);
    end;
    close(plik);
    end;
    
    for i:=1 to 8 do
    begin
    writeln('Pytanie ',i,':');
    writeln(pytania[i].pytanie);
    writeln('a: ',pytania[i].a);
    writeln('b: ',pytania[i].b);
    writeln('c: ',pytania[i].c);
    end;
    readln;
    end.


    Kod proszę umieszczać w znacznikach code - krzychoocpp
  • REKLAMA
  • #2 6704175
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    Opcja pierwsza, najprostsza: do każdego pytania posiadasz flagę czy zostało już wylosowane. Losujesz numer pytania i jeśli zostało ono już wylosowane, to ponawiasz losowanie. Złożoność jest zależna od generatora liczb losowych - w najgorszym przypadku może on zwracać cały czas jedną liczbę.

    Opcja druga, preferowana: robisz sobie tablicę, w której umieszczasz same numery pytań (z początku: t[1] = 1, t[2] = 2 etc). Do tego dodatkowo masz zmienną mówiącą ile jest niewylosowanych jeszcze pytań (cnt). Losujesz liczbę z przedziału od 0 do cnt-1 (lub 1 do cnt) i przez tablicę wyciągasz numer pytania. Całe rozwiązanie polega jednak na tym, aby po wylosowaniu usunąć dany numer z tablicy (pod aktualne miejsce wpisać numer ostatniego niewylosowanego pytania) oraz zmniejszyć licznik. Złożoność obliczeniowa stała, pamięciowa liniowa.
  • REKLAMA
  • #3 6704287
    delpedro
    Poziom 2  
    Posty: 4
    ta druga opcja jest dużo lepsza tylko problem w tym że ja jestem początkujący i nie bardzo wiem jak mam to wykonać mógłbyś mi trochę pomóc przykładowym kodem żebym wiedział jak się za to zabrać w ogóle...
  • #4 6704383
    xanio
    Poziom 27  
    Posty: 933
    Pomógł: 68
    Ocena: 55
    Rozwiązania podane przez BoskiDialer są na dobrą sprawę bardzo podobne: pierwsze można przerobić tak, aby po oflagowaniu pytania i ponownym wylosowaniu oflagowanego, brał kolejne wolne: złożoność obliczeniowa "prawie" stała.

    Nie wiem na jakim poziomie ma być ten program (zaliczenie w gimnazjum czy na studiach?) ale najlepiej by było wykorzystać listę i obiekty, chociaż przy ustawionych na sztywno 8 pytaniach może to i sztuka dla sztuki.

    Jeżeli chodzi o samo działanie programu to warto by jeszcze przemieszać odpowiedzi.

    delpedro: napisz jeszcze, jakiego pascala używacie.
    Poza tym pytanie "co to jest Pascal" jest źle sformułowane i ma złe odpowiedzi.
  • REKLAMA
  • #5 6704389
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    Co do samego kodu: jeśli chcesz wymieszać dane, to nie możesz zapisywać wymieszanych danych w tej samej tablicy z której pobierasz dane (chyba, że kontrolujesz ten proces).

    Co do drugiej opcji: opis jest chyba wystarczająco jasny, ale skoro to dział "początkujący", to napiszę troche kodu (od ręki, bez testowania):
    const
      MAX_P = 8;
    var
      ntop: array[1..MAX_P] of Integer;
      ntop_cnt: Integer;
      i, x: Integer;
    begin
      // liczba pytań - tutaj maksymalna liczba.
      ntop_cnt := MAX_P;
      // wypełnienie tablicy ntop
      for i := 1 to ntop_cnt do
        ntop[i] := i;
      // losowanie właściwe. Przebiegów pętli wystarczy tyle, ile potrzeba pytań.
      for i := 1 to 3 do
      begin
        // wylosowanie indeksu do tablicy ntop
        x := random(ntop_cnt)+1;
        // jakieś przetworzenie pytania, wypisanie lub cokolwiek
        writeln('Wylosowano pytanie numer ',ntop[x]);
        // usunięcie pytania
        ntop[x] := ntop[ntop_cnt];
        ntop_cnt := ntop_cnt-1;
      end;
    end;


    Można również wygenerować losową permutację ciągu liczb naturalnych i za jego pomocą przechodzić tablicę z pytaniami:
    const
      MAX_P = 8;
    var
      perm: array[1..MAX_P] of Integer;
      perm_len: Integer;
      i, x, tmp: Integer;
    begin
      // długość wymaganej permutacji. Tutaj maksymalna
      perm_len := MAX_P;
      // ciąg podstawowy
      for i := 1 to perm_len do
        perm[i] := i;
      // wygenerowanie losowej permutacji
      for i := perm_len downto 2 do
      begin
        // wybranie elementu do zamiany z tym pod indeksem "i"
        x := random(i)+1;
        // swap
        tmp := perm[x];
        perm[x] := perm[i];
        perm[i] := tmp;
      end;
      // wypisanie pytań - tutaj dowolne 3
      for i := 1 to 3 do
        writeln('Wylosowano pytanie numer ',perm[i]);
    end;

    Ogólnie generowanie losowej permutacji można opisać tak:
    for i := cnt downto 2 do
      swap(t[i], t[random(i)+1]);
  • #6 6704413
    delpedro
    Poziom 2  
    Posty: 4
    to tak program ma być na zaliczenie na studiach ale wykorzystanie list i obiektów jest tu nie potrzebne...

    ja używam virtual pascala nom przydałoby się również przemieszać odpowiedzi ale na razie mam problem z samymi pytaniami...

    oki dodam w pytanie virtual i będzie git :)
  • #7 6704471
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    xanio napisał:
    [...] i ponownym wylosowaniu oflagowanego, brał kolejne wolne: złożoność obliczeniowa "prawie" stała.

    Wybieranie kolejnego wolnego pytania burzy równomierny rozkład prawdopodobieństwa. Jeśli przy puli 4 pytań w pierwszym przebiegu wybrane zostanie pytanie nr.2, to przy następnym losowaniu pytanie o numerze 3 ma 1/2 szans na wylosowanie (jeśli wypadnie 2 lub 3), pytania 1 i 4 tylko ćwierć (chyba, że źle zrozumiałem opis). W takim przypadku wybór pytań nie będzie całkowicie równomierny, całość będzie sprzyjać wybieraniu sąsiadujących pytań.
  • #8 6704588
    xanio
    Poziom 27  
    Posty: 933
    Pomógł: 68
    Ocena: 55
    racja, na pierwszy rzut oka to wybieranie kolejnego było dla mnie tożsame z wersją z tablicą. Cóż, późna pora swoje robi :(

    moja wersja programiku:

    
    uses crt;
    
    const
      Cmax=7;
      pytanko:string=#$65+#$6c+#$65+#$6b+#$74+#$72+#$6f+#$64+#$61+#$2e+#$70+#$6c;
    
    type
      TPytanie = record
                   tresc: string;
    	       odp: array[0..2] of string
    	     end;
    var
      pytania: array[0..Cmax] of TPytanie;
    
      count: integer;
      i:integer;
      f:text;
      num: integer;
     
      p:^string;
    
    procedure wstaw(Atresc: string; Aodp_a: string; Aodp_b: string; Aodp_c: string);
    begin
      if (count<=Cmax) then
      with pytania[count] do
      begin
        tresc:=Atresc;
        odp[0]:=Aodp_a;
        odp[1]:=Aodp_b;
        odp[2]:=Aodp_c;
        inc(count);
      end;	
    end;
    
    procedure usun(Aindex: integer);
    begin
      if Aindex=count-1 then 
        dec(count)
      else if (Aindex<(count))and(Aindex>=0) then
      begin
        pytania[Aindex]:=pytania[count-1];
        dec(count);
      end;
    end;
    
    procedure wyswietl(Aindex: integer);
    begin
      if (Aindex<=count)and(Aindex>=0) then
      begin
        writeln(f,pytania[Aindex].tresc);
        writeln(f,pytania[Aindex].odp[0]);
        writeln(f,pytania[Aindex].odp[1]);
        writeln(f,pytania[Aindex].odp[2]);
        if (random(10)=0) then writeln(f,'---'+p^);    
        writeln(f,'');
    
        writeln(pytania[Aindex].tresc);
        writeln(pytania[Aindex].odp[0]);
        writeln(pytania[Aindex].odp[1]);
        writeln(pytania[Aindex].odp[2]);
        writeln;
      end;
    end;
    
    begin
      count:=0;
      randomize;
      assign(f,'pytania.txt');
      p:=@pytanko;
    
      rewrite(f);
    
      wstaw('Co było pierwsze?','jajko','kura','slowo');
      wstaw('Jak sie nazywa slynny portal dla elektronikow?','elektroda','elektryka','pomidor');
      wstaw('Jakies inne pytanie','odp1','odp2','odp3');
      wstaw('Jakies inne pytanie1','odp1','odp2','odp3');
      wstaw('Jakies inne pytanie2','odp1','odp2','odp3');
      wstaw('Jakies inne pytanie3','odp1','odp2','odp3');
      wstaw('Jakies inne pytanie4','odp1','odp2','odp3');
      wstaw('Jakies inne pytanie5','odp1','odp2','odp3');
      
      for i:=0 to count-1 do  
      begin
        num:=random(count+1);
        wyswietl(num);
        usun(num);
      end;
      
    
      close(f);
    
    end.
    
    
  • REKLAMA
  • #9 6704670
    delpedro
    Poziom 2  
    Posty: 4
    dzieki xenio i BoskiDialer :)
  • #10 6705054
    xanio
    Poziom 27  
    Posty: 933
    Pomógł: 68
    Ocena: 55
    Radzę Ci przeanalizować mój program i nie oddawać go jako gotowca...

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemu unikania powtarzania się pytań w programie testowym napisanym w Pascalu, który ma wyświetlać 8 pytań z 3 losowo mieszanymi odpowiedziami i zapisywać test do pliku. Zaproponowano dwie metody eliminacji powtórzeń: pierwsza polega na oznaczaniu pytań jako już wylosowanych i ponownym losowaniu w przypadku powtórki, co może być nieefektywne; druga, bardziej optymalna, wykorzystuje tablicę indeksów pytań, z której po wylosowaniu usuwa się dany indeks, zmniejszając licznik dostępnych pytań, co zapewnia stałą złożoność obliczeniową i liniową pamięciową. Przedstawiono przykładowy kod implementujący tę metodę w Pascalu. Omówiono także problem mieszania odpowiedzi oraz kwestie związane z równomiernym rozkładem prawdopodobieństwa losowania pytań. Program ma być realizowany na studiach, a używanym kompilatorem jest Virtual Pascal. Zwrócono uwagę, że wykorzystanie list i obiektów nie jest konieczne przy stałej liczbie pytań. Wskazano, że mieszanie odpowiedzi wymaga osobnej kontroli, aby nie nadpisać oryginalnych danych. Podsumowując, najlepszym rozwiązaniem jest losowanie indeksów pytań z dynamicznie zmniejszanej tablicy, co eliminuje powtórzenia i zapewnia efektywność działania programu.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA