Newsgroup: it.comp.lang.delphi
Titolo: programma a generazione casuale

Ho la necessità di scrivere un programma (ho Delphi 3 Pro originale, 
ovviamente)per creare dei turni a caso di 11 persone.
Mi spiego meglio: Nell'arco dell'anno, 11 persone devono fare dei turni 
settimanali ed ogni turno è composto da 2 persone, che in quella 
settimana devono prolungare l'orario di lavoro il martedì ed il giovedì. 
In più, queste 11 persone devono assicurare il turno del sabato. Quindi, 
ogni 11 settimane,a rotazione, ognuno deve fare anche il turno del sabato.
Non so neanche da dove cominciare questo programma che dovrebbe generare 
CASUALMENTE questi turni.
Se qualcuno è così gentile da rispondermi, dovrebbe dirmi da dove 
iniziare,con esempi, considerando che uso BDE con Delphi 3 Pro e che 
sono "programmatore" per diletto.
Grazie infinite.

:

In realta` non ha proprio niente a che vedere con delphi, percio` siamo
proprio OT... Comunque un suggerimento al volo posso dartelo
facilmente...
Naturalmente non tengo conto di vincoli che potrebbero risultare
importanti, come periodi di ferie, festivita`, il favorire o l'evitare
particolari accoppiamenti o cose cosi`... ma son tutte cose che solo tu
puoi sapere...
Una soluzione facile e immediata la ottieni creando una tabella come la
seguente:
 settimana | martedi` | giovedi` | sabato
------------------------------------------
    1a     |    AB    |    CD    |   EF
    2a     |    GH    |    IL    |   MA
    3a     |    BC    |    DE    |   FG
    4a     |    HI    |    LM    |   AB
    5a     |    CD    |    EF    |   GH
    6a     |    IL    |    MA    |   BC
    7a     |    DE    |    FG    |   HI
    8a     |    LM    |    AB    |   CD
    9a     |    EF    |    GH    |   IL
    10a    |    MA    |    BC    |   DE
    11a    |    FG    |    HI    |   LM
che costruisci facilmente mettendo di seguito le undici lettere da A a
M, riunite a coppie, fino ad esaurire il periodo [funziona anche nel
caso che al sabato il turno lo faccia una persona sola... ma non mi era
chiaro, percio` l'ho costruita cosi`... e` comunque immediato
costruirne un'altra con lo stesso sistema] delle undici settimane.
Ora non resta altro che assegnare casualmente alle undici persone le
undici lettere [non occorrerebbe nemmeno un programma, basterebbero i
numeri della tombola :-)] all'inizio di ogni nuovo periodo di undici
settimane [o anche farlo in un botto solo per i prossimi mesi o anni...
non saprei le vostre esigenze] e magari stamparlo con date e nomi al
posto delle lettere e del progressivo delle settimane. :-)
Questo garantisce casualita` e pure una certa uniformita` nei turni
[che pero` potrebbe essere non desiderata... ma anche questo solo tu
puoi saperlo].
Tradurlo in un programmino dovrebbe risultarti abbastanza facile...
sempreche` io abbia capito il problema...
Ciao ciao
Claudio

// Get an integer random number in the range 1..100
  for i := 1 to 5 do
  begin
    int := 1 + Random(100);    // The 100 value gives a range 0..99
    ShowMessage('int = '+IntToStr(int));
  end;
--- posted by geoForum on 
http://www.delphiedintorni.it

 
Hai capito perfettamente il mo problema. Ma dovresti dirmi qualcosa in 
più, se puoi, tipo l'applicativo da usare e, se è Delphi, farmi un esempio.
Grazie comunque per la pronta e cortese risposta.

 
tutto 	qui? Un esempio pochino pochino più completo lo potresti fare? 
Grazie.

 Grazie comunque per la pronta e cortese risposta.
Gli e` che dipende da molte cose... da dove prendi i dati di partenza e
la forma che hanno... qual e` l'output che preferisci...
Io posso farti un esempio che crea in output un file di testo molto
spartano, ma facilmente importabile in un foglio di calcolo, a partire
da una data qualsiasi... Non so se puo` esserti davvero utile, ma vedi
tu...
Diciamo che hai gia` i nomi dei turnisti inseriti in un vettore di
stringhe... per l'esempio lo inserisco come costante, ma non e`
importante...
const
  Turnisti: array [0..10] of string = ('Aldo', 'Berta', 'Carlo',
    'Denise', 'Ermanno', 'Federica', 'Giacomo', 'Helga', 'Ivo',
    'Livia', 'Mario');
