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 :)
Tarvitsen Apua!
13
693
Vastaukset
- 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
Miehille kysymys
Onko näin, että jos miestä kiinnostaa tarpeeksi niin hän kyllä ottaa vaikka riskin pakeista ja osoittaa sen kiinnostukse1323787- 851885
Olen tosi outo....
Päättelen palstajuttujen perusteella mitä mieltä minun kaipauksen kohde minusta on. Joskus kuvittelen tänne selkeitä tap151731Haluaisin jo
Myöntää nämä tunteet sinulle face to face. En uskalla vain nolata itseäni enää. Enkä pysty elämäänkin näiden kanssa jos541402Ylen uutiset Haapaveden yt:stä.
Olipas kamalaa luettavaa kaupungin irtisanomisista. Työttömiä lisää 10 tai enempikin( Mieluskylän opettajat). Muuttavat1231264VENÄJÄ muuttanut tänään ydinasetroktiinia
Venäjän presidentti Vladimir Putin hyväksyi tiistaina päivitetyn ydinasedoktriinin, kertoo uutistoimisto Reuters. Sen mu951251Kotkalainen Demari Riku Pirinen vangittu Saksassa lapsipornosta
https://www.kymensanomat.fi/paikalliset/8081054 Kotkalainen Demari Riku Pirinen vangittu Saksassa lapsipornon hallussapi351209- 691134
- 681014
Hommaatko kinkkua jouluksi?
Itse tein pakastimeen n. 3Kg:n murekkeen sienillä ja juustokuorrutuksella. Voihan se olla, että jonkun pienen, valmiin k102985