Apprendre à générer une grille pleine de Sudoku de façon aléatoire par macro OOoBasic

OooBasic ou StarBasicPartie I : Introduction à OooBasic

PascalTech

Ce tutoriel est la première partie d'une série pour apprendre à générer une grille pleine de Sudoku, de façon aléatoire par macro OOoBasic.

Dans cette première partie, il s'agit de présenter le langage Ooobasic et d'en apprendre les bases.

Commentez

- Titre : Apprendre à générer une grille pleine de Sudoku de façon aléatoire par macro OOoBasic

- Auteur : PascalTech

- Parution : 5 décembre 2016

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2016 PascalTech. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- 1. Préambule

- 2. Stratégie de remplissage de la grille

- 3. Choix de rédaction

- 4. Présentation de l'API OpenOffice.org

- 5. Commandes et déclarations minimum en OOoBasic

- 6. Transcription d'un objectif en code

- 7. Quelques outils de codage et façons de faire utilisés

- 7-A. La boucle de programme ou itération

- 7-B. Les variables

- 7-C. Les déclarations

- 7-D. L'affectation

- 7-E. Les sous-programmes

- 7-F. Les exécutions conditionnelles

- 7-G. La commande rnd()

- 7-H. La commande « Print »

- 7-I. L'outil Aprint

- 8. Un premier code

- 8-A. Détaillons ce programme :

- 8-B. Vient ensuite :

- 8-C. La variable matrice

- 8-D. La boucle comporte deux lignes de commande :

1 - Préambule

Ce tutoriel concerne l'apprentissage de l'algorithmique principalement et, secondairement, l'utilisation de fonctions OOoBasic pour la manipulation d'objets, de variables et de fichiers dans une macro.

Je ne suis pas parti d'une équation que j'ai transcrite en code ; j'ai commencé par définir un ordre d'obtention des chiffres de la grille de sudoku puis j'ai recherché le code correspondant.

Je me suis limité à l'obtention d'une grille complète et délaissé l'effacement des cases nécessaire à l'obtention d'une grille incomplète, le but de l'occupation des joueurs de sudoku étant de compléter cette grille.

Également parce qu'il est très courant de tomber sur des grilles malsaines, dans le sens qu'il est facile d'effacer aléatoirement des cases de sudoku sans tenir compte de la possibilité de résoudre la grille. La résolution de grille tient quelques fois à pas grand chose, c'est là tout l'intérêt du jeu de sudoku.

Je me suis concentré sur le code nécessaire à l'obtention de la grille et j'ai fait l'impasse sur la gestion de fichiers et de feuilles de calcul.

Je programmerai pour un fichier de calcul, cela va de soi, calc en l'occurrence.

2 - Stratégie de remplissage de la grille

L'obtention de l'ensemble de la grille doit être aléatoire afin d'obtenir une grande variété de résultats.

Je programmerai pour obtenir la première case en haut à gauche de la grille, puis les cases de la première ligne du haut jusqu'à la dernière case de droite. Ensuite je passerai à la ligne suivante, jusqu'à la dernière ligne.

Le plus important est de garder en mémoire les contraintes d'interaction entres les différentes cases de la grille de sudoku, qui sont biens connues, que je rappelle ici, pour que ce tutoriel soit complet :

Dans une grille sudoku :

contrainte 1 : chaque ligne comportant 9 cases doit être composée des chiffres 1 à 9

contrainte 2 : chaque colonne comportant 9 cases doit être composée des chiffres 1 à 9

contrainte 3 : chaque bloc comportant 9 cases doit être composé des chiffres 1 à 9

3 - Choix de rédaction

Sans reprendre l'ensemble de l'apprentissage nécessaire au démarrage de la rédaction du code, je liste ici les choix de rédaction, les fonctions et programmes nécessaire au code généré dans ce tutoriel :

- j'écrirai en minuscule ce qui me permet de clarifier le code et de simplifier l'écriture

- j'écrirai en majuscule la première lettre des déclarations, des noms des objets, les lettre majuscules des propriétés, méthodes ou interface(selon l'usage proposé par la documentation et qui permet de les mémoriser facilement, voir les définitions : *)

- je n'utiliserai pas la coutume de mettre des « o » devant chaque nom d'objet, ce qui m'horripile ; je préfère utiliser des noms suffisamment expressifs

- J'utiliserai des noms de variable sur 3 lettres maximum, ce qui permet d'associer leur nom à leur caractère facétieux, volage voir désobligeant

- je rangerai les déclarations d'objets et de variables en début de code, dans la plupart des cas