E questa e` la procedura di base:
procedure CreaFilePeriodo(nomefile: string; DataIniziale: TDate);
var
  indice, j, c: Integer;
  // Assegnati conterra` i nomi dei turnisti assegnati con
  // un'estrazione casuale
  Assegnati: array [0..10] of string;
  Data: TDate;
  FileTesto: TextFile;
  Nomi: TStringList;
const
  separatore = '; ';
  // Questa e` una funzione interna alla procedura per ottenere
  // comodamente il prossimo turnista assegnato
  function successivo: string;
  begin
    indice := (indice + 1) mod 11;
    successivo := Assegnati[indice];
  end;
begin
  // Va inizializzato il generatore di numeri casuali da qualche
  // parte...
  // Solo come esempio io lo faccio qui...
  Randomize;
  Data := DataIniziale;
  // Ora mi posiziono sul primo martedi` del periodo elaborato...
  // questo per semplicita`, ma si puo` fare in molti altri modi
  // probabilmente piu` consoni...
  while DayOfWeek(Data) <> 3 do // 3 e` un martedi`
  begin
    Data := Data + 1;
  end;
  // Ora preparo il vettore di stringhe Assegnati in modo che contenga
  // un riordinamento casuale del vettore di stringhe Turnisti...
  // Usero` Nomi, come contenitore temporaneo...
  Nomi := TStringList.Create; 
  for j := 0 to 10 do
  begin
    Nomi.Add(Turnisti[j]);
  end;
  for j := 0 to 10 do
  begin
    c := Random(10 - j);
    Assegnati[j] := Nomi.Strings[c];
    Nomi.Delete(c);
  end;
  Nomi.Free;;
  // Qua inizializzo la variabile indice che punta al turnista
  // assegnato...
  indice := -1;
  // Elaborazione del file di testo che conterra` i turni assegnati...
  AssignFile(FileTesto, nomefile);
  Rewrite(FileTesto);
  for j := 0 to 10 do
  begin
    // martedi`
    WriteLn(FileTesto, FormatDateTime('DDDD, D MMMM YYYY', Data),
      separatore, successivo, separatore, successivo);
    // giovedi`
    Data := Data + 2;
    WriteLn(FileTesto, FormatDateTime('DDDD, D MMMM YYYY', Data),
      separatore, successivo, separatore, successivo);
    // sabato
    Data := Data + 2;
    WriteLn(FileTesto, FormatDateTime('DDDD, D MMMM YYYY', Data),
      separatore, successivo, separatore, successivo);
    // e ora mi sposto al prossimo martedi`
    Data := Data + 3;
  end;
  CloseFile(FileTesto);
end;
Puoi provarlo facilmente copiandolo direttamente in Delphi 3... ma
ovviamente va sistemato per le tue esigenze... e sicuramente
migliorato, se serve...
Ciao ciao
Claudio

 
Grazie, lo proverò e ti farò sapere. Gentilissimo. Ciao

 Grazie ancora per la tua pazienza.
Ohi, temo ci sia qualche problema... Vabbe`, credo che si possa
risolvere... :-)
Apri un nuovo progetto... inserisci un bottone standard nella form
principale del progetto... doppio click sul bottone [cosi` ti crea in
automatico l'evento onclick]... Copia la procedura che ti ho dato e la
dichiarazione della costante Turnisti *prima* di quella nuova procedura
per l'onclick... ed ora scrivi questo in quella procedura:
CreaFilePeriodo('prova.txt', Date);
[Date, da non confondere con Data, passa la data attuale alla
procedura]
Salva il progetto da qualche parte, prima, poi avvialo e clicca il
bottone... nella directory del progetto dovrebbe comparire il file
prova.txt che contiene l'output... aprilo e vedi se ti puo` andare
bene...
Tuttavia, quanta pratica hai con Delphi? se fosse davvero poca temo che
ci farai altrettanto poco... Niente di male, eh! pero` forse dovresti
provare strumenti diversi...
Ciao ciao
Claudio

 ci farai altrettanto poco...
Te l'ho detto: non sono un programmatore, ma mi piace creare qualche 
applicazione e, anche se zoppicando, ci riesco sempre.
  Niente di male, eh!
Nel senso che non ci devo neanche provare, per quel poco che so di Delphi?
  pero` forse dovresti  provare strumenti diversi...
Quali?
Comunque ancora grazie per la tua grande disponibilità.

 Comunque ancora grazie per la tua grande disponibilità.
