Tarvitsen Apua!

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 :)
13787
Äänestä

Muut lukivat myös

Vastaukset 13

Vanhimmat

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;

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

    Äänestä

  • 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ä.

    Äänestä

  • 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;

    Äänestä

  • 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 :

    Äänestä

  • 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.

    Äänestä

  • 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;

    Äänestä

  • 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.

    Äänestä

  • 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;

    Äänestä

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;

Äänestä
  • :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?

    Äänestä

  • 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)

    Äänestä

  • 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.

    Äänestä

Kommentoi aloitusta


Uuppi kirjoitti:

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 :)

Anonyymi
5000

Ilmoita asiaton sisältö

  • Sisältää materiaalia, joka on loukkaavaa, herjaavaa, rasistista, uhkailevaa tai ahdistelevaa.

  • Materiaali sisältää nimiä, yhteystietoja tai muita henkilökohtaisia tietoja. Julkisuuden henkilöistä, julkisissa viroissa toimivista ihmisistä sekä yritysten vastuuhenkilöistä saa keskustella työhön liittyen. Myös yksityiselämään liittyvistä asioista voi keskustella siltä osin, kuin niistä on julkisesti kerrottu.

  • Sisältää lapsille haitallista tai heiltä kiellettyä materiaalia. Seksuaalinen sisältö on sallittua aiheeseen tarkoitetuilla palstoilla, joiden ikäraja on 18 vuotta.

  • Lainvastaista sisältöä voi olla mm. yksityiselämää loukkaavan tiedon levitys, kiihottaminen kansanryhmää vastaan, laiton uhkaaminen, alaikäisiin liittyvä seksuaalinen sisältö/grooming, petokset, identiteettivarkaudet, kunnianloukkaukset ja tekijänoikeusrikkomukset.

  • Sisältö ei liity palstan tai keskusteluketjun aiheeseen.

  • Viesti ei ole suomea tai ruotsia (pl. International Forums), se sisältää mainontaa, se sisältää tekijänoikeuksin suojattua materiaalia, se on massapostitus tai jokin muu syy.

Jaa keskustelu