From 8952cf1a9a56b3485a6c22963fb20c78a200ed6e Mon Sep 17 00:00:00 2001 From: fedebenelli Date: Sat, 23 Mar 2024 11:46:22 -0300 Subject: [PATCH] ford documentation --- .github/workflows/docs.yml | 48 ++++++++++++ ford.md | 30 ++++++++ src/sudoku.f90 | 146 ++++++++++++++++++++----------------- 3 files changed, 159 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 ford.md diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..639d12c --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,48 @@ +name: Build and Deploy Documentation + +on: [push, pull_request, workflow_dispatch] + +jobs: + documentation: + runs-on: ubuntu-22.04 + + env: + FC: gfortran + GCC_V: 12 + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Dependencies Ubuntu + run: | + sudo apt-get update + sudo apt install -y gfortran-${GCC_V} python3-dev graphviz + sudo pip install ford markdown + + - name: Build Developer Documentation + run: | + ford ford.md + + - name: Upload Documentation + uses: actions/upload-artifact@v2 + with: + name: documentation + path: doc/ford_site + if-no-files-found: error + + - name: Broken Link Check + if: ${{ github.ref == 'refs/heads/main'}} + uses: technote-space/broken-link-checker-action@v1 + with: + TARGET: file://${{ github.workspace }}/ford_site/index.html + RECURSIVE: true + ASSIGNEES: ${{ github.actor }} + + - name: Deploy API Documentation + uses: JamesIves/github-pages-deploy-action@4.1.0 + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: gh-pages + folder: doc/ford_site diff --git a/ford.md b/ford.md new file mode 100644 index 0000000..8c1c598 --- /dev/null +++ b/ford.md @@ -0,0 +1,30 @@ +--- +project: ForSudoku +summary: Sudoku generation and solving CLI program, written in Fortran +project_github: https://github.com/vmagnin/ForSudoku +author: vmagnin, nbehrnd +github: https://github.com/vmagnin +src_dir: src +exclude_dir: test doc +output_dir: doc/ford_site +preprocessor: gfortran -E +display: public + protected + private +source: false +proc_internals: true +sort: permission-alpha +docmark_alt: !> +docmark: ! +predocmark_alt: * +print_creation_date: true +creation_date: %Y-%m-%d %H:%M %z +md_extensions: markdown.extensions.toc + markdown.extensions.smarty +graph: true +license: GPL +--- + +[TOC] + +{!README.md!} diff --git a/src/sudoku.f90 b/src/sudoku.f90 index fd40b01..de634b1 100644 --- a/src/sudoku.f90 +++ b/src/sudoku.f90 @@ -1,25 +1,31 @@ -! This file is part of the ForSudoku Fortran project. -! Copyright (C) 2006-2024 Vincent Magnin & Norwid Behrnd -! -! This is free software; you can redistribute it and/or modify -! it under the terms of the GNU General Public License as published by -! the Free Software Foundation; either version 3, or (at your option) -! any later version. -! -! This software is distributed in the hope that it will be useful, -! but WITHOUT ANY WARRANTY; without even the implied warranty of -! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -! GNU General Public License for more details. -! -! You should have received a copy of the GNU General Public License along with -! this program; see the files LICENSE and LICENSE_EXCEPTION respectively. -! If not, see . -!------------------------------------------------------------------------------ -! Contributed by Vincent Magnin, 2006-11-27; Norwid Behrnd, 2023 -! Last modifications: 2023-09-12, vmagnin 2024-03-23 -!------------------------------------------------------------------------------ +!! This file is part of the ForSudoku Fortran project. +!! Copyright (C) 2006-2024 Vincent Magnin & Norwid Behrnd +!! +!! This is free software; you can redistribute it and/or modify +!! it under the terms of the GNU General Public License as published by +!! the Free Software Foundation; either version 3, or (at your option) +!! any later version. +!! +!! This software is distributed in the hope that it will be useful, +!! but WITHOUT ANY WARRANTY; without even the implied warranty of +!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!! GNU General Public License for more details. +!! +!! You should have received a copy of the GNU General Public License along with +!! this program; see the files LICENSE and LICENSE_EXCEPTION respectively. +!! If not, see . +!!------------------------------------------------------------------------------ +!! Contributed by Vincent Magnin, 2006-11-27; Norwid Behrnd, 2023 +!! Last modifications: 2023-09-12, vmagnin 2024-03-23 +!!------------------------------------------------------------------------------ module sudoku + !! Sudoku module + !! + !! @author: Vincent Magnin and Norwid Behrnd + !! + !! This module contains a set of procedures to generate sudokus grids and + !! solve them. implicit none contains @@ -28,6 +34,7 @@ module sudoku ! Input/Output routines !***************************************************************************** subroutine save_grid(grid, filename) + !! Input/Output routines integer, dimension(9, 9), intent(in) :: grid character(*), intent(in) :: filename @@ -48,8 +55,9 @@ subroutine save_grid(grid, filename) end subroutine save_grid subroutine read_grid(grid, filename) - integer, dimension(9, 9), intent(out) :: grid - character(*), intent(in) :: filename + !! Read a grid from a provided the path to a file + integer, dimension(9, 9), intent(out) :: grid !! Output grid + character(*), intent(in) :: filename !! File path character(len=2) :: pipe1, pipe2 ! to read the pipe/the vertical bar integer :: row @@ -76,6 +84,7 @@ subroutine read_grid(grid, filename) end subroutine read_grid subroutine display_grid(grid) + !! Display a grid on the terminal. integer, dimension(9, 9), intent(in) :: grid integer :: row, col @@ -102,9 +111,11 @@ end subroutine request_grid !***************************************************************************** ! Validation routines !***************************************************************************** - ! Returns true if each digit in the 1D array appears only once: pure logical function valid_colum_or_row(vector) - integer, dimension(1:9), intent(in) :: vector ! A row or a column + !! Validation of either a row or a column. + !! + !! Returns true if each digit in the 1D array appears only once + integer, dimension(1:9), intent(in) :: vector !! A row or a column ! The number of occurrences of each digit: integer, dimension(1:9) :: counters @@ -126,9 +137,11 @@ pure logical function valid_colum_or_row(vector) valid_colum_or_row = .true. end function valid_colum_or_row - ! Returns true if each digit in the 3x3 region appears only once. pure logical function valid_zone(region) - integer, dimension(1:3, 1:3), intent(in) :: region + !! Validation of a zone/region. + !! + !! Returns true if each digit in the 3x3 region appears only once. + integer, dimension(1:3, 1:3), intent(in) :: region !! Sudoku's subregion ! The number of occurrences of each digit: integer, dimension(1:9) :: counters @@ -152,9 +165,11 @@ pure logical function valid_zone(region) valid_zone = .true. end function valid_zone - ! Returns true if a full grid is valid: pure logical function valid_grid(grid) - integer, dimension(9, 9), intent(in) :: grid + !! Check if the whole grid is valid. + !! + !! Returns true if a full grid is valid. + integer, dimension(9, 9), intent(in) :: grid !! Sudoku grid. integer :: row, col @@ -187,10 +202,11 @@ pure logical function valid_grid(grid) valid_grid = .true. end function valid_grid - ! Returns true if the row, column and region of a digit are all valid: pure logical function valid_digit(grid, row, col) - integer, dimension(9, 9), intent(in) :: grid - integer, intent(in) :: row, col + !! Returns true if the row, column and region of a digit are all valid: + integer, dimension(9, 9), intent(in) :: grid !! Sudoky grid. + integer, intent(in) :: row !! Row number of the region. + integer, intent(in) :: col !! Column number of the region. integer :: i, j i = (row - 1) / 3 @@ -201,9 +217,9 @@ pure logical function valid_digit(grid, row, col) valid_zone(grid(i*3+1:i*3+3, j*3+1:j*3+3)) end function valid_digit - ! Returns true if the grid is full: pure logical function is_full(grid) - integer, dimension(9, 9), intent(in) :: grid + !! Returns true if the grid is full. + integer, dimension(9, 9), intent(in) :: grid !! Sudoky grid. if (any(grid(:,:) == 0)) then is_full = .false. @@ -212,11 +228,12 @@ pure logical function is_full(grid) end if end function - ! Procedure to create a list of allowed digits in the present empty cell: pure subroutine list_possible_digits(grid, row, col, & nb_possible, possible_digit) - integer, dimension(9, 9), intent(in) :: grid - integer, intent(in) :: row, col + !! Procedure to create a list of allowed digits in the present empty cell. + integer, dimension(9, 9), intent(in) :: grid !! Sudoku grid + integer, intent(in) :: row !! Row number + integer, intent(in) :: col !! Column number ! These arguments are returned: integer, intent(out) :: nb_possible integer, dimension(1:9), optional, intent(out) :: possible_digit @@ -256,12 +273,12 @@ end subroutine list_possible_digits ! Solver routines !***************************************************************************** - ! Starting from position p, sort the list of empty cells by - ! ascending number of allowed digits. We use a bubble sort: pure subroutine sort(empty_cells, p, n) - integer, dimension(1:81, 1:3), intent(inout) :: empty_cells - integer, intent(in) :: p ! The sort starts at position p (included) - integer, intent(in) :: n ! Number of empty cells in the list + !! Starting from position p, sort the list of empty cells by + !! ascending number of allowed digits. We use a bubble sort algorithm + integer, dimension(1:81, 1:3), intent(inout) :: empty_cells !! + integer, intent(in) :: p !! The sort starts at position p (included) + integer, intent(in) :: n !! Number of empty cells in the list integer :: i integer, dimension(1:3) :: col @@ -284,9 +301,10 @@ pure subroutine sort(empty_cells, p, n) end do end subroutine sort - ! Receives a puzzle grid and solves it: subroutine solve_puzzle(grid) + !! Receives a puzzle grid and solves it. integer, dimension(9, 9), intent(inout) :: grid + !! Input problem grid and returns solved grid. integer, dimension(9, 9) :: grid0 real :: r ! Random number @@ -354,16 +372,13 @@ subroutine solve_puzzle(grid) end subroutine solve_puzzle subroutine cli_solver(grid, file) - ! ****************************************************************** - ! Provides a solution for a puzzle passed by CLI: - ! - ! ```shell - ! $ ./executable test_in_02.txt - ! ``` - ! - ! ****************************************************************** - integer, dimension(9, 9), intent(inout) :: grid - character(*), intent(in) :: file + !! Provides a solution for a puzzle passed by CLI: + !! + !! ```shell + !! $ ./executable test_in_02.txt + !! ``` + integer, dimension(9, 9), intent(inout) :: grid !! Sudoku Grid + character(*), intent(in) :: file !! Filepath logical :: presence presence = .false. @@ -387,11 +402,11 @@ end subroutine cli_solver ! Puzzle generators !***************************************************************************** - ! Grid generation by brute force: in each cycle a digit is added and checked - ! for validity. If the grid becomes invalid, the grid generation - ! is started all over again. subroutine create_filled_grid(grid) - integer, dimension(9, 9), intent(out) :: grid + !! Grid generation by brute force: in each cycle a digit is added and + !! checked for validity. If the grid becomes invalid, the grid generation + !! is started all over again. + integer, dimension(9, 9), intent(out) :: grid !! Sudoku grid real :: r integer :: row, col @@ -430,11 +445,11 @@ subroutine create_filled_grid(grid) end do restart end subroutine create_filled_grid - ! Creates a minimal puzzle. - ! Digits are randomly removed one by one. The process ends when it is not - ! possible anymore to remove a digit while keeping a unique solution. - ! The number of remaining digits is therefore a priori unknown. subroutine create_puzzle_with_unique_solution(grid, nb_empty) + !! Creates a minimal puzzle. + !! Digits are randomly removed one by one. The process ends when it is not + !! possible anymore to remove a digit while keeping a unique solution. + !! The number of remaining digits is therefore a priori unknown. integer, dimension(9, 9), intent(inout) :: grid integer, intent(out) :: nb_empty @@ -485,12 +500,12 @@ subroutine create_puzzle_with_unique_solution(grid, nb_empty) end do end subroutine create_puzzle_with_unique_solution - ! Creates a puzzle by brute force. - ! But we are not 100% sure that the solution is unique - ! (just a "high" probability). subroutine create_puzzle(grid, givens) - integer, dimension(9, 9), intent(inout) :: grid - integer, intent(in) :: givens + !! Creates a puzzle by brute force. + !! But we are not 100% sure that the solution is unique + !! (just a "high" probability). + integer, dimension(9, 9), intent(inout) :: grid !! Sudoku grid. + integer, intent(in) :: givens !! Number of given digits in the puzzle. integer, dimension(9, 9) :: grid0 ! Maximum number of times we try to solve a grid: @@ -552,6 +567,7 @@ end subroutine create_puzzle ! System independent initialization of pseudo-random generator !************************************************************** subroutine initialize_random_number_generator(user_seed) + !! Initialize random number generator with a seed. integer, optional, intent(in) :: user_seed integer, allocatable, dimension(:) :: seed integer, dimension(1:8) :: time_values