zenxv icon

Experiment 1 Rubiks Cube

zenxv | PRO | 08/11/19 05:20:45 AM UTC | 0 ⭐ | 11299 👁️ | Never ⏰ | []
Fortran |

42.31 KB

|

None

|

0 👍

/

0 👎

!  RUBIK.f90 
!
!  FUNCTIONS:
!   RUBIK      - Entry point of console application.
!
!
 
!****************************************************************************
!
!  PROGRAM: RUBIK
!
!
!****************************************************************************
 
module external_fcts
implicit none
 
integer  :: m, n, o
 
contains
 
    subroutine ToString(sequence_numbers, numbersToString)
 
        integer, dimension(:), intent(in)   :: sequence_numbers
        integer                             :: a, taille_sequence
        character, dimension(:),intent(out) :: numbersToString
        taille_sequence = size(sequence_numbers)
        
 
        do a = 1, taille_sequence
            select case(mod(sequence_numbers(a),6))
                case(0)
                    numbersToString(3*a-2) = 'F'
                case(1) 
                    numbersToString(3*a-2) = 'U'
                case(2) 
                    numbersToString(3*a-2) = 'R'
                case(3) 
                    numbersToString(3*a-2) = 'B'
                case(4) 
                    numbersToString(3*a-2) = 'D'
                case(5) 
                    numbersToString(3*a-2) = 'L'
            end select
            
            numbersToString(3*a-1) = ' '
            if (sequence_numbers(a)> 5) numbersToString(3*a-1) = '2'
            if (sequence_numbers(a)>11) numbersToString(3*a-1) = "'"
            numbersToString(3*a) = ' '
        end do
 
    end subroutine ToString
 
    subroutine ToNumbers(sequence_string, StringToNumbers)
        character, dimension(2), intent(in)     :: sequence_string
        integer, intent(out)                    :: StringToNumbers
        integer                                 :: a, b, taille_string
 
        do a=1, 2
            select case(sequence_string(a))
                case('F')
                    StringToNumbers = 0
                case('U')
                    StringToNumbers = 1
                case('R')
                    StringToNumbers = 2
                case('B')
                    StringToNumbers = 3
                case('D')
                    StringToNumbers = 4
                case('L')
                    StringToNumbers = 5
                case("2")
                    StringToNumbers = StringToNumbers+6
                case("'")
                    StringToNumbers = StringToNumbers+12
                !case default
                !   print*, 'Incorrect caracter. Exit and run the program again'
 
            end select
        end do
        !print*, StringToNumbers
 
    end subroutine ToNumbers
 
    function init(cube)
        integer, dimension(0:53), intent(in)  :: cube
        integer, dimension(0:53)              :: init
        integer                               :: indice = 0, temp = 0
        
        do m = 0, 5
            do n = 0, 8
            init(indice) = temp
            indice = indice+1
            end do
            temp = temp+1
        end do
 
    return
    end function init
 
 
    function do_move(cube_state, move)
        integer, dimension(0:53), intent(in) :: cube_state
        integer, dimension(0:53)             :: do_move, cube
        integer, intent(in)                  :: move
        integer                              :: repetition
        
        do_move = cube_state
        
        
        repetition = 0
        if(move > 5)   repetition = 1
        if(move > 11)  repetition = 2
        if(move > 17)  repetition = 3  !stupide, c'est un tour complet (juste pour test)
 
        do m = 0, repetition
        cube = do_move          
 
        !tourne les cubes de la face en question
        do_move = turn_face(do_move, mod(move,6))   
        
        !tourne ceux de la couronne
        select case(mod(move,6))
        case(0)
            do_move(15) = cube(53)
            do_move(16) = cube(50)
            do_move(17) = cube(47)
            do_move(18) = cube(15)
            do_move(21) = cube(16)
            do_move(24) = cube(17)
            do_move(36) = cube(24)
            do_move(37) = cube(21)
            do_move(38) = cube(18)
            do_move(47) = cube(36)
            do_move(50) = cube(37)
            do_move(53) = cube(38)
        case(1)
            do_move(0) = cube(18)
            do_move(1) = cube(19)
            do_move(2) = cube(20)
            do_move(18) = cube(27)
            do_move(19) = cube(28)
            do_move(20) = cube(29)
            do_move(27) = cube(45)
            do_move(28) = cube(46)
            do_move(29) = cube(47)
            do_move(45) = cube(0)
            do_move(46) = cube(1)
            do_move(47) = cube(2)
        case(2)
            do_move(2) = cube(38)
            do_move(5) = cube(41)
            do_move(8) = cube(44)
            do_move(11) = cube(2)
            do_move(14) = cube(5)
            do_move(17) = cube(8)
            do_move(27) = cube(17)
            do_move(30) = cube(14)
            do_move(33) = cube(11)
            do_move(38) = cube(33)
            do_move(41) = cube(30)
            do_move(44) = cube(27)
        case(3)
            do_move(9) = cube(20)
            do_move(10) = cube(23)
            do_move(11) = cube(26)
            do_move(20) = cube(44)
            do_move(23) = cube(43)
            do_move(26) = cube(42)
            do_move(42) = cube(45)
            do_move(43) = cube(48)
            do_move(44) = cube(51)
            do_move(45) = cube(11)
            do_move(48) = cube(10)
            do_move(51) = cube(9)
        case(4)
            do_move(6) = cube(51)
            do_move(7) = cube(52)
            do_move(8) = cube(53)
            do_move(24) = cube(6)
            do_move(25) = cube(7)
            do_move(26) = cube(8)
            do_move(33) = cube(24)
            do_move(34) = cube(25)
            do_move(35) = cube(26)
            do_move(51) = cube(33)
            do_move(52) = cube(34)
            do_move(53) = cube(35)
        case(5)
            do_move(0) = cube(9)
            do_move(3) = cube(12)
            do_move(6) = cube(15)
            do_move(9) = cube(35)
            do_move(12) = cube(32)
            do_move(15) = cube(29)
            do_move(29) = cube(42)
            do_move(32) = cube(39)
            do_move(35) = cube(36)
            do_move(36) = cube(0)
            do_move(39) = cube(3)
            do_move(42) = cube(6)
        case default
            print*, "move error"
        end select
 
        end do
        return
    end function do_move
 
    function turn_face(cube, face)
        
        integer, dimension(0:53), intent(in) :: cube
        integer, dimension(0:53)             :: turn_face
        integer, intent(in)                  :: face
        integer                              :: offset
        
        turn_face = cube
        offset = 9*face
 
        turn_face(mod(offset,54)) = cube(mod(offset+6,54))
        turn_face(mod(offset+1,54)) = cube(mod(offset+3,54))
        turn_face(mod(offset+2,54)) = cube(mod(offset+0,54))
        turn_face(mod(offset+3,54)) = cube(mod(offset+7,54))
        turn_face(mod(offset+5,54)) = cube(mod(offset+1,54))
        turn_face(mod(offset+6,54)) = cube(mod(offset+8,54))
        turn_face(mod(offset+7,54)) = cube(mod(offset+5,54))
        turn_face(mod(offset+8,54)) = cube(mod(offset+2,54))
 
    end function turn_face 
 
    subroutine print_cube(cube)
        integer, intent(in), dimension(0:53)  :: cube
        integer                               :: offset
 
        offset = 0
        do m = 0, 5
            print*, cube(0+offset:8+offset)
            offset = offset+9
        end do
 
    end subroutine print_cube
 
    function compare(cube1, cube2)
        integer, dimension(0:53), intent(in) :: cube1, cube2
        integer                              :: compare
            
        compare = 0
        do m = 0, 53
            if(cube1(m) == cube2(m)) compare = compare +1
            if(cube2(m) > 5) then
                if (cube1(m) < 6) compare = compare+1  !sticker = 6=> couleur pas importante
            end if
        end do
    end function compare
 
    function do_sequence(cube, move_sequence, sequence_size)
        integer, intent(in)                  :: sequence_size
        integer, dimension(0:53), intent(in) :: cube
        integer, dimension(sequence_size), intent(in)    :: move_sequence
        integer, dimension(0:53)             :: do_sequence
        
        do_sequence = do_move(cube, move_sequence(1)) !initialisation
        
        if(sequence_size > 1) then
            do n = 2, sequence_size
                do_sequence = do_move(do_sequence, move_sequence(n))
            end do
        end if
        
    end function do_sequence
 
        function entropy(cube)
        !calcule l'entropie du cube, définie comme (somme(CEP) + somme(ECeP))
        !CEP = corner-edge pairs
        !ECeP = edges-center pairs
        !Ouaiiii c'est pas la vrai entropie puisque je la maximise ;)
 
        integer, dimension(0:53), intent(in)    :: cube
        integer                                 :: entropy
        
        entropy = 0
        
        !Corner-edges pairs
        !FLU corner
        if(cube(0) == cube(1) .and. cube(15)== cube(16)) entropy = entropy+1
        if(cube(0) == cube(3) .and. cube(47)== cube(50)) entropy = entropy+1
        if(cube(47) == cube(46) .and. cube(15) == cube(12)) entropy = entropy+1
        !FRU corner
        if(cube(2) == cube(5) .and. cube(18)== cube(21)) entropy = entropy+1
        if(cube(2) == cube(1) .and. cube(17)== cube(16)) entropy = entropy+1
        if(cube(17) == cube(14) .and. cube(18) == cube(19)) entropy = entropy+1
        !FRD corner
        if(cube(8) == cube(5) .and. cube(24)== cube(21)) entropy = entropy+1
        if(cube(8) == cube(7) .and. cube(38)== cube(37)) entropy = entropy+1
        if(cube(38) == cube(41) .and. cube(24) == cube(25)) entropy = entropy+1
        !FLD corner
        if(cube(6) == cube(3) .and. cube(53)== cube(50)) entropy = entropy+1
        if(cube(6) == cube(7) .and. cube(36)== cube(37)) entropy = entropy+1
        if(cube(36) == cube(39) .and. cube(53) == cube(52)) entropy = entropy+1
        !BLU corner
        if(cube(29) == cube(32) .and. cube(45)== cube(48)) entropy = entropy+1
        if(cube(29) == cube(28) .and. cube(9)== cube(10)) entropy = entropy+1
        if(cube(9) == cube(12) .and. cube(45) == cube(46)) entropy = entropy+1
        !BRU corner
        if(cube(27) == cube(28) .and. cube(11)== cube(10)) entropy = entropy+1
        if(cube(27) == cube(30) .and. cube(20)== cube(23)) entropy = entropy+1
        if(cube(11) == cube(14) .and. cube(20) == cube(19)) entropy = entropy+1
        !BRD corner
        if(cube(33) == cube(34) .and. cube(44)== cube(43)) entropy = entropy+1
        if(cube(33) == cube(30) .and. cube(26)== cube(23)) entropy = entropy+1
        if(cube(44) == cube(41) .and. cube(26) == cube(25)) entropy = entropy+1
        !BLD corner
        if(cube(35) == cube(34) .and. cube(42)== cube(43)) entropy = entropy+1
        if(cube(35) == cube(32) .and. cube(51)== cube(48)) entropy = entropy+1
        if(cube(42) == cube(39) .and. cube(51) == cube(52)) entropy = entropy+1
 
 
        !Edges-centers pairs
        !F
        if(cube(4) == cube(1))  entropy = entropy+1
        if(cube(4) == cube(3))  entropy = entropy+1
        if(cube(4) == cube(5))  entropy = entropy+1
        if(cube(4) == cube(7))  entropy = entropy+1
        !U
        if(cube(13) == cube(10))  entropy = entropy+1
        if(cube(13) == cube(12))  entropy = entropy+1
        if(cube(13) == cube(14))  entropy = entropy+1
        if(cube(13) == cube(16))  entropy = entropy+1
        !R
        if(cube(22) == cube(19))  entropy = entropy+1
        if(cube(22) == cube(21))  entropy = entropy+1
        if(cube(22) == cube(23))  entropy = entropy+1
        if(cube(22) == cube(25))  entropy = entropy+1
        !B
        if(cube(31) == cube(28))  entropy = entropy+1
        if(cube(31) == cube(30))  entropy = entropy+1
        if(cube(31) == cube(32))  entropy = entropy+1
        if(cube(31) == cube(34))  entropy = entropy+1
        !D
        if(cube(40) == cube(37))  entropy = entropy+1
        if(cube(40) == cube(39))  entropy = entropy+1
        if(cube(40) == cube(41))  entropy = entropy+1
        if(cube(40) == cube(43))  entropy = entropy+1
        !L
        if(cube(49) == cube(46))  entropy = entropy+1
        if(cube(49) == cube(48))  entropy = entropy+1
        if(cube(49) == cube(50))  entropy = entropy+1
        if(cube(49) == cube(52))  entropy = entropy+1
 
    end function entropy
 
    function is2x2x3(cube)
        !Voir commentaires fonction entropy ...
        !fonction "vérifiant" l'état du 2x2x3 situé en BD en terme de CE et ECe pairs
        !vaut 16 ssi le 2x2x3 est complet
 
        integer, dimension(0:53), intent(in)    :: cube
        integer                                 :: is2x2x3
        
        is2x2x3 = 0
        
        !Corner-edges pairs
        !BRD corner
        if(cube(33) == cube(34) .and. cube(44)== cube(43)) is2x2x3 = is2x2x3+1
        if(cube(33) == cube(30) .and. cube(26)== cube(23)) is2x2x3 = is2x2x3+1
        if(cube(44) == cube(41) .and. cube(26) == cube(25)) is2x2x3 = is2x2x3+1
        !BLD corner
        if(cube(35) == cube(34) .and. cube(42)== cube(43)) is2x2x3 = is2x2x3+1
        if(cube(35) == cube(32) .and. cube(51)== cube(48)) is2x2x3 = is2x2x3+1
        if(cube(42) == cube(39) .and. cube(51) == cube(52)) is2x2x3 = is2x2x3+1
 
        !Edges-centers pairs
        !R
        !if(cube(22) == cube(19))  is2x2x3 = is2x2x3+1
        !if(cube(22) == cube(21))  is2x2x3 = is2x2x3+1
        if(cube(22) == cube(23))  is2x2x3 = is2x2x3+1
        if(cube(22) == cube(25))  is2x2x3 = is2x2x3+1
        !B
        !if(cube(31) == cube(28))  is2x2x3 = is2x2x3+1
        if(cube(31) == cube(30))  is2x2x3 = is2x2x3+1
        if(cube(31) == cube(32))  is2x2x3 = is2x2x3+1
        if(cube(31) == cube(34))  is2x2x3 = is2x2x3+1
        !D
        !if(cube(40) == cube(37))  is2x2x3 = is2x2x3+1
        if(cube(40) == cube(39))  is2x2x3 = is2x2x3+1
        if(cube(40) == cube(41))  is2x2x3 = is2x2x3+1
        if(cube(40) == cube(43))  is2x2x3 = is2x2x3+1
        !L
        !if(cube(49) == cube(46))  is2x2x3 = is2x2x3+1
        if(cube(49) == cube(48))  is2x2x3 = is2x2x3+1
        !if(cube(49) == cube(50))  is2x2x3 = is2x2x3+1
        if(cube(49) == cube(52))  is2x2x3 = is2x2x3+1
 
    end function is2x2x3
 
    function is2gen(cube)
        !checks if a given cube is 2-gen solvable, according to two rules :
        !   correct edges orientation
        !   solvable position of corners (according to Sebastian Dumitrescu's demonstration)
        !   two different corners linkages must be computed !
        !   returns 1 if OK, 0 otherwise
 
        !The given 2 faces are F & U
 
        use dflib
 
        integer, dimension(0:53), intent(in)    :: cube
        integer                                 :: is2gen
        integer, dimension(6)                   :: corners_pos
        integer, dimension(6)                   :: corner_temp
        integer                                 :: edges_ori, co
 
        is2gen = 0
        edges_ori = 0
 
        !checks the orientation of edges
        if(cube(1) == cube(4) .or. cube(16) == cube(13)) edges_ori = edges_ori+1
        if(cube(3) == cube(4) .or. cube(50) == cube(13)) edges_ori = edges_ori+1
        if(cube(5) == cube(4) .or. cube(21) == cube(13)) edges_ori = edges_ori+1
        if(cube(7) == cube(4) .or. cube(37) == cube(13)) edges_ori = edges_ori+1
        if(cube(28) == cube(4) .or. cube(10) == cube(13)) edges_ori = edges_ori+1
        if(cube(46) == cube(4) .or. cube(13) == cube(13)) edges_ori = edges_ori+1
        if(cube(19) == cube(4) .or. cube(14) == cube(13)) edges_ori = edges_ori+1
        
        if (edges_ori < 7) return
 
        !corners :
        !5  6  U face
        !3  4
        !1  2  F face
        !checks the position of the corners: 1st test (link 5-1, 6-2, 3-4 and observe the pattern)
        corner_temp(1) = 2**cube(6)+ 2**cube(36)+2**cube(53) !FDL positioned corner of cube
        corner_temp(2) = 2**cube(8)+2**cube(38)+2**cube(24)  !FDR
        corner_temp(3) = 2**cube(0)+2**cube(15)+2**cube(47)  !FUL
        corner_temp(4) = 2**cube(2)+2**cube(17)+2**cube(18)  !FUR       
        corner_temp(5) = 2**cube(29)+2**cube(9)+2**cube(45)  !BUL
        corner_temp(6) = 2**cube(27)+2**cube(11)+2**cube(20) !BUR
        
        do co = 1, 6
            if (corner_temp(co) == 2**cube(4)+2**cube(40)+2**cube(49)) corners_pos(co)=0
            if (corner_temp(co) == 2**cube(4)+2**cube(40)+2**cube(22)) corners_pos(co)=1
            if (corner_temp(co) == 2**cube(4)+2**cube(13)+2**cube(49)) corners_pos(co)=2
            if (corner_temp(co) == 2**cube(4)+2**cube(13)+2**cube(22)) corners_pos(co)=2
            if (corner_temp(co) == 2**cube(31)+2**cube(13)+2**cube(49)) corners_pos(co)=0
            if (corner_temp(co) == 2**cube(31)+2**cube(13)+2**cube(22)) corners_pos(co)=1
        end do
 
        !print*, "corners positions", corners_pos
        
        !on doit passer en scalaire pour le select case
        co = 100000*corners_pos(1)+10000*corners_pos(2)+1000*corners_pos(3)+100*corners_pos(4)+10*corners_pos(5)+corners_pos(6) 
        select case(co)
            case(12201,1221,11022,12120,10212,102210,110220,100122,102021,101202,210021,221001,211200,210102,212010,21102,2112,22011,21210,20121,120012,112002,122100,120201,121020,201120,220110,200211,201012,202101) 
                is2gen = 1
            case default
                return
        end select
 
        !2nd test (link 5-2, 6-4, 3-1 and observe the pattern)
                do co = 1, 6
            if (corner_temp(co) == 2**cube(4)+2**cube(40)+2**cube(49)) corners_pos(co)=0
            if (corner_temp(co) == 2**cube(4)+2**cube(40)+2**cube(22)) corners_pos(co)=1
            if (corner_temp(co) == 2**cube(4)+2**cube(13)+2**cube(49)) corners_pos(co)=0
            if (corner_temp(co) == 2**cube(4)+2**cube(13)+2**cube(22)) corners_pos(co)=2
            if (corner_temp(co) == 2**cube(31)+2**cube(13)+2**cube(49)) corners_pos(co)=1
            if (corner_temp(co) == 2**cube(31)+2**cube(13)+2**cube(22)) corners_pos(co)=2
        end do
 
        !print*, "corners positions", corners_pos
        
        !on doit passer en scalaire pour le select case
        co = 100000*corners_pos(1)+10000*corners_pos(2)+1000*corners_pos(3)+100*corners_pos(4)+10*corners_pos(5)+corners_pos(6) 
        select case(co)
            case(12201,1221,11022,12120,10212,102210,110220,100122,102021,101202,210021,221001,211200,210102,212010,21102,2112,22011,21210,20121,120012,112002,122100,120201,121020,201120,220110,200211,201012,202101) 
                is2gen = 1
            case default
                is2gen = 0
        end select
 
    
    end function is2gen
 
    function fobj(cube, cube_solved, moves_sequence, sequence_size, type_func )
        !La fonction objectif est définie comme nmax - x, où nmax est le nombre max de stickers OK
        !en parcourant la séquence de moves et x le nombre de mouvements après lesquels on y arrive
        !Exemple d'appel :
        !print*, fobj(cube_scrambled, cube_solved, moves_sequence, size(moves_sequence),1) 
 
        integer, intent(in)                             :: sequence_size, type_func
        integer, dimension(0:53), intent(in)            :: cube, cube_solved
        integer, dimension(sequence_size), intent(in)   :: moves_sequence
        integer, dimension(2)                           :: fobj
        integer     :: nmax, x, ni, i
        integer, dimension(0:53)                        :: cube_temp
        
        cube_temp = cube
        
        x = 0
        nmax = 0                                    !approche par paires
 
        !nmax = compare(cube_temp, cube_solved)  !approche par stickers
        if (sequence_size > 1) then
            do i = 1, sequence_size
                cube_temp = do_move(cube_temp, moves_sequence(i))
 
                select case(type_func)
                case (1)
                    ni = compare(cube_temp, cube_solved)            !Approche par stickers
                case (2)
                    ni = entropy(cube_temp)                         !Approche par paires
                case (3)
                    ni = is2x2x3(cube_temp)                         !Approche par 2x2x3 en BD
                case (4)
                    ni = 10*is2gen(cube_temp) + 10*is2x2x3(cube_temp)   !Phase getting into 2-gen
                end select
 
                if (ni > nmax) then
                    nmax = ni
                    x = i
                end if
                !print*, i ,ni, nmax, x
            end do
        end if
 
        fobj(1) = 10*nmax -x
        fobj(2) = x
 
    end function fobj
 
    subroutine solve_twogen_bourrin(cube_2gen, cube_solved)
    !résoud un cube dans le groupe twogen de manière optimale (HTM)
    integer, dimension(0:53), intent(in)    :: cube_2gen, cube_solved
    integer, dimension(0:24)                :: sol
    integer, dimension(3)                   :: m
    integer, dimension(2)                   :: test_resolu
    integer                                 :: m1,m2,m3
    
    sol=sol+3   !On remplit la sol du 2-gen avec des mouvements qui n'ont rien à y faire (initialisation
 
 
    do m1=0,5
        sol(0)=(m1/2)*6 + mod(m1,2)  !0,1,6,7,12,13 OK
        !print*, mod(m1,2), " sol(0) : ", sol(0)
        test_resolu = fobj(cube_2gen, cube_solved, sol, 25, 1)
        !print*, (test_resolu(1)+test_resolu(2))/10.
        if((test_resolu(1)+test_resolu(2))/10. == 54) then
            print*, "youpie 1 !"
            print*, sol
            GOTO 3001
        end if
        
        do m2=0,5 !C'est pas top, ainsi il ajoute  de toute façon #m mouvements, changer les boucles...
            sol(1)=(m2/2)*6 + mod(m2,2)  !0,1,6,7,12,13 OK
            test_resolu = fobj(cube_2gen, cube_solved, sol, 25, 1)
            if((test_resolu(1)+test_resolu(2))/10. == 54) then
                print*, "youpie 2 !"
                print*, sol
                GOTO 3001
            end if
        end do
    
    end do
 
    
3001    end subroutine solve_twogen_bourrin
 
 
 
    function classement_population(pop, val_fobj)
    !classe une population selon les valeurs décroissantes de la fonction objectif
    
    integer, dimension(:, :), intent(in)    :: pop
    integer, dimension(:)                   :: val_fobj   !seulement la valeur de fobj
    integer                                 :: max_indice, taille, i
    integer, dimension(size(pop, 1), size(pop,2))   :: classement_population
 
    taille = size(pop, 1)
 
    classement_population = pop
 
    do i = 1, taille
        max_indice = maxloc(val_fobj,1)
        classement_population(i,:) = pop(max_indice, :)
        val_fobj(max_indice) = -10000
    end do
 
    end function classement_population
 
    function pop_mariee (pop, phi, pc, perfo)
!Choisit des couples parmi une population d'individus triés par ordre de fobj croissante:
!pc = probabilité de croisement
!n = taille population
!phi = nbre moyen de descendants de l'Elite
 
    use dflib
    use dfport
 
    integer, dimension(:,:), intent(in)             :: pop
    integer, dimension(size(pop,1),2), intent(in)   :: perfo
    real, intent(in)                                :: phi, pc
    integer, dimension(size(pop,1),size(pop,2))     :: pop_mariee
    real, dimension(0:size(pop,1)-1)                :: pi
    integer                                         :: i, j, n, numero_enf, r0, p1, p2, cross
    real                                            :: x0, y0
    
    call seed(RND$TIMESEED)
    n = size(pop, 1)
 
    !pop2 se remplira avec les enfants
    pop_mariee = pop
 
    !Calcul de la proba du nombre d'enfants en fct du rang
 
    do i = 0, n-1
 
        pi(i) = 1./n * (phi - i*(2.*phi-2)/(n-1.))    
    end do
 
    !Stratégie élitiste : on conserve l'Elite -> boucle start @ numero_enf = 2 et génère (n-1)/2 couples
 
    numero_enf = 2
    do j = 1, (n-1)/2
 
        !Choix du premier parent :
    1   call random(x0)
        r0 = int(n*0.9999*x0)            !le 0.9999 c'est pour si jamais x0==1
        call random(y0)
 
        if( (2. - phi + 2.*y0*(phi-1.))/n > pi(r0)) then
            GOTO 1
        end if
 
        p1 = r0+1
 
        !Choix du 2e parent : aléatoire équiprobable
 
        call random(x0)
        p2=int(n*0.9999*x0)+1
 
        !print*, p1, p2
 
        !Choix du gène de cross-over appartient à {1, ..., long_code-1}
        !ALEATOIRE
        call random(x0)
        cross = (size(pop,2)-1) * 0.9999* x0 + 1   !pour le cas foireux ou x0 ==1 pile
        !OU : APRES LE 1ER MAX DE FOBJ pour le premier parent
        !cross = perfo(p1, 2)
 
        if (cross == size(pop,2)) cross = cross-1
        !On attribue les gênes 1:cross du premier parent à l'individu numero_enf et cross+1:fin du 2e parent
        !vice-versa à l'individu suivant (son frère)
        !croisement a lieu avec une proba pc
 
        call random(x0)
 
        if(x0 < pc) then
        pop_mariee(numero_enf, 1:cross) = pop(p1, 1:cross)
        pop_mariee(numero_enf, cross+1:size(pop,2)) = pop(p2, cross+1:size(pop,2))
        pop_mariee(numero_enf+1, 1:cross) = pop(p2, 1:cross)
        pop_mariee(numero_enf+1, cross+1:size(pop,2)) = pop(p1, cross+1:size(pop,2))
        
        else  !pas croisement
        pop_mariee(numero_enf, :)   = pop(p1, :)
        pop_mariee(numero_enf+1, :) = pop(p2, :)
 
        end if
 
        numero_enf =numero_enf + 2
 
    end do   !boucle j sur le remplissage de pop2
 
    end function pop_mariee
 
    function pop_mutee(pop, pm)
 
        use dflib
        use dfport
 
        integer, dimension(:,:), intent(in)             :: pop
        real, intent(in)                                :: pm
        integer, dimension(size(pop,1),size(pop,2))     :: pop_mutee
        integer                                         :: i, j, n1, n2, g0
        real                                            :: x0
        
        call seed(RND$TIMESEED)
        n1 = size(pop, 1)
        n2 = size(pop, 2)
 
        pop_mutee = pop
 
        do i = 2, n1  !elite ne mute pas !
         do j = 1, n2
            call random(x0)
            if (x0 < pm) then
                call random(x0)
                g0 = 18*0.9999*x0 
                pop_mutee(i,j) = g0
            end if
         end do
        end do
 
 
    end function pop_mutee
 
    function trim_sequence (moves_sequence)
 
        use dflib
        use dfport
 
        integer, dimension(:), intent(in)           :: moves_sequence
        integer, dimension(size(moves_sequence))    :: trim_sequence
        integer :: l, ltot, shoots, move, move_suivant
        real    :: r
        
        call seed(RND$TIMESEED)
 
        ltot = size(moves_sequence)
        trim_sequence = moves_sequence
 
 
        shoots = 0
21      do l = 1, ltot-1
            move = trim_sequence(l)
            move_suivant = trim_sequence(l+1)
            if(mod(move, 6) == mod(move_suivant, 6)) then
                if(abs(move-move_suivant)== 12) then !Deux moves s'annulent
                    trim_sequence(l:ltot-2) = trim_sequence(l+2:ltot)
                    do shoots = 1,2
                    call random(r)
                    trim_sequence(ltot-2+shoots) = 18 * 0.9999* r
                    end do
                end if
 
                if(move < 6) then  !Face
                    if(move_suivant == move) then ! face puis face = face^2
                        trim_sequence(l) = move+6
                        trim_sequence(l+1:ltot-1) = trim_sequence(l+2:ltot)
                        call random(r)
                        trim_sequence(ltot) = 18 * 0.9999* r
                    else if(move_suivant == move+6) then ! face puis face^2 = face'                 
                        trim_sequence(l) = move+12
                        trim_sequence(l+1:ltot-1) = trim_sequence(l+2:ltot)
                        call random(r)
                        trim_sequence(ltot) = 18 * 0.9999* r
                    end if
                end if
                
                if(move < 12) then
                    if(move<6) GOTO 22
                    if (move_suivant == move-6) then !Face^2 puis face = face'
                        trim_sequence(l) = move+6
                        trim_sequence(l+1:ltot-1) = trim_sequence(l+2:ltot)
                        call random(r)
                        trim_sequence(ltot) = 18 * 0.9999* r
                    else if (move_suivant == move) then !Face^2 puis face^2 = annule
                        trim_sequence(l:ltot-2) = trim_sequence(l+2:ltot)
                        do shoots = 1,2
                        call random(r)
                        trim_sequence(ltot-2+shoots) = 18 * 0.9999* r
                        end do
                    else if (move_suivant == move+6) then !Face^2 puis face' = face
                        trim_sequence(l) = move-6
                        trim_sequence(l+1:ltot-1) = trim_sequence(l+2:ltot)
                        call random(r)
                        trim_sequence(ltot) = 18 * 0.9999* r
                    end if
                end if
                if (move < 12)  GOTO 22
                ! Arrive ci-dessous si et seulement move et face'
                if(move_suivant == move-6)  then !face' puis face^2 = face
                        trim_sequence(l) = move-12
                        trim_sequence(l+1:ltot-1) = trim_sequence(l+2:ltot)
                        call random(r)
                        trim_sequence(ltot) = 18 * 0.9999* r
                else if(move_suivant == move) then !face' puis face' = face^2
                        trim_sequence(l) = move-6
                        trim_sequence(l+1:ltot-1) = trim_sequence(l+2:ltot)
                        call random(r)
                        trim_sequence(ltot) = 18 * 0.9999* r
                end if
22          GO TO 21  ! Juste pour avoir un GO TO
            end if
 
        end do
 
end function trim_sequence
 
    function twist_sequence(moves_sequence)
        !twists moves sequence clockwise around FUR corner
        !vouaiii un peu stupide, autant twister le cube ...
        integer, dimension(:), intent(in)       :: moves_sequence
        integer, dimension(size(moves_sequence)):: twist_sequence
        twist_sequence = 6*(moves_sequence/6) + mod(1+moves_sequence-6*(moves_sequence/6) ,3) + 3*((moves_sequence-6*(moves_sequence/6))/3)
 
    end function twist_sequence
 
    function twist_cube(c)
        !twists whole cube around FUR corner
        integer, dimension(0:53), intent(in)    :: c
        integer, dimension(0:53)                :: twist_cube
        
        !print*, "FUR clockwise twist (= x y)"
        twist_cube(0:8)   = [c(24),c(21),c(18),c(25),c(22),c(19),c(26),c(23),c(20)] !F<-R
        twist_cube(9:17)  = [c(6),c(3),c(0),c(7),c(4),c(1),c(8),c(5),c(2)]          !U<-F
        twist_cube(18:26) = [c(17),c(16),c(15),c(14),c(13),c(12),c(11),c(10),c(9)]  !R<-U
        twist_cube(27:35) = [c(47),c(50),c(53),c(46),c(49),c(52),c(45),c(48),c(51)] !B<-L
        twist_cube(36:44) = [c(33),c(30),c(27),c(34),c(31),c(28),c(35),c(32),c(29)] !D<-B
        twist_cube(45:53) = c(36:44)                                                !L<-D
 
    end function twist_cube
 
    function rotate_whole_cube(cu)
            !rotates whole cube clockwise around vertical axis
        integer, dimension(0:53), intent(in)    :: cu
        integer, dimension(0:53)                :: rotate_whole_cube
        
        !print*, "whole cube clockwise rotation around Oz (= y)"
        rotate_whole_cube(9:17) = [cu(15),cu(12),cu(9),cu(16),cu(13),cu(10),cu(17),cu(14),cu(11)] !U
        rotate_whole_cube(36:44)= [cu(38),cu(41),cu(44),cu(37),cu(40),cu(43),cu(36),cu(39),cu(42)]!D        
        rotate_whole_cube(0:8)   = cu(18:26)        !F<-R
        rotate_whole_cube(18:26) = cu(27:35)        !R<-B
        rotate_whole_cube(27:35) = cu(45:53)        !B<-L
        rotate_whole_cube(45:53) = cu(0:8)          !L<-F
 
    end function rotate_whole_cube
 
    function rotate_whole_cube_x(cu)
            !rotates whole cube clockwise LR axis (= x)
            !defined as xy yyy
 
        integer, dimension(0:53), intent(in)    :: cu
        integer, dimension(0:53)                :: rotate_whole_cube_x
        integer                                 :: rot
                
        !print*, "whole cube clockwise rotation around Oy (= x)"
        rotate_whole_cube_x = cu
 
        rotate_whole_cube_x = twist_cube(cu)
        do rot = 1,3
            rotate_whole_cube_x = rotate_whole_cube(rotate_whole_cube_x)
        end do
 
    end function rotate_whole_cube_x
 
    
 
end module external_fcts
 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    program RUBIK
 
 
    
    use external_fcts
    use dflib
    use dfport
 
    implicit none
 
    integer                                 :: i, j, k, ll, lll, two_gen, loc2x2x3, scramble_type, moves_total, twogen_bourrin
    integer, dimension(:), allocatable      :: moves_sequence, scramble_sequence
    integer, dimension(0:53)                :: cube_solved, cube_scrambled, cube, cube_scrambled_copy
    real                                    :: r !random number
    character, dimension(:),allocatable     :: scramble_notation, sequence_notation, sol1, sol2, sol3
    character*2                             :: char_buffer
    integer, dimension(12)                  :: best2x2x3loc, best2x2x3fobj, best2x2x3fobj_copie
    integer, dimension(12, 30)              :: best2x2x3elits
    integer, dimension(12,2)                :: best_temp
    
    !Paramètres algo génétique
    integer                                     :: taille_pop, long_code, Ttot, generation, nbre_intrus, is_continuing
    real                                        :: pm, pc, phi
    integer, dimension(:,:), allocatable        :: pop, perfo, perfo_copie
    integer, dimension(:,:,:), allocatable      :: pop_storage   !si on doit recommencer les 2x2x3, on ne perd pas tout ;-)
 
    !initialisation
    call seed(RND$TIMESEED)   !la seed est effectivement différente à chaque appel :)
    cube_solved = init(cube)
    scramble_type = 2    !0 = défini manuellement, 1 = random, 2 = entré manuellement
    
    print*, 'Genetic rubik''s cube solver, version 2.1'
    print*, ''
    print*, 'Cyril Castella, May 22, 2005'
    print*, 'http://www.francocube.com'
    print*, ''
    print*, 'Enter scramble type : 1 = random, 2 = User-defined'
    read*, scramble_type
    print*, ''
    print*, 'Enter number of generations for simulation : '
    read*, Ttot
 
    two_gen = 0
    twogen_bourrin=0        !résoud le 2-gen par brute force au lieu algo génétique
 
    open(unit=10, file='results.txt', status='replace')
 
    !mélange
 
    allocate(scramble_sequence(37))
    !scramble_sequence = [6,1,14,17,0,1,14,17,0,1,14,17,0,1,14,17,0,9,13,14,10,0,2,9,7,0,2,9,7,0,2,9,7,0,2,9,7,4] !FMC#81, 38 moves
    !scramble_sequence = [14,16,14,6,3,7,17,16,0,7,17,16,0,7,17,16,0,8,1,5,0,7,14,5,9,12,2,10,1,12,2,10,1,12,2,10,1,11,12,15,4] !41 moves
    !scramble_sequence = [0,1,6,13,0,1,6,13,0,1,6,13,6,7,12,1,6,13,0,1,6,13,0,1,6,13,0,7,12,1,6,13,12,7,0,13,12,7,0,13,12,7,0] !43 moves 2-.gen
    !scramble_sequence = [10,14,9,10,17,6,15,10,12,17,6,15,10,12,17,6,15,10,12,13,3,7,15,12,2,12,3,1,10,2,12,3,1,10,2,12,3,1,10,0,1,15,12] !#82, 43 moves
    scramble_sequence = [2,4,2,3,11,4,15,5,0,4,15,5,0,4,15,5,0,8,4,12,7,3,2,16,7,3,2,16,7,3,2,16,11,2,4,7,6] !FMC#83, 37 moves
    !if(two_gen) scramble_sequence = mod(scramble_sequence,2) + 6*(scramble_sequence/6) !2-gen scramble
 
    if(scramble_type == 1) then
        print*, 'Enter number of moves of the scramble'
        read*, j
        deallocate(scramble_sequence)
        allocate(scramble_sequence(j))
        do i = 1, j
            call random(r)
            scramble_sequence(i) = 18*0.9999*r
        end do
        scramble_sequence = trim_sequence(scramble_sequence)
    endif
 
    if(scramble_type ==2) then
        print*, 'Enter number of moves of the scramble'
        read*, j
        print*, 'Enter the scramble moves. Only one move (HTM) per line !'
        deallocate(scramble_sequence)
        allocate(scramble_sequence(j))
        do i = 1, j
            read*, char_buffer
            call ToNumbers(char_buffer, scramble_sequence(i))
        end do
    end if
 
    allocate(scramble_notation(3*size(scramble_sequence)))
    call ToString(scramble_sequence, scramble_notation)
    print*, scramble_notation
 
    !Ecriture du scramble dans le fichier de résultats
    write(10, *), 'Scramble : '
    write(10, *), scramble_notation
 
    cube_scrambled = do_sequence(cube_solved, scramble_sequence, size(scramble_sequence))
    cube_scrambled_copy = cube_scrambled
 
 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Solving 2x2x3 !!!!!!!!!!!!!!!!!!!!!!!!!!!
 
    is_continuing = 0
    taille_pop = 51     !# individus
    nbre_intrus = 5     !#individus aléatoires remplacent les plus mauvais de pop à chaque gén.
    long_code  = 30     !nombre de gènes   
    !Ttot = 50      !nombre de générations
    pm = 0.05           !proba mutation
    pc = 0.8            !proba croisement
    phi = 1.5           !poids élite
 
    allocate(pop_storage(12, taille_pop, long_code))
    allocate(pop(taille_pop, long_code))
    allocate(perfo(taille_pop, 2))
    allocate(perfo_copie(taille_pop,2))
 
