Tarvitsen Apua!

Uuppi

Hei, tarvitsisin ohjelmaani 5 kolmenumeroista lukua jotka eivät saa olla samoja, mutta en oikein tiedä kuinka sen tekisin.

Esimerkki jossa voi mahdollisesti tulla samoja:
begin
Label1.Caption := inttostr(randomrange(1,200));
Label2.Caption := inttostr(randomrange(1,200));
Label3.Caption := inttostr(randomrange(1,200));
Label4.Caption := inttostr(randomrange(1,200));
Label5.Caption := inttostr(randomrange(1,200));
end;

osaan kyllä kahdella luvulla tehdä ettei tule samoja mutta useammalla en.

repeat
Label2.Caption := inttostr(randomrange(1,200));
until Label2.Caption Label1.Caption;

apua, kiitos :)

13

664

    Vastaukset

    Anonyymi (Kirjaudu / Rekisteröidy)
    5000
    • L A R A

      Ongelman voi ratkaista usealla tavalla. Esitän seuraavanlaisen tavan siksi että se antaa vinkkejä mitä voisi olla ja sen lisäksi kun kokeilet koodia niin haluanet kehittää sitä (Yksinkertaisempiakin ratkaisuja on mutta ...)

      Tee uusi projekti. Lisää formille Button, Edit ja Memo -komponentit.
      Luo Buttonille onClick-tapahtuma ja formille onCreate-tapahtuma.

      Liisää tyypin (type sanan jälkeinen lohko) esittelyyn Tmjono-luokka.
      ...

      { Tmjono }

      Tmjono = class(TStringList)
      public
      constructor Create;
      procedure PoistaSamat;
      function maara(kpl:integer):boolean;
      end;

      ...

      Tuo luokka periytyy TStringList-luokasta (TStringList luokasta löytyy mm. tällä keskustelualueella lisätietoja). Huomaa että tuota luokkaa voi käyttää muuassakin
      tarkoituksessa kuin satunnaisluvuilla ja sillä on paljon toimintoja!

      Lisäksi RandomRange funktion voi tehdä näin jos sitä ei ole vanhemmissa versioissa:

      function randomrange(eka,vika:integer):integer;
      var
      vali,satluku:integer;
      begin
      vali := vika-eka 1;
      satluku:=random(vali);
      result := satluku eka;
      end;


      Koodin voi täydentää vaikkapa tälläiseksi:


      { TForm1 }

      procedure TForm1.Button1Click(Sender: TObject);
      var
      kpl:integer;
      Satunnaisluvut:Tmjono;
      begin
      Satunnaisluvut:=Tmjono.Create;
      kpl := StrToInt(Edit1.Text);
      repeat
      Satunnaisluvut.Add(inttostr(randomrange(1,200)));
      Satunnaisluvut.PoistaSamat;
      until Satunnaisluvut.Maara(kpl);
      Memo1.Lines.Assign(Satunnaisluvut);
      FreeAndNil(Satunnaisluvut);
      end;

      procedure TForm1.FormCreate(Sender: TObject);
      begin
      Randomize;
      end;

      { Tmjono }

      constructor Tmjono.Create;
      begin
      inherited Create;
      self.Sorted:= true;
      end;

      procedure Tmjono.PoistaSamat;
      var
      i:integer;
      begin
      i := 0 ;
      while i < self.Count-2 do
      begin
      if self.Strings[i] = self.Strings[i 1] then self.Delete(i 1);
      inc(i);
      end;
      end;

      function Tmjono.maara(kpl: integer): boolean;
      begin
      result:= self.Count> kpl;
      end;

      • Uuppi

        Kiitos paljon nopeasta ja hyvästä vastauksesta. Nyt sain toimimaan


      • Uuppi

        Taas avulle tarvetta. Muokkailin vähän koodia ja nyt tulee virhe:
        'Operation not allowed on sorted list'. Luulen että se johtuu siitä kun koodissani on mm. nämä:

        Satunnaisluvut.Assign(Memo.Lines);

        Satunnaisluvut.Insert(1,randomcrd randomclr);

        Olisiko jotain keinoa korjata? En löytänyt googlesta mitään tuosta 'Operation not allowed on sorted list' virheestä.


      • Uuppi
        Uuppi kirjoitti:

        Taas avulle tarvetta. Muokkailin vähän koodia ja nyt tulee virhe:
        'Operation not allowed on sorted list'. Luulen että se johtuu siitä kun koodissani on mm. nämä:

        Satunnaisluvut.Assign(Memo.Lines);

        Satunnaisluvut.Insert(1,randomcrd randomclr);

        Olisiko jotain keinoa korjata? En löytänyt googlesta mitään tuosta 'Operation not allowed on sorted list' virheestä.

        Sainkin ehkä toimimaan: Satunnaisluvut.Sorted := false;


      • Uuppi

        Hmm.. huomasinkin että tuolla keinolla tulee silti välillä samoja.


        begin
        Satunnaisluvut:=Tmjono.Create;
        randomize;
        kpl := 4;
        repeat
        randomclr := Clrs[randomrange(0,4)];
        randomcrd := Crds[randomrange(0,13)];
        Satunnaisluvut.Add(randomcrd randomclr);
        Satunnaisluvut.PoistaSamat;

        until Satunnaisluvut.maara(kpl);
        memo.Lines.Assign(satunnaisluvut);
        end;

        Haluaisin myös tietää miten saan tehtyä niin, että esim. kun 5 eri stringiä on listattu, ja listaa uudestaan, niin se ei vaihda vaikka ensimmäistä kolmea stringiä ja vaihtaa vain viimeiset 2 eikä ne saa olla samoja kuin jotkut kolmesta ensimmäisestä :D monimutkaista, mutta toivottavasti ymmärsitte.. Toivottavasti joku voi auttaa :


      • huomaa
        Uuppi kirjoitti:

        Hmm.. huomasinkin että tuolla keinolla tulee silti välillä samoja.


        begin
        Satunnaisluvut:=Tmjono.Create;
        randomize;
        kpl := 4;
        repeat
        randomclr := Clrs[randomrange(0,4)];
        randomcrd := Crds[randomrange(0,13)];
        Satunnaisluvut.Add(randomcrd randomclr);
        Satunnaisluvut.PoistaSamat;

        until Satunnaisluvut.maara(kpl);
        memo.Lines.Assign(satunnaisluvut);
        end;

        Haluaisin myös tietää miten saan tehtyä niin, että esim. kun 5 eri stringiä on listattu, ja listaa uudestaan, niin se ei vaihda vaikka ensimmäistä kolmea stringiä ja vaihtaa vain viimeiset 2 eikä ne saa olla samoja kuin jotkut kolmesta ensimmäisestä :D monimutkaista, mutta toivottavasti ymmärsitte.. Toivottavasti joku voi auttaa :

        Huomaa että Randomize rutiinia ei saane suorittaa kuin kerran koko ohjelman käytön aikana.


      • Delphi_again

        Terve,

        Toivottavasti ymmärsin oikein kysymyksesi,
        alla on pieni esimerkki siitä kuinka tuon tekee nopeasti/helposti,
        pitäisi olla aika virhe vapaa/yksinkertainen esimerkki, eli siitä vaan jalostamaan...
        (Ei ole optimoitu yms, kuhan päästäni heitin esimerkin, josta varmaan saat taidolla ja tunteella paremman/nopeamman)

        procedure TForm1.Button1Click(Sender: TObject);
        var
        i : Integer;
        MyRndNumber : String;
        RndNumberCount : Integer;
        begin
        Memo1.Clear;
        RndNumberCount := 5;

        // Random seed
        Randomize;

        while true do
        begin
        // Time to other threads
        Application.ProcessMessages;
        Sleep(1);

        MyRndNumber := GetRandomNumbers(3);

        // Validate
        for I := 0 to Memo1.Lines.Count do
        begin
        if (Memo1.Lines[I] = MyRndNumber) then
        begin
        MyRndNumber := '';
        Break;
        end;
        end;

        // Add to my list if valid
        if MyRndNumber '' then
        Memo1.Lines.Add(MyRndNumber);

        // Check if ready
        if Memo1.Lines.Count >= RndNumberCount then
        Break;
        end;
        end;

        function TForm1.GetRandomNumbers(const ANumberCount : Cardinal) : String;
        var
        Rnd : Integer;
        begin
        // Invalid return value
        Result := '';

        while (Length(Result) < ANumberCount) do
        begin
        // Get random values
        Rnd := Random(10);

        // Set result
        Result := Result IntToStr(Rnd);
        end;
        end;


      • Uuppi
        Delphi_again kirjoitti:

        Terve,

        Toivottavasti ymmärsin oikein kysymyksesi,
        alla on pieni esimerkki siitä kuinka tuon tekee nopeasti/helposti,
        pitäisi olla aika virhe vapaa/yksinkertainen esimerkki, eli siitä vaan jalostamaan...
        (Ei ole optimoitu yms, kuhan päästäni heitin esimerkin, josta varmaan saat taidolla ja tunteella paremman/nopeamman)

        procedure TForm1.Button1Click(Sender: TObject);
        var
        i : Integer;
        MyRndNumber : String;
        RndNumberCount : Integer;
        begin
        Memo1.Clear;
        RndNumberCount := 5;

        // Random seed
        Randomize;

        while true do
        begin
        // Time to other threads
        Application.ProcessMessages;
        Sleep(1);

        MyRndNumber := GetRandomNumbers(3);

        // Validate
        for I := 0 to Memo1.Lines.Count do
        begin
        if (Memo1.Lines[I] = MyRndNumber) then
        begin
        MyRndNumber := '';
        Break;
        end;
        end;

        // Add to my list if valid
        if MyRndNumber '' then
        Memo1.Lines.Add(MyRndNumber);

        // Check if ready
        if Memo1.Lines.Count >= RndNumberCount then
        Break;
        end;
        end;

        function TForm1.GetRandomNumbers(const ANumberCount : Cardinal) : String;
        var
        Rnd : Integer;
        begin
        // Invalid return value
        Result := '';

        while (Length(Result) < ANumberCount) do
        begin
        // Get random values
        Rnd := Random(10);

        // Set result
        Result := Result IntToStr(Rnd);
        end;
        end;

        Kiitoksia, luulenpa että sain juuri toimimaan omalla tekniikalla, mutta sillointällöin tulee virhe: 'List index out of bounds(4)'. Sen varmaan saan korjattua itse.


      • afdsa
        Uuppi kirjoitti:

        Hmm.. huomasinkin että tuolla keinolla tulee silti välillä samoja.


        begin
        Satunnaisluvut:=Tmjono.Create;
        randomize;
        kpl := 4;
        repeat
        randomclr := Clrs[randomrange(0,4)];
        randomcrd := Crds[randomrange(0,13)];
        Satunnaisluvut.Add(randomcrd randomclr);
        Satunnaisluvut.PoistaSamat;

        until Satunnaisluvut.maara(kpl);
        memo.Lines.Assign(satunnaisluvut);
        end;

        Haluaisin myös tietää miten saan tehtyä niin, että esim. kun 5 eri stringiä on listattu, ja listaa uudestaan, niin se ei vaihda vaikka ensimmäistä kolmea stringiä ja vaihtaa vain viimeiset 2 eikä ne saa olla samoja kuin jotkut kolmesta ensimmäisestä :D monimutkaista, mutta toivottavasti ymmärsitte.. Toivottavasti joku voi auttaa :

        No tuo loppuosa vaatimuksistasi voidaan lisätä vaikka näin

        Lisää luokan TForm1 määrittelyyn private ja public osien väliin luokan
        aliohjelma Sailyta3ekaajaArvo2Lisaa
        siis näin

        ...
        private
        { private declarations }
        procedure Sailyta3ekaajaArvo2Lisaa;
        public
        ...


        Täydennä koodi osaa vaikkapa näin


        procedure TForm1.Sailyta3ekaajaArvo2Lisaa;
        var
        i,ekatkpl,kaikkiaan:integer;
        sl:TStringList;
        s:string;
        jatka, olijo:boolean;
        begin
        sl:=TStringList.Create;
        i := 0;
        ekatkpl := 3;
        kaikkiaan := ekatkpl 2;
        jatka := i < Memo1.Lines.Count;
        while jatka do
        begin
        sl.Add(Memo1.Lines[i]);
        inc(i);
        jatka := i < ekatkpl;
        if jatka then jatka := i < Memo1.Lines.Count;
        end;
        repeat
        s:=inttostr(randomrange(1,200));
        olijo := false;
        for i:= 0 to sl.Count-1 do
        if s = sl[i] then olijo := true;
        if olijo = false then sl.Add(s);
        until sl.Count >= kaikkiaan;
        Memo1.Lines.Assign(sl);
        FreeAndNil(sl);
        end;
        ...

        Tuota voit testata vaikkapa niin että luot uuden painikkeen
        ja täydennät sitä vaikkapa näin:

        procedure TForm1.Button2Click(Sender: TObject);
        begin
        Sailyta3ekaajaArvo2Lisaa;
        end;


    • Polullakulkija

      Tässä yksi ratkaisu lisää. Ideana tässä on mm se että jos luvut hylätään niin
      ne ei ole mukana uudessa arvonnassa. Lisäksi toteutus on sellainen että voit
      valita mitkä tahansa arvotuista pois. Arvotut laitetaan ListBox1:n josta voit
      esim hiirellä valita poistettavat. Poisto tapahtuu button2:lla.

      Button1:n painaminen on eräänlainen peruskäyttö ja Button3:n ratkaisu hyödyntää
      nuo erikoisuudet. Button2:n painaminen tuo myös näytölle(Memo1) näkyviin
      ne arvot mitkä on kielletty.


      Luokkien esittely on siis tälläinen

      TForm1 = class(TForm)
      Button1: TButton;
      Button2: TButton;
      Button3: TButton;
      Edit1: TEdit;
      ListBox1: TListBox;
      Memo1: TMemo;
      procedure Button1Click(Sender: TObject);
      procedure Button2Click(Sender: TObject);
      procedure Button3Click(Sender: TObject);
      procedure FormCreate(Sender: TObject);
      procedure FormDestroy(Sender: TObject);
      private
      { private declarations }
      EiSallitut:TStringList;
      public
      { public declarations }
      end;


      { TSatunnaisluvut }

      TSatunnaisluvut = class
      private
      FKielletytArvot,FSaadutArvot:TStringList;
      FKpl, FMin, FMax:integer;
      function OnkoKielletty(arvo:string):boolean;
      public
      constructor Create;
      procedure AsetaKielletytArvot(const ASl:TStringList);
      procedure AsetaMaara(kpl:integer);
      procedure AsetaRajaArvot(AMin,AMax:integer);
      procedure ArvoLuvut;
      procedure LueArvotut(var ASl:TStringList);
      procedure LueKielletytJaArvotut(var ASl:TStringList);
      destructor Destroy; override;
      end;


      Ja koodin osuus on seuraavanlainen

      procedure TForm1.Button1Click(Sender: TObject);
      var
      Satunnaisluvut:TSatunnaisluvut;
      sl:TStringList;
      begin
      Satunnaisluvut:=TSatunnaisluvut.Create;
      Satunnaisluvut.AsetaMaara(StrToInt(Edit1.Text));
      Satunnaisluvut.AsetaRajaArvot(1,200);
      sl:=TStringList.Create;
      Satunnaisluvut.ArvoLuvut;
      Satunnaisluvut.LueArvotut(sl);
      ListBox1.Items.AddStrings(sl);
      FreeAndNil(sl);
      FreeAndNil(Satunnaisluvut);
      end;

      procedure TForm1.Button2Click(Sender: TObject);
      var
      i:integer;
      begin
      i:= ListBox1.Count-1 ;
      while i >= 0 do
      begin
      if ListBox1.Selected[i] then
      begin
      EiSallitut.Add(ListBox1.Items[i]);
      ListBox1.Items.Delete(i);
      end;
      dec(i);
      end;
      Memo1.Lines.Assign(EiSallitut);
      end;

      procedure TForm1.Button3Click(Sender: TObject);
      var
      kpl:integer;
      Satunnaisluvut:TSatunnaisluvut;
      sl:TStringList;
      begin
      Satunnaisluvut:=TSatunnaisluvut.Create;
      kpl := StrToInt(Edit1.Text);
      kpl := kpl - ListBox1.Items.Count;
      Satunnaisluvut.AsetaMaara(kpl);
      Satunnaisluvut.AsetaRajaArvot(1,200);
      sl:=TStringList.Create;
      sl.AddStrings(ListBox1.Items);
      sl.AddStrings(EiSallitut);
      Satunnaisluvut.AsetaKielletytArvot(sl);
      Satunnaisluvut.ArvoLuvut;
      Satunnaisluvut.LueArvotut(sl);
      ListBox1.Items.AddStrings(sl);
      FreeAndNil(sl);
      FreeAndNil(Satunnaisluvut);
      end;

      procedure TForm1.FormCreate(Sender: TObject);
      begin
      Randomize;
      EiSallitut:=TStringList.Create;
      end;

      procedure TForm1.FormDestroy(Sender: TObject);
      begin
      FreeAndNil(EiSallitut);
      end;



      { TSatunnaisluvut }

      function TSatunnaisluvut.OnkoKielletty(arvo: string): boolean;
      var
      oli_kielletty:boolean;
      i :integer;
      begin
      oli_kielletty := false;
      for i:= 0 to FKielletytArvot.Count-1 do
      if arvo = FKielletytArvot[i] then oli_kielletty := true;
      result := oli_kielletty;
      end;

      constructor TSatunnaisluvut.Create;
      begin
      FKielletytArvot:=TStringList.Create;
      FSaadutArvot:=TStringList.Create;
      FKielletytArvot.Sorted:=True;
      end;

      procedure TSatunnaisluvut.AsetaKielletytArvot(const ASl: TStringList);
      begin
      FKielletytArvot.Assign(ASl);
      end;

      procedure TSatunnaisluvut.AsetaMaara(kpl: integer);
      begin
      FKPl:=kpl;
      end;

      • Uuppi

        :D Vieläkin oli ongelmia uusien lukujen arvonnassa, tuli silti samoja. Tällä tavalla saan sen vihdoin toimimaan :) Mitä hyötyä tosta .sorted arvosta muuten on?


      • yhdessä oli merkitystä
        Uuppi kirjoitti:

        :D Vieläkin oli ongelmia uusien lukujen arvonnassa, tuli silti samoja. Tällä tavalla saan sen vihdoin toimimaan :) Mitä hyötyä tosta .sorted arvosta muuten on?

        Tuossa "Samojen arvojen estäminen" -viestissä
        sillä oli merkitystä (samat arvot tulivat vierekkäiksi jolloin on helppo löytää
        samat arvot).

        Mutta tässä missä kysyt sillä ei taida olla merkitystä (Koodihan voi olla
        otettu jostain isommasta kokonaisuudesta mutta sitä ei ole tuotu esille)


      • Delphiguru
        yhdessä oli merkitystä kirjoitti:

        Tuossa "Samojen arvojen estäminen" -viestissä
        sillä oli merkitystä (samat arvot tulivat vierekkäiksi jolloin on helppo löytää
        samat arvot).

        Mutta tässä missä kysyt sillä ei taida olla merkitystä (Koodihan voi olla
        otettu jostain isommasta kokonaisuudesta mutta sitä ei ole tuotu esille)

        1. TStringlist.Sorted:

        tästä ON hyötyä, tietyissä tapauksissa...

        eli:

        SL.Sorted := True;

        tämän jälkeen voit:

        SL.Duplicates := dupIgnore;

        tällöin voit yksinkertaisesti:

        N := SL.add(jotakin);

        jos merkkijono jotakin ON jo listassa, niin tuo ei tee mitään, muuten se lisätään listaan.

        Tuossa N saa arvokseen indeksin, johon jotakin lisättiin, tai -1 jos sitä EI lisätty.

        mutta, onhan toinenkin tapa:

        1. Tee merkkijono, jossa on halutut arvot, siis näin:

        St1 := St1 char(arvo);

        huomaa: Delphi2009:ssä arvo voi olla 0..65535, mutta vanhemmissa delpheissä arvon on oltava välillä 0..255.

        sitten voit:

        N := Random(length(St1)) 1;

        Merkki := St1[N];

        system.delete(St1,N,1); // estää saman arvon uudelleenkäytön

        ja satunnaislukusi:

        char(SLuku) := merkki;

        Tämä taktiikka hyödyntää merkkijonoa toimii siis kaikissa Delpheissä, jos satunnaislukusi ovat välillä 0..255, mutta jos käytät Delphi2009:ää, niin arvot 0..65535 ovat sallittuja.

        Ero johtuu tästä:

        sz := sizeOf(char);

        Delphi2009:ssä sz=2, aiemmissa Delpheissä sz=1; tämä johtuu siitä, että merkkijonoissa on siirrytty unicode -aikaan (Delphi2009)

        Jos vanhemmissa Delpheissä lukualue 0..255 ei riitä, löytyy 2 vaihtoehtoa:

        a) käytä WideChar ja WideString -tyyppejä

        TAI

        b) älä käytä STRINGejä, vaan dynaamisia taulukoita:

        var

        Arvot : Array of Integer;

        begin

        SetLength(Arvot, 1000);

        // täytä taulukko Arvot[0..999] 1000:lla haluamallasi luvulla, jotka toimivat satunnaislukuna (älä käytä tähän randomia !)

        system.delete pitäisi toimia myös dynaamisiin taulukoihin kuten merkkijonoihin, eli:

        system.delete(Arvot,N,1);

        tuo EI kuitenkaan toimi, jos olet määritellyt taulukkosi staattiseksi, sii snäin:

        var

        Arvot : Array[0..999] of Integer;

        SetLength kun toimii vain merkkijonoihin ja dynaamisiin taulukoihin mutta EI staattisiin taulukoihin.


    Ketjusta on poistettu 0 sääntöjenvastaista viestiä.

    Luetuimmat keskustelut

    1. Tollokin tajuaa että Timo Vornanen

      oli joutunut äärimmäiseen tilanteeseen ampuessaa yhden laukauksen katuun. Ei poliisi tee tuollaista hetken mielijohteest
      Maailman menoa
      583
      4252
    2. Istuva kansanedustaja epäiltynä pahoinpitelystä ja ampuma-aserikoksesta

      Seiskan tietojen mukaan Timo Vornanen on epäiltynä pahoinpitelystä ja ampuma-aserikoksesta eikä kenellekään taatusti tul
      Maailman menoa
      468
      3479
    3. Timo Vornanen kilahti

      Mikähän sille kansanedustajalle polisiisi miehelle on noin pahasti mennyt hermot , että tulevaisuudensa pilasi totaalise
      Kotka
      144
      3126
    4. Pullonpalautusjärjestelmä muuttuu - paluu menneisyyteen

      EU suuressa viisaudessaan on päättänyt, että pulloja pitää kierrättää. Jos oikein ymmärsin, nykyisen järjestelmänmme ti
      Maailman menoa
      166
      2407
    5. Sininen farmari - Ford Focus- YFB-842 on poliisilta kadoksissa Kauhajärvellä

      https://alibi.fi/uutiset/poliisilta-poikkeuksellinen-vihjepyynto-autossa-oleva-henkilo-on-avuntarpeessa/?shared=29255-2d
      Lapua
      8
      2260
    6. 235
      1748
    7. Onko oikeudenmukaista? Yhdellä taholla yllättävä valta-asema Tähdet, tähdet -voittajan valinnassa!

      Näinpä, onko sinusta tämä oikein? Viime jaksossakin voittaja selvisi vain yhden äänen erolla ja tänä sunnuntaina ensimm
      Tv-sarjat
      23
      1437
    8. No kerros nyt nainen

      Kumpi mielestäsi oli se joka väärinkäsitti kaiken? Nyt voi olla jo rehellinen kun koko tilanne on jo lähes haihtunut.
      Ikävä
      100
      1339
    9. Persukansanedustaja Timo Vornanen ammuskellut Helsingissä

      Poliisi siviiliammatiltaan, luvallinen ase mukana baarissa tällä hemmetin valopääpersulla. Meni eduskunnasta suoraan baa
      Haapavesi
      95
      1320
    10. Nainen, mietit miten minä jaksan

      En voi hyvin. Nykyään elämäni on lähinnä selviytymistä tunnista ja päivästä toiseen. Usein tulee epävarma olo, että mite
      Ikävä
      89
      1120
    Aihe