In rete http://www.elegio.it/fortran/sudoku.html
Il gioco del SUDOKU
L'input è costituito da un file html qualsiasi in cui ci siano almeno 9 righe contenenti ciascuna, solo 9 numeri di una cifra (ossia in tutto una tabella di SUDOKU). Il programma scarta automaticamente le righe in cui ci sia un carattere delimitatore di marca (< oppure >) e quelle che non terminano con una cifra. Il programma potrebbe accettare per errore, una riga senza marche ma con caratteri alfanumerici mescolati e con l'ultimo carattere numerico. Lo scrivere un input sotto form di file HTML è un modo per poter documentare bene l'input stesso. Basta comunque stare attenti di non far cadere in errore il programma (ad esempio mettendo un piccolo commento su ogni riga, tipo <!-- -->, oppure badando di non far finire nessuna riga con una cifra). La tabella 9*9 del SUDOKU va data usando lo 0 come segnalatore di nessun dato. Ad esempio questa è una tabella valida: 0 0 0 7 0 0 4 0 0 0 3 0 0 9 0 0 2 0 4 0 0 0 0 5 0 0 0 0 0 8 0 0 0 0 0 5 0 9 0 0 3 0 0 7 0 6 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 1 0 7 0 0 2 0 0 9 0 0 0 5 0 0 8 0 0 0 Il risultato viene scritto non usando le cifre ma le lettere della parola Esperanto. Ossia: E==1, s==2, p==3, e==4, r==5, a==6, n==7, t==8, o==9. Si tratta di una concessione ad una mia fissazione o meglio, lucida indicazione della Via, Verità e Vita. Chiunque però può operare la trasformazione inversa, magari per controllare se la sua soluzione coincide con quella data dal Corriere della Sera per i Sudoku del giorno prima. Se non altro questo programma serve ad evidenziare cosa è possibile fare programmando in Fortran moderno ossia in Fortran 95. Il sorgente è compilabile usando il compilatore gratuito della Silverfrost (estensione .f95).http://www.silverfrost.com/ Attenzione: l'eseguibile Silverfrost è piccolo ma richiede la loro DLL ottenibile scaricando il loro compilatore ed istallandoselo. Altro compilatore gratuito che ho applicato qui:http://www.g95.org/ Le procedure bat applicate ai file con estensione .f03 creano l'eseguibile a.exe Io ho usato anche il compilatore della Intel (estensione .f90).http://en.wikipedia.org/wiki/Intel_Fortran_Compiler
- http://en.wikipedia.org/wiki/G95
- http://en.wikipedia.org/wiki/Coarray_Fortran
- http://www.fortran.com/F/
- http://www.rice.edu/ ... dove ci si interessa ... e si inventano... le CoArray ... http://caf.rice.edu/index.html
To address these shortcomings, Rice University is developing a clean-slate redesign of the Coarray Fortran programming model. Rice's new design for Coarray Fortran, which we call Coarray Fortran 2.0, is an expressive set of coarray-based extensions to Fortran designed to provide a productive parallel programming model. Compared to the emerging Fortran 2008, Rice's new coarray-based language extensions include some additional features:- http://www.fortran.com/F/compilers.html
- http://www.fortran.com/F/ex_big_integers.html
In Italia vendono compilatori Fortran, ad esempio: Attualmente i compilatori Fortran più moderni aderiscono allo standard F95 ma è stato ratificato lo standard F2003 che consente la piena programmazione ad oggetti.Programmare ad oggetti però non è sempre facilissimo per cui ci sono validi motivi per usare versioni Fortran più semplici ma comunque ottimali per il calcolo scientifico.
! sudoku.f90 module miosudoku implicit none character(len=*),parameter::versione="SUDOKU - ESPERANTESCO : gpbottoni@gmail.com [V20050717]" type,public:: passo integer::esaminato integer,dimension(9,9)::stato end type passo type,public::proposta integer:: r,c,valore end type proposta type(proposta)::forse type(passo),dimension(90)::stati integer::fase,konto,pausamax,tentativi character(len=1),dimension(0:9),parameter::es=(/ ".","E","s","p",& "e","r","a","n","t","o" /), & sx=(/ " ","^","^","^","^","^","^","^","^","^"/) ! contains ! subroutine lettura(s) type(passo),intent(out)::s character(len=256)::nomefile,riga integer::nf,j,nstato,m,r logical::esiste ! write(*,*)"Digita il nome del file da cui vuoi leggere ",& "la situazione iniziale..." write(*,*)"Attenzione: se il nome finisce con una cifra viene aggiunta ",& "l'estensione .html" s%stato(:,:)=0 do j=1,3 read(*,"(1a)") nomefile nf=len_trim(nomefile) if(1>nf )exit if(ichar(nomefile(nf:nf))>47.and.58>ichar(nomefile(nf:nf)))then nomefile=nomefile(1:nf)//".html" nf=len_trim(nomefile) end if write(*,*)"Cerco ",nomefile(1:nf) inquire(file=nomefile(1:nf),exist=esiste) if(esiste) then open(12,file=nomefile(1:nf),action="read",status="old",iostat=nstato) if(nstato/=0) then write(*,*)"Fallisce apertura di ",nomefile(1:nf) write(*,*)"Invia..." read(*,*) exit end if write(*,*)"Apertura riuscita" r=0 tutto : do read(12,"(1a)",iostat=nstato) riga if(nstato/=0) then write(*,*)"Lettura troncata" close(12) return end if m=scan(riga,char(60)) if(m>0) cycle tutto m=scan(riga,char(62)) if(m>0) cycle tutto m=len_trim(riga) if(2>m) cycle tutto if(48>ichar(riga(m:m)).or.ichar(riga(m:m))>57) cycle tutto r=r+1 read(riga,*,iostat=nstato) s%stato(r,:) if(nstato/=0) then write(*,*)"Una riga non valida. Tronco la lettura" close(12) return end if s%stato(r,:)=modulo(s%stato(r,:),10) write(*,"(20x,3(1x,1a,1x),2x,3(1x,1a,1x),2x,3(1x,1a,1x))") es(s%stato(r,:)) write(*,"(20x,3(1x,1a,1x),2x,3(1x,1a,1x),2x,3(1x,1a,1x))") sx(s%stato(r,:)) if(r.eq.3.or.r.eq.6) write(*,*)" " if(r>=9) then close(12) return end if end do tutto else write(*,*)"Non trovo ",nomefile(1:nf) write(*,*)"...altro tentativo..." end if end do return end subroutine lettura ! subroutine imposto() integer::j do j=1,size(stati,1) stati(j)%stato(:,:)=0 end do stati(:)%esaminato=0 fase=0 tentativi=0 return end subroutine imposto ! function achepunto(situazione)result(tento) type(passo),intent(in)::situazione type(proposta)::tento integer::j,k,jj,kk,p,jp,kp tento%r=0 tento%c=0 tento%valore=0 if(situazione%esaminato>8) then return end if do jj=0,6,3 do kk=0,6,3 do j=jj+1,jj+3 do k=kk+1,kk+3 if(situazione%stato(j,k)==0) then tento%r=j tento%c=k unico: do p=situazione%esaminato+1,9 do jp=jj+1,jj+3 do kp=kk+1,kk+3 if(situazione%stato(jp,kp)==p) then cycle unico end if end do end do tento%valore=p exit unico end do unico if(tento%valore==0) then tentativi=tentativi+1 ! write(*,*)"tento%valore nullo!" end if return end if end do end do end do end do return end function achepunto ! function baco(s,avviso,nf)result(bah) logical::bah type(passo),intent(in)::s integer,optional,intent(in)::nf character(len=*),intent(in)::avviso integer::j,nfu bah=.false. if(avviso(1:1)=="!") konto=0 if(modulo(konto,pausamax)/=0) return if(present(nf)) then nfu=nf else nfu=6 end if write(nfu,*) avviso do j=1,9 write(nfu,"(20x,3(1x,1a,1x),2x,3(1x,1a,1x),2x,3(1x,1a,1x))") es(s%stato(j,:)) write(nfu,"(20x,3(1x,1a,1x),2x,3(1x,1a,1x),2x,3(1x,1a,1x))") sx(stati(1)%stato(j,:)) if(j.eq.3.or.j.eq.6) write(nfu,*)" " end do j=0 if(nfu==6) then write(*,*) konto, "Un invio per continuare..." ! read(*,*) j read(*,*) end if if(j>0) bah=.true. return end function baco ! function ammesso(situazione,tento)result(siono) type(passo),intent(in)::situazione type(proposta),intent(in)::tento logical::siono integer::j,k,r,c if ((tento%r>9).or.(1>tento%r).or.(tento%c>9).or.(1>tento%c) & .or.(tento%valore>9).or.(1>tento%valore)) then siono=.false. return end if r=tento%r c=tento%c ! write(*,*)"Valuto",r,c,tento%valore if(situazione%stato(r,c)/=0) then siono=.false. return end if ! Prova nel suo cellone do j=1+3*((r-1)/3),3+3*((r-1)/3) do k=1+3*((c-1)/3),3+3*((c-1)/3) if(situazione%stato(j,k)==tento%valore) then ! write(*,*)tento%valore," male:, anche in",j,k siono=.false. return end if end do end do ! write(*,*)"Nel cellone va bene" do j=1,9 if(situazione%stato(r,j)==tento%valore) then siono=.false. ! write(*,*)tento%valore,": Male: anche in",r,j return end if end do ! do j=1,9 if(situazione%stato(j,c)==tento%valore) then siono=.false. ! write(*,*)tento%valore,": Male: anche in",j,c return end if end do siono=.true. ! write(*,*)"accettabile" return end function ammesso ! function fatti(situazione)result(n) type(passo),intent(in)::situazione integer::n integer::j,k n=0 do j=1,9 do k=1,9 if(situazione%stato(j,k)/=0) n=n+1 end do end do return end function fatti ! end module miosudoku program sudoku use miosudoku implicit none integer::nunc,j,jp logical::decido character(len=60)::avviso,path call imposto() write(*,*)"Il gioco del SUDOKU risolto usando, in luogo delle cifre," write(*,*)"le nove lettere della LUMINOSA parola: Esperanto" write(*,*) write(*,*) versione write(*,*) write(*,*)"Dimmi ogni quanti passi deve fare una sosta" read(*,*) pausamax if(1>pausamax) pausamax=2000000000 konto=0 nunc=1 call lettura(stati(nunc)) write(*,*)"Un invio per iniziare..." read(*,*) ciclo:do konto=konto+1 fase=fatti(stati(nunc)) if(fase>=81) exit ciclo forse=achepunto(stati(nunc)) if(forse%valore==0) then if(nunc>1) then nunc=nunc-1 ! ! write(*,*)"Deve arretrare a",nunc cycle ciclo else write(*,*)"Non riesce ad andare avanti" read(*,*) exit ciclo end if end if if(ammesso(stati(nunc),forse)) then stati(nunc)%esaminato=forse%valore nunc=nunc+1 stati(nunc)%stato=stati(nunc-1)%stato stati(nunc)%stato(forse%r,forse%c)=forse%valore stati(nunc)%esaminato=0 if(baco(stati(nunc),"Ora tenta questo")) then write(*,*)"Digita t se vuoi veramente terminare" decido=.false. read(*,*) decido if(decido) exit ciclo end if else stati(nunc)%esaminato=forse%valore end if end do ciclo write(*,*) konto konto=0 decido=baco(stati(nunc),"Situazione finale") write(*,*)"Digita 1 per salvare i passaggi per arrivare al risultato:" read(*,*) konto if(konto==1) then write(*,*)"Digita il path (quello locale== .",char(92)," )" read(*,"(1a)")path jp=len_trim(path) if(1>jp) then path="."//char(92) jp=len_trim(path) end if open(13,file=path(1:jp)//"sudoku-risultato.html",action="write",status="replace") write(13,*)char(60),"html>",char(60),"body>Sudoku Esperanto",char(60),"pre>" konto=0 do j=1,nunc write(avviso,"(1x,1a,i4)")"--- Passo",j decido=baco(stati(j),avviso,13) end do write(13,*)char(60),"/pre>",char(60),"/body>",char(60),"/html>" close(13) write(*,*)"Ha salvato sul file ",path(1:jp),"sudoku-risultato.html" end if write(*,*)"Ha finito (Fecit: http://mail.cilea.it/~bottoni/)" read(*,*) stop end program sudoku !