101 do loc2x2x3 = 0,11
    print*,''
    print*, '------------2x2x3 position is : ', loc2x2x3, '       ----------'
 
    cube_scrambled = cube_scrambled_copy   !subtil ... je crois qu'une de mes fcts change cube_scrambled
 
    !Subtil ... mais visite effectivement toutes les 12 locations possibles ;-)
    ! 0 = BD, 1 = xy = BL, 2 = x2 = FU, 3 = y = DL, 4 = yxy = FL, 5 = yx2 = UR
    ! 6 = y2 = FD, 7 = y2xy = FR, 8 = y2x2 = UB, 9 = y3 = RD, 10 = y3xy = RB, 11 = y3x2UL
 
    do ll=1, loc2x2x3/3
        cube_scrambled = rotate_whole_cube(cube_scrambled)
        print*, "whole cube clockwise rotation around Oz (= y)"
        print*
    end do
 
    select case (modulo(loc2x2x3,3))
        case(1)
            cube_scrambled = twist_cube(cube_scrambled)
            print*, "whole cube rotation around FUR corner (=xy)"
        case(2)
            do i = 1,2
                cube_scrambled = rotate_whole_cube_x(cube_scrambled)
                print*, "whole cube rotation around LR horizontal axis (=x)"
            end do
    end select
 
    k = is2gen(cube_scrambled)
    !print*, "... is 2-gen ? ", k
    if(k==1) then 
        print*, '2-gen solve'
        two_gen = 1
    end if
    
    !génération population initiale
    do i = 1, taille_pop
        do j = 1, long_code
            call random(r)
            pop(i,j) = r*0.9999*18
        end do
    end do
    
    !si on est en train de continuer car pas assez de générations, on reprend la pop d'avant pour
    !cette location
    if(is_continuing) pop = pop_storage(loc2x2x3+1, :, :)
 
    do generation = 1, Ttot
    
    if(two_gen) pop = mod(pop,2) + 6*(pop/6)        !2-gen-> séquence contient uniquement (F,U)
    !Raccourci des mouvements qui s'annulent
    do i = 1, taille_pop
        pop(i,:) = trim_sequence(pop(i,:))
    end do
    
    !Evaluation de la fonction objectif sur la population
    !pour fobj : 3=2x2x3, 4=is2gen, 2=entropy
    do i = 1, taille_pop
    perfo(i, :) = fobj(cube_scrambled, cube_solved, pop(i, :), long_code, 3) 
    !print*, pop(i,:), perfo(i, 1)
    end do
    
    !classement de la population
    perfo_copie = perfo
    pop = classement_population(pop, perfo_copie(:,1))
    perfo_copie = perfo
    perfo = classement_population(perfo, perfo_copie(:,1))  !subtil :)
 
    !Print de l'état actuel
    if (modulo(generation, 100000) == 0) then
    print*, "Generation / elite/ moy. ", generation, perfo(1,:), float(sum(perfo(:,1))/taille_pop)
    end if
 
    !génocide des nmbre_intrus plus mauvais de la pop et remplacement par des aléatoires
    if(nbre_intrus > 0) then 
        do i = taille_pop-nbre_intrus+1, taille_pop
            do j = 1, long_code
                call random(r)
                pop(i,j) = r*0.9999*18
            end do
        end do
    end if
 
    !Mariages
    pop = pop_mariee (pop, phi, pc, perfo)
 
    !mutations
    pop = pop_mutee (pop, pm)
 
 
    end do  !fin boucle sur les generations
    
    pop_storage(loc2x2x3+1, :,:) = pop
 
    print*, "optimal :"
    allocate(sequence_notation(3*perfo(1,2)))
    call ToString(pop(1,1:perfo(1,2)), sequence_notation)
    print*, sequence_notation
    print*, "perfo, # moves, entropy"
    print*, perfo(1,:), (perfo(1,1)+perfo(1,2))/10
    if((perfo(1,1)+perfo(1,2))/10==16) print*, 'This 2x2x3 was solved :)'
    print*,''
    
    best2x2x3loc(loc2x2x3+1) = loc2x2x3
    best2x2x3elits(loc2x2x3+1, :) = pop(1, :)   
    best2x2x3fobj(loc2x2x3+1) = -perfo(1, 2) - (16-(perfo(1,1)+perfo(1,2))/10)*100 !pénalise une chiée si 2x2x3 pas solved
    
    deallocate(sequence_notation)
    end do !FIN BOUCLE SUR loc2x2x3
 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Getting into 2-gen !!!!!!!!!!!!!!!!!!!!!!!!!!!
 
    
    !Classement des élites en fonction de leur fobj définie ci-dessus
 
