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
!