- je n'utiliserai pas l'appel de Function, que je maîtrise pas

* https://wiki.openoffice.org/wiki/Extensions_development_basic_fr :

4 - Présentation de l'API OpenOffice.org

Cette section introduit les termes :

- Interface

- Module

- Service

- Méthode

- Propriété

S'il n'est pas essentiel de comprendre la différence entre une interface et un service ou ce qu'est un module pour pouvoir écrire des extensions à OpenOffice.org, la compréhension de ces termes aide à correctement interpréter la documentation ainsi qu'à l'introspection des éléments manipulés. Peut-être nous faudra-t-il relire cette section plusieurs fois.

Une interface est la définition d'un ensemble de méthodes (avec leurs arguments) qu'un service implémentant cette interface doit comporter.

Les interfaces sont regroupées en modules pour des besoins de nommage. Toutes les interfaces (et les services) commencent par le nom "com.sun.star" puis vient le nom du module puis celui de l'interface (ou du service).

Une interface fournit l'accès aux propriétés d'un service.

Une propriété est une valeur tandis qu'une méthode définit une action.

Un objet OpenOffice.org peut supporter de nombreux services.

Un objet OpenOffice.org peut supporter un service qui implémente une interface dans laquelle une description de méthode déclare qu'un autre objet OpenOffice.org est retourné.

5 - Commandes et déclarations minimum en OOoBasic

Pour un fichier calc, elles se limitent à :

1. Sub

2. Dim Dok as object

3. Dok = ThisComponent

4. Dim Feuille as object

5. Feuille = Dok.Sheets.getByIndex(0)

6. ...

7. end Sub

le reste étant du code pour l'obtention de la grille sudoku.

Je travaille sur le fichier ouvert, donc je n'ai pas de gestion d'ouverture ou de fermeture de fichier à faire. Attention, bien s'assurer que c'est le fichier dans lequel vous avez créé votre code qui est actif lorsque vous lancez votre macro,sinon il n'y aura pas d'exécution correcte.

C'est la signification de Dok = ThisComponent : le fichier actif.*

Je travaille également sur la première feuille du fichier calc, je n'ai pas à gérer d'autre feuille de calcul.

C'est la signification de Feuille = Dok.Sheets.getByIndex(0). 0 étant le numéro de la première feuille.

J'utilise le nom d'objet « Dok » en respect et en l'honneur du programmateur russe qui l'utilisait dans un programme d'obtention d'une grille de sudoku qui m'a servi de modèle d'apprentissage.

* annexe A, page 859 Marcelly

ThisComponent

Représente l'objet document en cours ; il est en général équivalent à :

1. Dim Document as Object

2. Document = StarDesktop.CurrentComponent

Cependant, si l'EDI est en premier plan, CurrentComponent renverra l'EDI et la macro ne fonctionnera pas, alors que ThisComponent continue à renvoyer l'objet document.

C'est pourquoi ThisComponent est préférable.

Notez que ThisComponent n'est pas une variable, mais un appel de fonction:s'il y a plusieurs documents OpenOffice.org ouverts, elle renvoie le document OpenOffice.org dont la fenêtre est actuellement en avant-plan. C'est pourquoi il est préférable de ne l'appeler qu'au début de la macro et de sauver le résultat dans une variable interne.

6 - Transcription d'un objectif en code

Le cap le plus important à passer, dans votre apprentissage, est la transcription de votre idée de traitement en code : l'algorithmique.

Par exemple, le tirage des chiffres de la grille de sudoku :

(→ signifie : opération suivante)

Je veux tirer au hasard un chiffre de 1 à 9 :

- → je range dans une boîte les 9 chiffres
→ je défini chacune de leur position par un numéro de 0 à 8
→ je tire au hasard un numéro entre 0 et 8 dans un sac
→ j'écris dans une case de la feuille calc le chiffre qui a le numéro tiré
→ j'enlève du sac le chiffre qui a été tiré, pour qu'il n 'apparaisse pas une seconde fois dans la grille sudoku
→ je tire au hasard à nouveau un numéro entre 0 et 8 dans le sac
→ j'écris à nouveau dans une case de la feuille calc le chiffre qui a le numéro tiré, la case étant la suivante à droite de la précédente, tel qu'il a été défini plus haut
→ j'enlève à nouveau du sac le chiffre qui a été tiré, pour qu'il n 'apparaisse pas une seconde fois dans la grille sudoku
→ je tire au hasard à nouveau et pour la troisième fois un numéro entre 0 et 8 dans un sac, …