200 print*, ''
    best2x2x3fobj_copie = best2x2x3fobj
    best2x2x3elits = classement_population(best2x2x3elits, best2x2x3fobj_copie)
 
    best2x2x3fobj_copie = best2x2x3fobj
    best_temp(:,1) = best2x2x3loc
    best_temp(:,2) = best2x2x3fobj
    best_temp = classement_population(best_temp, best2x2x3fobj_copie)
    best2x2x3loc = best_temp(:,1)
    
    !si on n'a résolu aucun 2x2x3, ou un en plus de 20 moves on doit recommencer !!
    if(best_temp(1,2) < -20) then
        print*, 'Adding generations to solve the 2x2x3: no good solution was found.'
        is_continuing = 1
        GOTO 101
    end if
 
    !sinon, c'est cool, on continue
    deallocate(pop, perfo, perfo_copie)
    
    print*, 'Best 2x2x3 locations : '
    print*, best2x2x3loc
    print*, ''
    print*, 'End of the 2x2x3 search.'
    print*, 'Alg will now try to go into 2-gen for the best location.'
    print*, 'Location searched : ', best2x2x3loc(1)
    print*,''
 
 
    !On réinitialise cube_scrambled avec scramble, puis setup-rotations, puis best 2x2x3 solution
    loc2x2x3 = best2x2x3loc(1)
 
    cube_scrambled = cube_scrambled_copy
    do ll=1, loc2x2x3/3
        cube_scrambled = rotate_whole_cube(cube_scrambled)
        print*, "whole cube clockwise rotation around Oz (= y)"
        write(10, *), "whole cube clockwise rotation around Oz (= y)"
    end do
 
    select case (modulo(loc2x2x3,3))
        case(1)
            cube_scrambled = twist_cube(cube_scrambled)
            print*, "whole cube rotation around FUR corner (=xy)"
            write(10, *), "whole cube rotation around FUR corner (=xy)"
        case(2)
            do i = 1,2
                cube_scrambled = rotate_whole_cube_x(cube_scrambled)
                print*, "whole cube rotation around LR horizontal axis (=x)"
                write(10, *), "whole cube rotation around LR horizontal axis (=x)"
            end do
    end select
 
    best_temp(1,:) = fobj(cube_scrambled, cube_solved, best2x2x3elits(1,:), long_code, 3)
    cube_scrambled = do_sequence(cube_scrambled, best2x2x3elits(1,1:best_temp(1,2)), best_temp(1,2))
    moves_total = best_temp(1,2)  !comptage pour le nombre de moves de la solution finale
 
    !Print dans le fichier de résultats
    allocate(sol1(3*moves_total))
    call ToString(best2x2x3elits(1,1:best_temp(1,2)), sol1)
 
    !!!!!!!!Algo génétique pour la phase 'getting into 2-gen'
    taille_pop = 51     !# individus
    nbre_intrus = 5     !#individus aléatoires remplacent les plus mauvais de pop à chaque gén.
    long_code  = 30     !nombre de gènes   
    Ttot = 10000        !nombre de générations
    pm = 0.05           !proba mutation
    pc = 0.8            !proba croisement
    phi = 1.5           !poids élite
    allocate(pop(taille_pop, long_code))
    allocate(perfo(taille_pop, 2))
    allocate(perfo_copie(taille_pop,2))
 
    if(is2gen(cube_scrambled)) Ttot = 10
    
    !génération population initiale
    do i = 1, taille_pop
        do j = 1, long_code
            call random(r)
            pop(i,j) = r*0.9999*18
        end do
    end do
    
 