Ah, figurati! e` stata un'occasione, per me, per provare lazarus.
Ciao ciao
Claudio

 
Un esempio sarebbe gradito, se proprio non ti secca.
Comunque, grazie. Mi hai già dato una gran bella mano.
-- 
Saluti da
Mazinga
-----------------
caso...@hotmail.com

 Un esempio sarebbe gradito, se proprio non ti secca.
Anche qua le possibilita` sono troppe... Te ne faccio uno basato sulla
procedura che gia` ti avevo dato, anche se non va bene...
Metti una StringGrid nella Form principale... anche se e` sempre meglio
rinominare un oggetto non appena lo inserisci, lasciagli pure il nome
che ti mette di default, ovvero StringGrid1... La prima cosa da fare e`
dimensionarla per i tuoi scopi... nell'esempio dovra` avere quattro
colonne e trentaquattro righe... quindi imposti a 4 la proprieta`
ColCount e a 34 la proprieta` RowCount... metti poi a 0 la proprieta`
FixedCols [ma dovresti studiarti un po' tutte le sue propieta` per
avere l'output che preferisci... dai un'occhiata in particolare alla
proprieta` Options]... giusto per esempio, cambia a AllLeft la
proprieta` Align, imposta a 99 la proprieta` DefaultColWidth e a 420 la
Width... ma a parte il dimensionamento non sono cambi importanti.
Ora, alla procedura CreaFilePeriodo che avevi provato, sostituisci la
parte...
  // Elaborazione del file di testo che conterra` i turni assegnati...
  AssignFile(FileTesto, nomefile);
  Rewrite(FileTesto);
  for j := 0 to 10 do
[fino a]
  end;
  CloseFile(FileTesto);
Con queste altre istruzioni [che sono, come vedi, molto simili]:
  // Elaborazione del file di testo che conterra` i turni assegnati...
 
  // Intestazione:
  Form1.StringGrid1.Cells[0, 0] := 'Data';
  Form1.StringGrid1.Cells[1, 0] := 'Giorno';
  Form1.StringGrid1.Cells[2, 0] := '';
  Form1.StringGrid1.Cells[3, 0] := '';
 
  // Tabella:
  for j := 0 to 10 do
  begin
    // martedi`
    Form1.StringGrid1.Cells[0, 3*j+1] 
      := FormatDateTime('DD/MM/YYYY', Data);
    Form1.StringGrid1.Cells[1, 3*j+1] 
      := FormatDateTime('DDDD', Data);
    Form1.StringGrid1.Cells[2, 3*j+1] := successivo;
    Form1.StringGrid1.Cells[3, 3*j+1] := successivo;
    // giovedi`
    Data := Data + 2;
    Form1.StringGrid1.Cells[0, 3*j+2] 
      := FormatDateTime('DD/MM/YYYY', Data);
    Form1.StringGrid1.Cells[1, 3*j+2] 
      := FormatDateTime('DDDD', Data);
    Form1.StringGrid1.Cells[2, 3*j+2] := successivo;
    Form1.StringGrid1.Cells[3, 3*j+2] := successivo;
    // sabato
    Data := Data + 2;
    Form1.StringGrid1.Cells[0, 3*j+3] 
      := FormatDateTime('DD/MM/YYYY', Data);
    Form1.StringGrid1.Cells[1, 3*j+3] 
      := FormatDateTime('DDDD', Data);
    Form1.StringGrid1.Cells[2, 3*j+3] := successivo;
    Form1.StringGrid1.Cells[3, 3*j+3] := successivo;
    // prossimo martedi`
    Data := Data + 3;
  end;
Da notare che non avendo definito la procedura CreaFilePeriodo come
interna alla Form TForm1, quando ti riferisci alla StringGrid1 devi
usare l'identificazione completa Form1.StringGrid1 [ma se hai
rinominato il nome della Form, dovrai intervenire di conseguenza].
E` solo un esempio... puoi farlo in mille altri modi...
Una cosa che di solito capita con questi oggetti e` il voler allineare
il testo all'interno delle celle in modo che sia centrato sia
orrizzontalmente che verticalmente... nelle stringgrid di Delphi 3 non
c'era una proprieta` che gestisse la cosa [a differenza di versioni
piu` recenti con la proprieta` Columns]... ma ottenerlo non e` troppo
complicato... Devi scrivere l'evento OnDrawCell [nella scheda Events
delle proprieta` della StringGrid, fai doppio click nell'evento
OnDrawCell]... dovresti scrivere qualcosa di simile:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
var
  s: TSize;