Dans la suite de ce tutoriel, pour une meilleure compréhension et par convention, j'utiliserai le terme« numéro» pour désigner les cases de la boîte de rangement et le terme « chiffre » pour désigner les valeurs de la grille de sudoku.

Il m'a été aisé de rédiger cette suite d'opérations, car j'ai déjà réalisé la recherche du mode opératoire le plus adapté, après plusieurs essais, et surtout qui peut être transcrit en code.

La démarche de l'algorithmique est la suivante :

- définir un découpage opérationnel du processus

- identifier les outils de codage utilisables pour chaque opération

- rédiger en code chaque opération au fur et à mesure

- reprendre depuis le début s'il y a une impossibilité de rédaction du code

Cela nécessite de connaître les outils de codage ou de rechercher de nouveaux outils utilisés dans des exemples et de comprendre leur fonctionnement puis leur utilisation.

En OOoBasic, il y a 75 modules comportant chacun 6 types(par ordre α : constant group, enum, exception, interface, service, struct) (les interfaces commencent par .X), composés de 3531 méthodes ou propriétés, comportant chacune 6 types(par ordre α : attribute, constant, field, function, property, value) ce qui représente 16572 composants au total (environ, certains composants sont déclarés mais ne sont plus utilisées).

7 - Quelques outils de codage et façons de faire utilisés

Á la lecture de l'exemple précédent, vous voyez que j'ai écrit « à nouveau » en italique ; c'est pour vous préparer à l'écriture d'une boucle.

7-A - La boucle de programme ou itération

C'est parce qu'il est plus intéressant d'écrire un code simple de quelques lignes, qu'une page répétitive de code et aussi parce que les processeurs ne s'ennuient jamais lorsqu'ils font des opérations répétitives.

Quelles sont les opérations répétées ?

...

- → je tire au hasard à nouveau un numéro entre 0 et 8 dans le sac
→ j'écris à nouveau dans une case de la feuille calc le chiffre qui a le numéro tiré, la case étant la suivante à droite de la précédente, tel qu'il a été défini plus haut
→ j'enlève à nouveau du sac le chiffre qui a été tiré, pour qu'il n 'apparaisse pas une seconde fois dans la grille sudoku
…

Cela forme un bloc d'opérations répétitives qui seront inclues dans la boucle.

Le principe de la boucle est que lorsque la dernière opération est effectuée, on reprend l'exécution au début de la boucle, c'est-à-dire à la première opération de la boucle.

L'itération sera effectuée tant que l'objectif n'est pas atteint, dans notre cas, tant que tous les chiffres de 1 à 9 n'ont pas été tirés.

Alors il faut compter le nombre d'exécutions de la boucle. C'est le rôle d'une variable.

7-B - Les variables

Elles prennent des valeurs temporelles, utiles pour l'exécution des opérations, puis sont renseignées à nouveau, ou s'effacent.

Dans mon cas, il me faut une variable qui compte chaque exécution, alors il suffit de la faire progresser d'une unité à chaque exécution, c'est-à-dire, inclure cette progression dans la boucle via une opération d'addition de 1 à la valeur de la variable en cours d'utilisation.

Les variables ne progressent pas forcément d'une unité, il est intéressant par exemple, de sauter une ligne dans un fichier, alors il suffit de faire progresser une variable de 2 unités, ou 3, ou de la faire diminuer pour reculer ou remonter dans un fichier.

Pour une utilisation correcte des variables, il faut déclarer leur type : est-ce un nombre, un texte, une date, une bascule oui/non ?

Dans notre cas, pour le comptage des exécutions de la boucle, ce doit être un nombre.

OOoBasic est assez souple, vous pouvez utiliser une variable sans la déclarer. OOoBasic est assez soupe au lait, si vous ne déclarez pas votre variable et que vous voulez l'utiliser dans différents programmes, vous aurez quelques surprises.

Il est préférable de faire une déclaration de variable, située avant son utilisation. Dans mon cas, j'effectue les déclarations en début de programme.

C'est aussi se préparer à l'apprentissage de langages plus exigeants.

7-C - Les déclarations

A l'intérieur d'un programme, les déclarations se font par l'outil « Dim ».

Si vous voulez utiliser une variable ou un objet dans plusieurs programmes, vous devez les déclarer « Public », c'est-à-dire, comme un lieu accessibles à tout le monde, accessible à tous les programmes, en dehors des programmes dont le programme principal.