201 do generation = 1, Ttot
    
    if(two_gen) pop = mod(pop,2) + 6*(pop/6)        !2-gen-> séquence contient uniquement (F,U)
    !Raccourci des mouvements qui s'annulent
    do i = 1, taille_pop
        pop(i,:) = trim_sequence(pop(i,:))
    end do
    
    !Evaluation de la fonction objectif sur la population
    !pour fobj : 3=2x2x3, 4=is2gen, 2=entropy
    do i = 1, taille_pop
    perfo(i, :) = fobj(cube_scrambled, cube_solved, pop(i, :), long_code, 4) 
    !print*, pop(i,:), perfo(i, 1)
    end do
    
    !classement de la population
    perfo_copie = perfo
    pop = classement_population(pop, perfo_copie(:,1))
    perfo_copie = perfo
    perfo = classement_population(perfo, perfo_copie(:,1))  !subtil :)
 
    !Print de l'état actuel
    if (modulo(generation, 5000) == 0) then
    print*, "Generation / elite/ moy. ", generation, perfo(1,:), float(sum(perfo(:,1))/taille_pop)
    end if
 
    !génocide des nmbre_intrus plus mauvais de la pop et remplacement par des aléatoires
    if(nbre_intrus > 0) then 
        do i = taille_pop-nbre_intrus+1, taille_pop
            do j = 1, long_code
                call random(r)
                pop(i,j) = r*0.9999*18
            end do
        end do
    end if
 
    !Mariages
    pop = pop_mariee (pop, phi, pc, perfo)
 
    !mutations
    pop = pop_mutee (pop, pm)
 
 
    end do  !fin boucle sur les generations
 
    
    !Etait-on déjà dans le 2-gen groupe ?
    if(perfo(1,2)==1 .and. is2gen(cube_scrambled)==1) print*, 'Cube was already in the 2-gen group.'
    !A-t-on vraiment fini cette étape ?
 
    if( sum(perfo(1,:)) == 1700) then 
        
        print*, 'Getting into 2-gen phase is done :)'
 
        allocate(sequence_notation(3*perfo(1,2)))
        call ToString(pop(1,1:perfo(1,2)), sequence_notation)
 
        !Mise à jour de l'état de cube_scrambled si on n'y était pas déjà
        if(perfo(1,2) > 1) then
            cube_scrambled = do_sequence(cube_scrambled, pop(1,1:perfo(1,2)), perfo(1,2))
            moves_total = moves_total + perfo(1,2) !comptage pour #moves solution finale
            print*, "optimal :"
            print*, sequence_notation
            print*, "# moves"
            print*, perfo(1,2)
        end if  
    else
        print*, 'Adding 10''000 gen. to solve this part'
        GOTO 201
    end if
 
    print*,''
 
    !Prépare le print final dans le fichier
    allocate(sol2(size(sequence_notation)))
    sol2 = sequence_notation
    deallocate(pop, perfo, perfo_copie, sequence_notation)
 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Solving 2-gen !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