begin
  // Puoi anche testare Row = 0, invece di gdFixed... almeno in questo
  // esempio...
  // questo serve solo per ottenere i titoli in grassetto...
  if gdFixed in State then
    StringGrid1.Canvas.Font.Style := [fsBold]
  else
    StringGrid1.Canvas.Font.Style := [];
  // Questo invece centra il testo nella cella... e lo fa con tutte le
  // celle...
  s := StringGrid1.Canvas.TextExtent(StringGrid1.Cells[Col, Row]);
  StringGrid1.Canvas.TextRect(Rect,
    Rect.Left + (Rect.Right - Rect.Left - 
s.cx
) div 2,
    Rect.Top + (Rect.Bottom - Rect.Top - 
s.cy
) div 2,
    StringGrid1.Cells[Col, Row]);
end;
Dovrei avvisarti di altre cose [ad esempio il DefaultDrawning], ma sono
troppe ed e` meglio se gli dai un'occhiata tu... per farsi un'idea
dovrebbe bastare cosi`...
Ciao ciao
Claudio

   end;
Ah, questa parte conteneva un errore...
Dovrebbe essere:
    c := Random(11 - j);
altrimenti l'ultimo turnista mantiene sempre la stessa posizione
relativa, non potendo mai essere scelto...
Ciao ciao
Claudio

 altrimenti l'ultimo turnista mantiene sempre la stessa posizione
Grazie, sono riuscito a fare quello che mi occorreva, modificandolo in 
qualche parte. Grazie, sei stato grandissimo.
Ti chiedo l'ultimo sforzo, se possibile: la procedura per stampare la 
stringgrid. Con quickReport, con i database, lo so fare benissimo, ma 
con le string proprio non lo so. E' possibile? Grazie ancora un mondo. 
Mi hai risolto un grandissimo problema.


Coso ha scritto:

Ho trovato questa procedura per stampare, ma non mi stampa la prima 
colonna, quella della data:
procedure TForm1.BitBtn3Click(Sender: TObject);
  //procedure PrintGrid(StringGrid1: TStringGrid);
var
   X1, X2: Integer;
   Y1, Y2: Integer;
   TmpI: Integer;
   F: Integer;
   TR: TRect;
begin
   //Printer.Title := sTitle;
   Printer.BeginDoc;
   Printer.Canvas.Pen.Color  := 0;
 
Printer.Canvas.Font.Name
  := 'Times New Roman';
   Printer.Canvas.Font.Size  := 12;
   Printer.Canvas.Font.Style := [fsBold, fsUnderline];
   //Printer.Canvas.TextOut(0, 100, Printer.Title);
   for F := 1 to stringGrid1.ColCount -1 do
   begin
     X1 := 0;
     for TmpI := 1 to (F - 1) do
       X1 := X1 + 5 * (stringGrid1.ColWidths[TmpI]);
     Y1 := 300;
     X2 := 0;
     for TmpI := 1 to F do
       X2 := X2 + 5 * (stringGrid1.ColWidths[TmpI]);
     Y2 := 450;
     TR := Rect(X1, Y1, X2 - 30, Y2);
     Printer.Canvas.Font.Style := [fsBold];
     Printer.Canvas.Font.Size := 12;
     Printer.Canvas.TextRect(TR, X1 + 50, 350, stringGrid1.Cells[F, 0]);
     Printer.Canvas.Font.Style := [];
     for TmpI := 1 to stringGrid1.RowCount - 1 do
     begin
       Y1 := 150 * TmpI + 300;
       Y2 := 150 * (TmpI + 1) + 300;
       TR := Rect(X1, Y1, X2 - 30, Y2);
       Printer.Canvas.TextRect(TR, X1 + 50, Y1 + 50, 
stringGrid1.Cells[F, TmpI]);
     end;
   end;
   Printer.EndDoc;
end;
perchč?????????????


    for F := 1 to stringGrid1.ColCount -1 do
... questo ciclo salta la prima colonna... Dovrebbe partire da 0, non
da 1... Per le righe e` diverso perche` la prima riga non contiene dati
ma intestazioni, quindi va trattato in maniera generalmente diversa...
Ciao ciao
Claudio

Coso ha scritto:

Fatto: adesso stampa anche la prima colonna con la data. Ancora grazie e 
Dio ti benedica per la tua grande pazienza. Te ne sono veramente grato.