Dans un premier temps, j'ai utilisé le déclaratif « Global », cela pourrait être imagé par « mondial », le monde entier peut utiliser mon programme, j'ai été peut-être un peu prétentieux (c'était mon « Hello World »).

Pourquoi je suis passé de déclarations « Dim », privées, à « Public », « locales » ?

Dans la rédaction du programme, je me suis rendu compte qu'une boucle était utile à différents endroits du programme, alors je les ai copiées/collées, puis j'en ai eu marre de faire une opération répétitive, alors j'ai écris cette boucle dans un programme que j'ai appelé depuis différents endroits du programme principal.

La conséquence a été que les variables et les objets utilisés dans le programme principal et les sous-programmes, pour être en adéquation d'état ou de valeur, devaient être connues par les différents programmes, donc être déclarées « Public »*.

* https://wiki.openoffice.org/wiki/FR/Documentation/BASIC_Guide/Scope_of_Variables

7-D - L'affectation

C'est l'opération qui permet :

- d'attribuer un contenu à une variable : valeur, texte, oui/non, ...

- d'attribuer un service ou une propriété à un objet

L'opérateur est le signe : = . Il fonctionne de la droite vers la gauche ; l'opérateur = attribue la valeur (ou autre) située à sa droite, à l'opérande situé à sa gauche.

Dok = ThisComponent : affectation de la propriété « fichier actif » à l'objet Dok.

7-E - Les sous-programmes

L'utilisation de sous-programmes est aussi intéressantes d'un point de vue de l'organisation du travail à effectuer. Il faut être ordonné pour être programmateur.

Un sous-programme correspond à une tâche, c'est intéressant pour la rédaction des opérations nécessaires à votre objectif, mais aussi, d'un point de vue intellectuel.

Lorsque vous travaillez sur un sous-programme, vous n'êtes pas perturbé par les autres éléments de votre programme principal.

Cela correspond aussi à la répartition des tâches et à la spécialisation dans l'organisation du travail.

7-F - Les exécutions conditionnelles

« Si tu me donnes un foret, je pourrai percer le mur ».

« Tant que je n'ai pas atteint l'autre côté du mur, je continue à percer ».

J'ai utilisé les outils d'exécution conditionnelle parce qu'à un moment donné, je devais attendre qu'un état soit atteint pour pouvoir continuer.

Par exemple, tant que l'ensemble des cases de la première ligne n'ont pas été tirées, je ne passe pas au tirage des cases de la deuxième ligne.

Vous remarquerez que j'utilise le présent, c'est-à-dire que la lecture de la condition se fait à l'instant t de l'exécution du programme.

La deuxième condition a été un cas d'écueil lorsque j'effectuais le tirage de la fin de la troisième ligne de la grille de sudoku. J'effectuais un tirage entre 3 chiffres restants qui devaient respecter les 3 contraintes de viabilité de la grille, alors le tirage était recommencé de façon interminable.

Je me suis rendu compte de cet écueil en affichant à l'écran le chiffre tiré.

7-G - La commande rnd()

C'est la commande qui permet le tirage au sort. Cette commande génère aléatoirement un chiffre en 0 et 1 à chaque utilisation. Sa programmation :

1. ...

2. randomize

3. Y = X*rnd()

4. ...

X est une valeur qui permet de « décoller » le résultat obtenu entre 0 et 1, c'est un facteur tout simplement, et donc d'affecter à Y une valeur représentative dans le programme.

La commande randomize() est à déclarer avant l'utilisation de la commande rnd().

Description de ces deux commandes :

http://christianwtd.free.fr/index.php?rubrique=BasFonction04

Bravo Christian, c'est très bien résumé. Un site très intéressant et bien fait.

J'ai ajouté une valeur entre les parenthèses de la fonction rnd(): rnd(sqr(5)) afin d'obtenir une meilleure répartition aléatoire.

Voici les statistiques de cette commande :

Je trouve cette fonction déséquilibrée. Elle a une tendance répétitive, liée à l'instant t du démarrage du programme.

Si vous lancez les tirages dans une boucle, comme je l'ai réalisé, le résultat est homogène. Si vous faites plusieurs exécutions indépendantes, le résultat est aléatoire. Surprenant !

L'autre possibilité est que je ne sache pas l'utiliser.

Voici le programme que j'ai utilisé pour obtenir le graphique ci-dessus :

1. REM  *****  BASIC  *****

3. rem ----- Déclarations ----------------------------------------------------------------------

4. Public document as object

6. Public a as integer

7. Public lim as integer

8. Global x as integer

10. rem ----- Déclarations pour impression ---------------------------------------------------

11. Public col as integer        ' numéro de la colonne en cours pour impression

12. Public lig as integer        ' numéro de la  ligne    en cours pour impression

13. Public compt as integer      ' compteur d'exécution

14. Public col_tt as integer    ' numéro de la colonne en cours pour impression totaux

15. Public lig_tt as integer    ' numéro de la  ligne    en cours pour impression totaux

18. rem ----- Programme ------------------------------------------------------------------------

19. Sub lancement

20. x = 0

21. for u = 0 to 10 ' correspond au facteur de 10 000 boucles : 10 pour 100 000 boucles

22. col = 2

23. lig = 4

24. compt = 0

25. compt_max = 1000

26. for t = 0 to 9

27. for compt = 0 to compt_max-1

28. print_compt

29. Fonction_rnd

30. aprint_a

31. next

32. col = col + 1

33. lig = 4

34. next

35. aprint_graph

36. next

37. end Sub

39. Sub Fonction_rnd

40. randomize

41. lim = 8

42. a = lim*rnd(sqr(5))

43. end Sub

45. rem ----- Impression -------------------------------------------------------------------------

46. Sub print_compt

47. document = ThisComponent

48. Feuille = document.Sheets.getByIndex(0)

49. Feuille.getCellByPosition(0,0).value = u

50. Feuille.getCellByPosition(2,0).value = compt

51. Feuille.getCellByPosition(col,2).value = a

52. end Sub

54. Sub aprint_a

55. Set document = ThisComponent

56. Feuille = document.Sheets.getByIndex(0)

57. Feuille.getCellByPosition(col,lig).value = a

58. lig = lig + 1

59. end Sub

62. Sub aprint_graph

63. col_tt = 14

64. lig_tt = 3 + x

66. document = ThisComponent

67. Feuille = document.Sheets.getByIndex(0)

69. Feuille.getCellByPosition(col_tt  , 2).string = "0"

70. Feuille.getCellByPosition(col_tt+1, 2).string = "1"

71. Feuille.getCellByPosition(col_tt+2, 2).string = "2"

72. Feuille.getCellByPosition(col_tt+3, 2).string = "3"

73. Feuille.getCellByPosition(col_tt+4, 2).string = "4"

74. Feuille.getCellByPosition(col_tt+5, 2).string = "5"

75. Feuille.getCellByPosition(col_tt+6, 2).string = "6"

76. Feuille.getCellByPosition(col_tt+7, 2).string = "7"

77. Feuille.getCellByPosition(col_tt+8, 2).string = "8"

79. Feuille.getCellByPosition(col_tt-1, 3 + x).value = x

81. for col = 2 to 11

82. for lig = 4 to 1003

83. e = Feuille.getCellByPosition(col,lig).value

84. Select case e

85. case 0

86. Feuille.getCellByPosition(col_tt  , lig_tt).value = Feuille.getCellByPosition(col_tt  , lig_tt).value + 1

87. case 1

88. Feuille.getCellByPosition(col_tt+1, lig_tt).value = Feuille.getCellByPosition(col_tt+1, lig_tt).value + 1

89. case 2

90. Feuille.getCellByPosition(col_tt+2, lig_tt).value = Feuille.getCellByPosition(col_tt+2, lig_tt).value + 1

91. case 3

92. Feuille.getCellByPosition(col_tt+3, lig_tt).value = Feuille.getCellByPosition(col_tt+3, lig_tt).value + 1

93. case 4

94. Feuille.getCellByPosition(col_tt+4, lig_tt).value =    Feuille.getCellByPosition(col_tt+4, lig_tt).value + 1

95. case 5

96. Feuille.getCellByPosition(col_tt+5, lig_tt).value =    Feuille.getCellByPosition(col_tt+5, lig_tt).value + 1

97. case 6

98. Feuille.getCellByPosition(col_tt+6, lig_tt).value = Feuille.getCellByPosition(col_tt+6, lig_tt).value + 1

99. case 7

100. Feuille.getCellByPosition(col_tt+7, lig_tt).value = Feuille.getCellByPosition(col_tt+7, lig_tt).value + 1

101. case 8

102. Feuille.getCellByPosition(col_tt+8, lig_tt).value = Feuille.getCellByPosition(col_tt+8, lig_tt).value + 1

103. end select

104. next

105. next

106. x = x + 1

107. end sub

Pour info, voici le code source en C des deux fonctions randomize et rnd de OpenOffice, issu du site opengrok :

http://opengrok.adfinis-sygroup.org/source/xref/aoo-AOO34/main/basic/source/runtime/methods.cxx#3354

3339RTLFUNC(Randomize)
3340{
3341    (void)pBasic;
3342    (void)bWrite;
3343
3344    if ( rPar.Count() > 2 )
3345        OOoBasic::Error( SbERR_BAD_ARGUMENT );
3346    sal_Int16 nSeed;
3347    if( rPar.Count() == 2 )
3348        nSeed = (sal_Int16)rPar.Get(1)->GetInteger();
3349    else
3350        nSeed = (sal_Int16)rand();
3351    srand( nSeed );
3352}
3353
3354RTLFUNC(Rnd)
3355{
3356    (void)pBasic;
3357    (void)bWrite;
3358
3359    if ( rPar.Count() > 2 )
3360        OOoBasic::Error( SbERR_BAD_ARGUMENT );
3361    else
3362    {
3363        double nRand = (double)rand();
3364        nRand = ( nRand / (double)RAND_MAX );
3365        rPar.Get(0)->PutDouble( nRand );
3366    }
3367}

7-H - La commande « Print »

J'utilise beaucoup cette fonction pour voir ce qui se passe dans le programme, pour faire une pause programme, donc une sortie possible en cas d'écriture d'une boucle infinie.

La fonction « Print » affiche dans une boîte de dialogue la valeur d'une variable ou de plusieurs variables et stoppe l'exécution du programme. Selon la réponse choisie, le programme s'arrête ou continue.

7-I - L'outil Aprint

Ce n'est pas une commande OOoBasic. C'est un de mes outils, un sous-programme en fait.

J'appelle Aprint, l'impression dans la feuille de calcul des variables à l'instant t, ce qui permet de rédiger un rapport d'exécution final, mais surtout en cours d'exécution.

Cela m'a permis de déboguer rapidement certaines anomalies de mes programmations.

J'ai regroupé dans un sous-programme, toujours dans la même logique d'économie de travail et d'organisation, l'impression (l'écriture dans la feuille de calcul) des variables du programme à un instant t :

1. Sub aprint

2. Dim Dok as object

3. Set Dok = ThisComponent

4. Dim Feuille as object

5. Feuille = Dok.Sheets.getByIndex(0)

9. Dim col as integer

10. Dim lig as integer

12. col = 5

13. lig = 3

16. Feuille.getCellByPosition(col, lig).string = "Num()"

17. col = col + 2

19. Dim i as integer

20. Dim Num(8) as integer

22. for i = 0 to 8

23. Feuille.getCellByPosition(col, lig).value = Num(i)

24. col = col + 1

25. next

27. end Sub

Le système fait la différence entre le programme principal et ce sous-programme lors du lancement de ce dernier car il ne se nomme pas « main » ( principal) et n'est pas situé en première position dans l'éditeur.

Aide en ligne de OpenOffice : Un clic sur l'icône Exécuter le programme BASIC de la barre de macro permet d'exécuter le programme à partir de la première ligne de l'éditeur Basic. Le programme exécute le premier Sub ou Function puis l'exécution du programme s'interrompt. L'instruction Sub Main n'est pas prioritaire sur l'exécution du programme.

8 - Un premier code

Vous retrouvez dans le programme ci-dessus, 4 des outils de codage et façons de faire que je vous ai présentés ci-dessus :

1. la boucle

2. les variables

3. la déclaration

4. l'affectation

8-A - Détaillons ce programme :

1. Sub aprint

2. Dim Dok as object

3. Dok = ThisComponent

4. …

Vous le savez , il s'agit des déclarations minimum en OOoBasic pour travailler avec une feuille de calcul. Vous retrouverez end Sub en fin de programme, évidemment.

1. …

2. Dim Feuille as object

3. Feuille = Dok.Sheets.getByIndex(0)

4. …

Je déclare ensuite que l'objet Feuille puis déclare qu'elle représente la première (numéro : 0) feuille de calcul de l'objet Dok, le fichier actif.

Attention : toujours penser à démarrer la numérotation par 0. Afin d'avoir une uniformité intellectuelle de numérotation, je démarre aussi la numérotation des boucles par 0, ce qui évite des maux de tête.

Afin de simplifier cette description de programme, j'ai regroupé les déclarations et les affectations dans la même partie du code.

1. …

2. Dim col as integer

3. Dim lig as integer

5. col = 5

6. lig = 3

7. …

Donc il y a deux déclarations correspondant aux deux variables qui vont représenter la ligne et la colonne permettant de trouver la cellule de la feuille de calcul, dans laquelle je veux écrire un nom ou une valeur de variable.

Vous remarquerez que je ne me suis pas cassé la tête pour trouver un nom de variable représentant le numéro de colonne et de ligne.

Puis, j'affecte une valeur à chacune des variables qui correspondent à la cellule : F4, dans la quelle je souhaite démarrer la rédaction du rapport d'exécution, à chaque exécution.

1. …

2. Feuille.getCellByPosition(col, lig).string = "Num()"

3. …

J'appelle la méthode .getCellByPosition(colonne, ligne) de l'interface .XcellRange*, que j'applique à l'objet Feuille, représentant la feuille de calcul, dans notre cas.

* https://www.openoffice.org/api/docs/common/ref/com/sun/star/table/XCellRange.html

« Description : provides access to the cells or to Sub-ranges of a cell range. »

L'interface n'a pas notion qu'il s'agit d'une feuille de calcul, elle autorise l'accès à une cellule d'un groupe de cellules.

C'est ce qui m'émerveille dans la programmation objet, cet espèce de dilettantisme, d'anonymat plutôt confortable, il faut le dire.

J'aurais utilisé la méthode .getCellByName(Référencedecellule), qui ne me permet pas d'utiliser de variable représentant la position de cellule, par exemple :

Feuille.getCellByName(A1) : la première cellule en haut à gauche de la feuille de calcul.

C'est assez perturbant d'utiliser cette méthode ,car la numérotation des lignes commence par 1, ce qui est habituel lorsque l'on utilise un tableur mais qui devient inhabituel lorsque l'on démarre l'étude des macros.

Ensuite, je dois déterminer ce que je veux écrire dans cette cellule : quel est le contenu cette cellule ?

Est-ce une valeur ? Une formule ? Quel est son type ? Est-ce une valeur d'erreur ?

Le contenu d'une cellule est géré par l'interface .Xcell :

* https://www.openoffice.org/api/docs/common/ref/com/sun/star/table/XCell.html

« Description : provides methods to access the contents of a cell in a table. »

En premier, ne pas oublier le point « . »entre la méthode et son type.

Dans mon cas , je veux écrire dans la cellule, un titre qui informera du nom des variables, un texte donc (string) :

Feuille.getCellByPosition(col, lig).string

Je viens de définir entièrement la cellule dans laquelle je veux écrire, et j'ai déterminé le genre de contenu que j'écrirai. Il me reste à lui affecter [une valeur, un texte,oui/non,...], dans mon cas un texte :

Feuille.getCellByPosition(col, lig).string = "Num()"

C'est un texte, alors il faut le déclarer entre guillemets : " … " . L'éditeur reconnaît bien que c'est un texte car il est affiché en rouge.

1. …

2. col = col + 2

3. …

Pour des questions de présentation, je souhaite sauter deux colonnes de cellules dans mon rapport, alors j'ajoute la valeur 2 à la valeur de la colonne à cet instant t.

J'aurais pu écrire :

col = 7

puisque sa valeur précédente était 5, mais, j'ai prévu d'utiliser ce sous-programme plusieurs fois, correspondant à différentes cellules donc à différentes valeur de colonne, alors j'effectue une addition « relative » : j'ajoute la valeur 2 à la valeur temporaire de col.

Affecter la valeur 7 à la variable col est similaire à un déplacement absolu de l'index dans la feuille de calcul.

Ajouter la valeur 2 à la valeur temporaire de col est similaire à un déplacement relatif de l'index dans la feuille de calcul. L'index passe à la cellule : H4.

8-B - Vient ensuite :

1. …

2. Dim i as integer

3. …

C'est une déclaration de variable de type entière. Cette variable est utilisée dans la déclaration de la boucle et effectuera le comptage du nombre de boucles effectuées.

Déclaration de la boucle :

1. for i = 0 to 8

2. …

3. next

Le commande for...next se déclare sur deux lignes qui encadrent les commandes à répéter.

Le fonctionnement est le suivant : l'initialisation de la boucle de programme est déclarée par la commande : for i = 0 …

Puis, à chaque fois que l'exécution du programme arrive à la commande next , i est augmenté de la valeur 1, jusqu'à atteindre le maximum fixé par la commande : for … to 8 .

Ce qui nous fait au total : 9 valeurs correspondant à la totalité des numéros (de 0 à 8) de position dans la boîte de rangement des 9 chiffres.

La variable i a une double fonction :

1. compter le nombre d'exécutions ;

2. lister les valeurs des numéros de position dans la boîte de rangement.

Comment gérer dans le programme, les numéros 0 à 8 de position dans la boîte de rangement ?

Par 8 variables ? C'est faisable.

Par une matrice : une variable matrice. C'est plus simple à gérer et plus « préhensible ».

https://wiki.openoffice.org/wiki/FR/Documentation/BASIC_Guide/Arrays

8-C - La variable matrice

La déclaration de la variable matrice :

1. …

2. Dim Num(8) as integer

3. …

Vous voyez apparaître des parenthèses à la suite du nom de la variable, entre lesquelles est inscrit une valeur.

Cette valeur représente le nombre maximum de zones mémoires d'enregistrement à l'instant t de la matrice : 8.

C'est-à-dire :

0, 1, 2, 3, 4, 5, 6, 7, 8 : nous avons bien 9 zones mémoires qui correspondent aux 9 positions attendues.

Une variable matrice est définie comme ceci :

- sa dimension est définie par la valeur d'index de la dernière zone mémoire, entre parenthèses, à la suite de son nom

- ses zones mémoires sont accessibles par leur valeur d'index

- la valeur du premier index est 0

L'affectation d'une variable matrice se rédige comme ceci :

Num() = array(9,8,7,6,5,4,3,2,1)

Indexes de la matrice : 0, 1, 2, 3, 4, 5, 6, 7, 8

Le terme array signifie matrice. Le nombre de valeurs saisies doit correspondre au nombre déterminé lors de la déclaration de la variable, voir ci-dessus.

L'accès à une zone mémoire de la matrice, se fait par le numéro d'index :

Num(1) = 0

alloue la valeur 0 à la deuxième case de la matrice :

Num() = array(9,0,7,6,5,4,3,2,1)

Une variable simple peut prendre une infinité de valeur au cours de l'exécution d'un programme mais une seule à l'instant t.

Une variable matrice peut prendre une infinité de valeur au cours de l'exécution d'un programme mais autant que sa déclaration le permet à l'instant t.

Je pourrais déclarer 9 variables simples à la place de la variable matrice, mais déjà, je dois rédiger 9 déclarations, donc 9 lignes de programme supplémentaires. Imaginez si je souhaitais enregistrer 150 valeurs !

8-D - La boucle comporte deux lignes de commande :

Dans la première, je veux écrire les valeurs, donc (value), de la variable Num() à chaque exécution :

Feuille.getCellByPosition(col, lig).value = Num(i)

Num(i) est écrit en noir dans l'éditeur, donc c'est l'appel d'une entité connue par le programme et non plus un texte qui sera enregistré dans une cellule de la feuille de calcul.

C'est ici que l'on retrouve la deuxième fonction de la variable i : lister les valeurs de position dans la boîte de rangement.

À chaque exécution de la boucle, i prend une valeur qui va progresser de 1, ce qui permettra de lister l'ensemble des cases de Num(), de 0 à 8 par l'exécution des boucles de programme jusqu'à son terme.

Cette commande fait appel également aux variables col et lig .

Lors de la première exécution de la boucle, les valeurs de ces variables sont celles correspondantes à l'affectation précédente :

col = 5

lig = 3

Si je ne fais pas évoluer l'une de ces variables, les 9 valeurs de Num(i) vont s'enregistrer dans la même cellule. Alors je ne verrai rien !

C'est l'intérêt de la deuxième ligne de commande de la boucle :

col = col + 1

Comme je l'ai expliqué ci-dessus, il s'agit d 'un déplacement relatif de l'index dans la feuille de calcul.

Après chaque enregistrement via la commande de la première ligne de la boucle, la variable col représentant la valeur de colonne de l'enregistrement glisse d'un pas vers la droite : H4, I4, J4,K4, L4, M4, N4, O4, P4.

Ce qui me permet d'obtenir le résultat suivant :

Enfin, la commande :

…

end Sub

permet de déclarer la fin du programme.

Aide en ligne de OpenOffice :

Instruction end [Exécution]

Indique la fin d'une procédure ou d'un bloc.

Syntaxe :

end, end Function, end if, end Select, end Sub

Paramètres :

Utilisez l'instruction end comme suit :

Instruction

end : non obligatoire, mais peut être saisie n'importe où dans une procédure afin de mettre fin à l'exécution du programme.

end Function : marque la fin d'une instruction Function.

end if : marque la fin d'un bloc if...Then...else.

end Select : marque la fin d'un bloc Select Case.

end Sub : marque la fin d'une instruction Sub.