if(twogen_bourrin > 0) then 
    print*, "calling bourrin"
    call solve_twogen_bourrin(cube_scrambled, cube_solved)
    GOTO 9999
end if
 
300 taille_pop = 51     !# individus
    nbre_intrus = 5     !#individus aléatoires remplacent les plus mauvais de pop à chaque gén.
    long_code  = 30     !nombre de gènes   
    Ttot = 200000       !nombre de générations
    pm = 0.05           !proba mutation
    pc = 0.8            !proba croisement
    phi = 1.5           !poids élite
    allocate(pop(taille_pop, long_code))
    allocate(perfo(taille_pop, 2))
    allocate(perfo_copie(taille_pop,2))
 
    two_gen = 1
 
    !génération population initiale
    do i = 1, taille_pop
        do j = 1, long_code
            call random(r)
            pop(i,j) = r*0.9999*18
        end do
    end do
    
 
301 do generation = 1, Ttot
    
    if(two_gen) pop = mod(pop,2) + 6*(pop/6)        !2-gen-> séquence contient uniquement (F,U)
    !Raccourci des mouvements qui s'annulent
    do i = 1, taille_pop
        pop(i,:) = trim_sequence(pop(i,:))
    end do
    
    !Evaluation de la fonction objectif sur la population
    !pour fobj : 3=2x2x3, 4=is2gen, 2=entropy
    do i = 1, taille_pop
    perfo(i, :) = fobj(cube_scrambled, cube_solved, pop(i, :), long_code, 2) 
    !print*, pop(i,:), perfo(i, 1)
    end do
    
    !classement de la population
    perfo_copie = perfo
    pop = classement_population(pop, perfo_copie(:,1))
    perfo_copie = perfo
    perfo = classement_population(perfo, perfo_copie(:,1))  !subtil :)
 
    !Print de l'état actuel
    if (modulo(generation, 10000) == 0) then
    print*, "Generation / elite/ moy. ", generation, perfo(1,:), float(sum(perfo(:,1))/taille_pop)
    end if
 
    !génocide des nmbre_intrus plus mauvais de la pop et remplacement par des aléatoires
    if(nbre_intrus > 0) then 
        do i = taille_pop-nbre_intrus+1, taille_pop
            do j = 1, long_code
                call random(r)
                pop(i,j) = r*0.9999*18
            end do
        end do
    end if
 
    !Mariages
    pop = pop_mariee (pop, phi, pc, perfo)
 
    !mutations
    pop = pop_mutee (pop, pm)
 
 
    end do  !fin boucle sur les generations
 
    
 
    !Si on a fini, on a fini, sinon on continue ... quel poète ce cyril !
 
    if( (perfo(1,1)+perfo(1,2))/10. == 48) then
        print*, "optimal :"
        allocate(sequence_notation(3*perfo(1,2)))
        call ToString(pop(1,1:perfo(1,2)), sequence_notation)
        print*, sequence_notation
        
        print*, "fobj / # moves / entropy"
        print*, perfo(1,:), sum(perfo(1,:))/10
        moves_total = moves_total + perfo(1,2)
        
        print*, 'Whole cube was solved in ', moves_total, ' moves :)'
    else
        print*, 'Adding 200 000 more generations to solve this stage.'
        GOTO 301
    end if
    print*,''
 
    !Prépare le print dans le fichier de résultat
    allocate(sol3(size(sequence_notation)))
    sol3 = sequence_notation
    deallocate(pop, perfo, perfo_copie, sequence_notation)
 
 
 
 
 
    !Print des résultats
999 write(10, *) 'Solution : '
    write(10, *), sol1
    write(10, *), sol2
    write(10, *), sol3
    write(10, *), 'total moves # : ', moves_total
    close(unit=10)
 
    Deallocate(scramble_sequence, scramble_notation, sol1, sol2, sol3)
    
9999    print*, 'End of the program.'
        read*,i
    end program RUBIK

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