raphnet.net banner

RetroChallenge, mars 2019

twitter@raphnetlabs
Contenu

Sommaire

Dans l'édition précédente (RC2018/09) je me suis initié à la programmation sur SNES mais je n'ai fait qu'un testeur de manette.

Pour cette édition de mars 2019 du RetroChallenge, afin de ne pas tout oublier ce que j'ai réussi à apprendre sur l'assembleur 65816 et l'architecture du SNES, j'ai l'intention de mettre le tout en pratique en réalisant un jeu simple. D'ailleurs, faire un jeu pour SNES, ça fait très longtemps que j'y pense!

Je ne suis pas certain pour le moment du jeu que je réaliserai, mais j'aimerais bien qu'il exploite les boutons supplémentaires du NTT Data Keypad, puisqu'il n'y a pas assez (voir aucun, selon que JRA PAT peut être considéré un jeu ou pas) de jeux supportant cette manette:

La manette NDK10

La manette NDK10




goto top


Section 1: Outils de développement

Pour une fois, prendre le temps

La dernière fois que je me suis entraîné à programmé sur SNES, j'ai pris une approche « apprendre-au-vol, que-le-minimum, aller-très-vite ». Cela a fonctionné, oui, mais pas sans obstacles.

Mais cette fois, je prends la programmation pour SNES très au sérieux. J'ai donc imprimé ce qui semble être jusqu'à présent un excellent ouvrage de référence sur le CPU 65816. J'ai passé quelques heures à lire au sujet de son architecture, à découvrir ces multiples modes d'adressage et à apprendre quels sont les limitations et les pièges à éviter. Cela m'a beaucoup servi ces derniers jours, je ne regrette pas.



Environnement de développement et outils

Je préfère de loin travailler sous Linux, mais cela rends la vie du programmeur pour SNES plus difficile. Plusieurs outils et compilateurs sont distribués au format .EXE (et souvent même pas open source). Je pourrais employer Wine ou une machine virtuelle, mais ce n'est pas idéal. Il en résulte que mon jeu d'outils de travail est probablement un peu atypique.

Langage de programmation

Je sais qu'il y a moyen d'utiliser le langage C pour développer sur SNES et qu'il existe des librairies pour simplifier certaines choses, mais je préfère continuer d'utiliser l'assembleur pour le moment. Comme je suis en apprentissage, je pense qu'il vaut mieux être proche du matériel. Ainsi, comme rien n'est caché, il est plus facile de comprendre, et ultimement, de tout maîtriser.

L'assembleur dont je me sers est WLA-DX. J'ai appris à m'en servir lors de mon projet précédent (test de manette) et plusieurs tutoriels de programmation SNES en ligne emploient WLA-DX.


Graphiques

« Tilesets »

J'utilise GIMP pour dessiner les tilesets. Configurer une grille visible de la bonne taille aide beaucoup. Il faut aussi se servir du mode de couleur indexé et bâtir une palette manuellement.



J'enregistre le tilesets dans une seule image .PNG.


« Tilemaps »

Les tuiles (dans le tileset) sont de petites images de taille fixe auquel il est possible de faire référence par un numéro. Un tilemap est un tableau bidimensionnel qui précise à quel endroit chaque tuile doit apparaître dans l'écran. Dans ce projet, la zone visible de l'écran occupe 32x28 tuiles, ou 245x224 pixels (les tuiles font 8x8).

Pour construire un tilemap, j'utilise un outil nommé Tiled. Il est gratuit, open-source et fonctionne sous Linux. Parfait.

J'importe le fichier PNG du tileset dans Tiled, et je place ensuite les tuiles dans la grille. Ce qui est très pratique, c'est que Tiled détecte quand le fichier PNG du tileset est changé (suite à une retouche dans gimp, par exemple) et le charge à nouveau automatiquement. Le résultat est donc instantané.

J'aime bien travailler avec les deux outils simultanément, chacun dans son propre écran: (gauche: Gimp, Droite: Tiled)




Conversion des données

Naturellement, la console SNES ne traite pas directement les fichiers .PNG ni les fichiers .TMX de Tiled. Mais j'ai des outils pour faire la conversion.

Conversion des PNG

Afin de convertir les tileset au format PNG vers le format binaire utilisé par la console, j'utilise png2snes (Voir aussi mon fork sur GitHub). L'outil fonctionne en ligne de commande, il est donc facile de l'appeler depuis un script. J'y fais appel depuis le Makefile de mon projet, ainsi, quand je modifie une image, la conversion est refaite automatiquement lors de la prochaine compilation.

Voici un exemple:
./png2snes -v --bitplanes 4 --tilesize 8 --binary tilemaps/main.png --output=main
L'extrait ci-dessus lit le fichier main.png et génère deux fichiers: main.cgr (la palette) et main.vra (les donnés d'image). Les deux fichiers sont inclus depuis le code source à l'aide de la directive .incbin de l'assembleur.

Conversion du Tilemap

Tiled peut exporter le tilemap en format .CSV. Comme cela peut se faire en ligne de commande, cela s'automatise facilement:
tiled tilemaps/grid.tmx --export-map grid.csv
C'est un début (CSV est bien plus simple qu'un fichier XML, ce que sont réellement les fichiers .TMX de Tiled) mais ce n'est pas ce que le matériel du SNES exige. Pour passer de ce format CSV à un format binaire compris par la console, j'ai créé un outil en C:
csv2bin/csv2bin title.csv title.map
Cela génère le fichier tilemap.map qui est alors inclus par le code source (avec .incbin). Ici encore, la conversion est gérée par le Makefile du projet. Il suffit d'appuyer sur le bouton enregistrer dans Tiled et tout le nécessaire sera fait automatiquement à la prochaine compilation.



Éditeur pour le code

J'utilise déjà VIM pour presque tout, alors il est naturel de l'utiliser pour le développement SNES aussi.

J'aime avoir de la couleur, mais par défaut il n'y a pas de coloriage syntactique pour l'assembleur 65816. Mais j'ai trouvé un dépôt git contenant les fichiers de règles de syntaxe nécessaires pour le développement snes (65816, SuperFX et SPC700), exactement ce qu'il me fallait: vim syntax highlighting for 65816, SuperFX and spc700 assembly

Bien, bien!:




Faire rouler le code

Émulation

J'utilise presque tout le temps bsnes-plus, une version de bsnes spécialisée pour le débogage. J'ai contribué au projet au cours du Retro-challenge précédent en y ajoutant le support pour la manette NTT Data Keypad. C'est bien, je vais en avoir besoin. Vous aussi d'ailleurs, si vous voulez essayer mon jeu. (Avec le temps il y aura d'autres émulateurs capables d'émuler cette manette. Il me semble avoir lu que byuu ajouterait cela dans la prochaine version d'Higan, mais je n'arrive plus à trouve le tweet où il en était question...)

Tel que décrit, bsnes-plus est bien équipé pour le développement. Il est possible d'inspecter le contenu de la mémoire, d'exécuter le programme pas à pas, de regarder ce que contiennent les registres du PPU, et ainsi de suite.

J'ai une cible spéciale dans mon Makefile nommée run qui démarre automatiquement le ROM dans bsnes-plus, ce qui est pratique. Le menu System -> Reload dans bsnes-plus permet de charger un nouveau ROM sans perdre les fenêtres de débogage déjà ouvertes. Excellent!




Sur le vrai matériel!

Bien sûr, le code doit pouvoir fonctionner sur le vrai matériel. Le Super Everdrive que j'ai acheté de krikzz il y a quelques mois rend cela possible:

Everdrive + SD Card

Everdrive + SD Card



Tester dans bsnes-plus est rapide et facile, mais essayer sur la console de temps en temps est très important. Même si bsnes est un émulateur dont le fonctionnement est très fidèle à la console d'origine, il faut se méfier. Si jamais mon jeu cesse de fonctionner et que je n'ai pas essayé sur la console depuis plusieurs semaines, il pourrait être difficile de trouver quelle modification est en cause. (Cela est vrai pour tout développement fait dans un émulateur, j'en sais quelque chose. J'ai eu ce genre de problème en développant des jeux dans DOSBox...)

Mon premier test

Mon premier test

Plus tard: Test d'affichage de la grille

Plus tard: Test d'affichage de la grille


goto top


Section 2: Décision du jeu, énonciation des buts

J'avais quelques idée pour le jeu, mais je n'était pas certain de ce que j'allais faire. Mais j'ai reçu une suggestion par Twitter (de @Shadoff_d) de faire un jeu de Sudoku. J'ai trouvé que c'était une bonne idée:

Alors c'est décidé, je fais un jeu de Sudoku! Maintenant, énonçons des buts: C'est assez je crois. Plusieurs de ces tâches d'apparence facile ne le seront pas pour moi en raison de mon inexpérience en assembleur 65816. (Ah si c'était du 8088 ce serait une autre histoire...)

J'ai commencé à mettre en place mon environnement de développement et à travailler sur le jeu samedi après midi, et dimanche j'avais un pilote fonctionnel pour le keypad (ok, je me suis basé sur mon projet précédent pour cette partie) et un début d'écran titre. J'avais aussi le code en place pour dessiner la grille à l'écran à partir des données contenues dans un tableau de 81 éléments (9x9) représentant l'état du jeu.

L'écran titre fonctionne. Lorsqu'on appuie sur START, l'écran fait une transition vers le noir, puis l'écran avec la grille apparaît progressivement. Normalement j'attendrais la fin pour ce genre de chose, mais quand j'ai vu à quel point c'était facile, je n'ai pas su résister. Il suffit d'écrire une valeur entre 0 et 15 à l'adresse $2100 (INIDISP) et l'effet est immédiat. Très pratique!

Voici quelques images du jeu dans son état actuel:



La grille n'est pas centrée, car je pense utiliser l'espace à droite. Je mettrai peut-être un chronomètre, et peut-être des infos sur ce que font les boutons (par exemple: Y pour effacer, B pour placer un numéro sûr, A pour placer un essai?). Ce sont des choses à expérimenter.

La prochaine chose que je souhaite faire est rendre la grille interactive. Mais j'ai besoin d'un curseur, et donc d'un sprite. Alors maintenant je dois donc apprendre comment les sprites fonctionnent sur SNES :-)

goto top


Section 3: Utilisation d'un sprite pour le pointeur

Le document Qwertie's SNES Documentation est une bonne référence sur le fonctionnement des graphiques sur SNES. Une lecture attentive m'a fourni ce qu'il fallait savoir pour utiliser les sprites.

Il faut:

Disposer les images de sprites en VRAM

Le document de Qwertie mentionné ci-haut explique que les sprites sont un assemblage de petites tuiles 8x8 et qu'il doit y avoir un espace de 16 tuiles du début d'une ligne à l'autre. Cela veut dire que je peux utiliser png2snes comme je le fais déjà pour les arrière-plans, en mode 8x8, couleurs 4 bit (16 couleurs), à condition que l'image .png source fasse exactement 128 pixels de large.



Taille des sprites et origine en mémoire

Les trois bits les moins significatifs du registre 8-bit $2101 (OBSEL) permettent d'indiquer à quel endroit les tuiles sont placées en mémoire vidéo (VRAM). 1 bit vaut 16 kilo-octet, les emplacements possibles sont donc: $0000, $4000, $8000, $C000. J'ai déjà des tuiles et des tilemap au début de la mémoire vidéo, alors j'ai écrit une valeur de 2, ce qui correspond à $8000 (32K) pour sauter par dessus tout ça.

Les bits 7 à 5 permettent de choisir deux tailles pour les sprites. Chaque sprite peut être de deux grandeurs: Petite ou large (contrôlé par une table en mémoire, démontré plus bas). Ici, ce à quoi correspond les tailles dites 'petites' et 'larges' et défini:

J'ai utilisé une valeur de 5, afin d'avoir des sprites 32x32.

Palette

Un total de 8 palettes différentes (16 couleurs chaque) peut être placé en mémoire CGRAM à partir de l'adresse $80. En modifiant les attributs d'objets, il est possible d'avoir plusieurs sprites à l'écran partageant les mêmes données graphiques source (même dessin) mais s'affichant de couleurs différente. Pour mon jeu, je n'utilise qu'un sprite et une seule palette est suffisante.

Bsnes-plus contient un visualiseur de palette. Voici la palette actuelle du jeu. La bande centrale est la palette pour les sprites.



OAM (Object attribute memory)

La console SNES contient plusieurs espaces mémoire: Cette dernière zone, nommée OAM, contient une table de 128 entrées détaillant quelles sprites doivent apparaître dans l'écran, et à quel endroit. D'autres attributs sont également présent: La taille (petite ou grande), le numéro de palette, la priorité, le numéro de la tuile d'origine, inversion horizontale/verticale.

Bref, pour mon jeu très simple, je n'ai qu'à m'occuper de la première sprite et mettre à jour son emplacement (X/Y) en l'écrivant dans la OAM.

Le sprite viewer de bsnes-plus est très pratique pour voir ce que contient la table, particulièrement lorsque ça ne fonctionne pas comme prévu.



Après quelques problèmes, j'avais un pointeur et il était possible d'insérer des chiffres. J'ai donc pu m'amuser à terminer un puzzle avec le jeu pour la première fois!


goto top


Section 4: Problèmes sur le vrai matériel

J'ai continué à améliorer le jeu, à modifier les graphiques et à tester avec bsnes-plus. Puis j'ai voulu essayer le jeu qui était à présent très jouable sur la console. Mais surprise! Le sprite ne fonctionnait pas...

À ce moment dans le développement du jeu, le pointeur utilisé dans la grille apparaissait aussi dans le coin de l'écran titre. Mais pour une raison alors inconnue, il n'apparaissait pas sur la vrai console. Je me suis demandé quel changement avait causé cela. J'avais fait beaucoup de modifications... (je n'ai pas écouté mon propre conseil: Tester sur le vrai matériel, et souvent!).

Après plusieurs essais, j'ai compris que les sprites ne fonctionnait pas depuis le début. J'avais 127 sprites placées dans le coin de l'écran à la position 0,0. Il y a des limites au nombre de sprite total ou nombre de sprite par ligne que le SNES peut afficher, mais ce n'est pas très bien documenté (ou je comprends mal, ce qui est fort possible). Le comportement du système lorsque ces limites sont dépassées n'est sans doute pas parfaitement reproduit par l'émulateur.

Lorsque j'ai modifié le code pour que les sprites/objets inutilisés soient placés hors de l'écran, le curseur est devenu visible.

Sprite manquant

Sprite manquant

Plus tard: Sprite présent!

Plus tard: Sprite présent!



Ayant réussi à faire fonctionner les sprites même sur la console, j'ai fêté cette petite victoire en terminant un puzzle:

Première partie sur console

Première partie sur console


goto top


Section 5: Validation des coups

J'ai d'abord fait en sorte de ne pas permettre au joueur d'écraser les chiffres faisant partie du puzzle initial.

Ensuite je voulais que le jeu empêche le joueur de faire un coup qui n'est pas dans les règles. L'algorithme pour vérifier s'il est possible d'écrire un chiffre dans une case est le suivant: Facile! Mais étant donnée une case X,Y et un chiffre J à insérer, il faut faire des boucles et accéder aux "voisins" de colonne, rangée et de groupe. Et pour chaque cellule à examiner, il faut en calculer l'adresse mémoire. (L'état du jeu est stocké dans un tableau 81 mots de 16 bits).

J'ai jugé qu'il serait plus facile d'écrire un programme en C générant pour chaque case du jeu la liste des adresses des voisins à considérer.
void computeNbrs(int x, int y)
{
	int X, Y, i, j;

	// Same row
	for (X=0; X<x; X++)
		outputNeighbor(X,y);
	for (X=x+1; X<GRID_SIZE; X++)
		outputNeighbor(X,y);

	// Same column
	for (Y=0; Y<y; Y++)
		outputNeighbor(x,Y);
	for (Y=y+1; Y<GRID_SIZE; Y++)
		outputNeighbor(x,Y);

	// Same cell AND not already output above
	for (Y = (y/3)*3, j = 0; j < 3; j++,Y++) {
		for (X = (x/3)*3, i = 0; i < 3; i++,X++) {
			if (Y != y && X != x) {
				outputNeighbor(X,Y);
			}
		}
	}
}
Le programme en C génère un fichier .ASM de ce genre:

_nbors_0_0: .dw $02, $04, $06, $08, $0a, $0c, $0e, $10, $12, $24, $36, $48, $5a, $6c, $7e, $90, $14, $16, $26, $28,
_nbors_1_0: .dw $00, $04, $06, $08, $0a, $0c, $0e, $10, $14, $26, $38, $4a, $5c, $6e, $80, $92, $12, $16, $24, $28,
...
_nbors_8_8: .dw $90, $92, $94, $96, $98, $9a, $9c, $9e, $10, $22, $34, $46, $58, $6a, $7c, $8e, $78, $7a, $8a, $8c,

neighbor_list:
	.dw _nbors_0_0, _nbors_1_0, _nbors_2_0, _nbors_3_0, _nbors_4_0, _nbors_5_0, _nbors_6_0, _nbors_7_0, _nbors_8_0,
	...
	.dw _nbors_0_8, _nbors_1_8, _nbors_2_8, _nbors_3_8, _nbors_4_8, _nbors_5_8, _nbors_6_8, _nbors_7_8, _nbors_8_8,
Pour obtenir le pointeur vers la liste de voisins d'une case en particulier, le code tournant sur la console n'a qu'à lire le mot de 16 bit correspondant de neighbor_list et faire une série d'accès indirects, en comptant jusqu'à 20.
	; Get the pointer to the list of neighbors for the designated cell
	lda neighbor_list, Y
	sta dp_indirect_tmp1

	ldy #0
@checknext:
	lda (dp_indirect_tmp1),Y    ; Load offset for neighbor
	tax                         ; Move the offset to X to use it
	lda griddata, X             ; Load the value at this position
	and #$FF
	cmp gridarg_value           ; Check if it is the value we are checking
	beq @foundit                ; Yes? Then it is not unique. Can't put this value in this cell.
	iny                         ; Advance to next neighbor in list
	iny
	cpy #20*2
	bne @checknext

	; All neighbors checked, no match found
@finished:
	; return with carry clear
	clc
	...
	rts

@foundit:
	; TODO ? Perhaps remember *where* we found it to show the user why he can't place it here?

	; return with carry set
	sec
	...
	rts
Je crois que c'est beaucoup plus simple ainsi, et probablement assez rapide en exécution!

goto top


Section 6: Indices et suggestions

Vous avez remarqué le bouton bleu (X) nommé Hint dans les screenshots? Ce bouton permet d'obtenir un suggestion. Appuyer une première fois déplace le curseur jusqu'à une case ne pouvant accepter uniquement un chiffre.

Une fois le curseur au dessus de la case suggérée, appuyez une nouvelle fois insère automatiquement le bon chiffre. Les puzzles les plus simples peuvent être complètement résolus en appuyant à répétition sur X:



Pour le moment, ce qui est fait est très simple. Le code regarde chaque case libre et compte combien de coups légaux sont possibles à cet endroit. Si une case avec un seul coup possible est trouvée, c'est elle que le jeu suggère.

Je compte améliorer cette fonction un peu en détectant aussi les cas où un chiffre ne peut qu'apparaître à un seul endroit:

goto top


Section 7: Les puzzles

Les puzzles sudoku ne sont pas générés par la console (Désolé). J'utilise plutôt un générateur de sudoku nommé qqwing fonctionnant en ligne de commande. Quatre niveaux de difficulté sont disponibles. J'ai fait un petit script qui en génère 100 de chaque sorte:
#!/bin/bash
N_PUZZLES=100

function generatePuzzles
{
			echo "Level: $1..."
					qqwing --generate $N_PUZZLES --one-line --difficulty $1 > $1.txt
}

echo "Generating puzzles..."

generatePuzzles simple
generatePuzzles easy
generatePuzzles intermediate
generatePuzzles expert
Voici un court extrait d'un des fichiers générés (simple.txt). Chaque ligne correspond à un puzzle et les cases vides sont représentés par des points:
27....95.3..76.....8629..37...6...............4.....285.........684...9.7..9...62
....8....6.....5...71...6...9...7.......35894.53....71.....4.63.39......4.....1.8
47..5....9.6...............2...3...6.6.8.4.798..2..35.....6......8..7.4.3495.8.6.
........8...........5...21..28.9.5....36..1..9.15.3.6.5.9481.3.....3.4....6..5...
9.1....72.......65...17.....15.....9...325.1....8....6...913........7.8..2...6..7
J'ai créé un outil en C qui passe de ce format texte à un format binaire simple, où chaque case correspond à un octet de valeur 0 à 9 (0 pour les cases vides). Il serait possible de mettre deux chiffres par octet, et même de compresser les donnés, mais je n'ai pas encore de raison pour le faire. (je ne manque pas d'espace).
./puzzletxt2bin simple.txt simple.bin
Chaque collection de 100 puzzles est ensuite incluse depuis l'assembleur avec la directive .incbin.

Avec cette petite collection de 400 puzzles en ROM, il était temps de permettre à l'usager d'y accéder.

Cela a été un peu long, car j'ai créé un système pour afficher du texte, généralisé le concept de pointeur qui se déplace, de sorte que le pointeur en jeu et le pointeur dans les menu est contrôlé par le même code.

Voici le résultat:

goto top


Section 8: Première version du ROM

Voici une première version que vous pouvez essayer! Il vous faudra cependant un émulateur supportant la manette NTT Data Keypad, ou sinon une vraie manette physique et un moyen de faire tourner le ROM sur votre SNES...

Caractéristiques de cette version: Téléchargement: super_sudoku_v0.1.sfc (256K)


goto top


Section 9: Nouveaux buts

Les choses se sont plutôt bien passées, mais surtout, j'ai eu beaucoup de temps pour travailer sur le jeu. La deuxième fin de semaine de RC2019/03 se termine et j'ai atteint tout mes objectifs. J'aurais peut-être dû être un peu plus ambitieux:

Il n'y a qu'un solution à ce petit problème: Se donner de nouveaux buts! Alors les voici:

Voilà, alors la semaine prochaine, j'aurai probablement réalisé au moins un de ces nouveaux objectifs.

goto top


Section 10: Conception d'un circuit-imprimé pour la cartouche

Un de mes nouveaux buts est de fabriquer une cartouche. J'ai cherché en ligne pour des options mais je n'ai rien trouvé qui corresponde exactement à mes besoins:

J'ai donc décidé de concevoir mon propre circuit. Bon, j'avoue que j'ai peut-être abandonné mes recherches un peu rapidement car j'avais vraiment envie d'essayer de faire mon propre circuit. Mais j'ai quand même commandé des cartes non idéales (fini HASL plutôt qu'en or et sans chanfrein, pour ne citer que deux problèmes) au cas où je ne réussirais pas à faire fonctionner mon design à temps.


Premier volet: Dimensions de la carte

J'ai ouvert une cartouche (que ces vis soient damnés, je ne trouve plus mes tournevis spéciaux) et effectué une série de mesures avec un pied à coulisse numérique. Je crois bien que le concepteur travaillait en millimètres car les mesures arrivent généralement très prés de valeurs (ou demie valeurs) exactes en unités métrique. J'ai donc arrondi certaines mesures en me fiant à mon jugement et intuition.




Voici le dessin que j'ai réalisé:


J'espère que tout est exact. Mais lorsque j'ai imprimé mon dessin à l'échelle et placé le circuit de référence par dessus, tout s'alignait bien. J'ai donc confiance que mon circuit pourra être installé dans un boîtier de jeu standard sans problème.

Circuit placé par dessus le dessin

Circuit placé par dessus le dessin




Deuxième volet: Schéma et circuit imprimé

Je fabrique une cartouche de type « LoRom ». Avant d'avoir programmé pour le SNES, je n'avais aucune idée de quoi il s'agissait. Mais à présent que je sais que les banques de 00 à 3F sont en deux parties (0000-7FFF: Zone système [WRAM, I/O], 8000-FFFF: ROM), je comprends pourquoi la ligne d'adresse A15 n'est pas câblée au ROM.

Alors que je pensais commencer à comprendre, j'ai eu la chance de tomber sur cette page qui a fait disparaître mes doutes sur le fonctionnement des cartouches LoRom:
LoRom Model (https://www.cs.umb.edu/~bazz/snes/cartridges/lorom.html)

En plus de la mémoire ROM, il y a un autre élément important (et aussi emmerdant que les vis de la cartouche) dont il faut tenir compte: La puce de « lock out », aussi appelée puce CIC. Cette puce fonctionne en tant que clef pour sa collègue (la serrure) à l'intérieur de la console. La serrure échange des informations avec la clef, et si la réponse n'est pas satisfaisante, la console redémarre (et le jeu ne fonctionne donc pas).

Peut-on se procurer des puces CIC neuves? C'est peu probable, mais peu importe! Des équivalents ont été développés à l'aide de micro-contrôleurs PIC 12F629, et le firmware est disponible sur github. J'ai donc simplement installé un PIC 12F629 sur mon circuit.

Alors voici le schéma complet. J'espère que je ne recevrai pas de messages à propos d'erreurs flagrantes. Mais s'il y en a, veuillez m'en faire part au plus vite!



Voici à quoi ressemble le circuit imprimé que j'ai fait à partir du schéma. Je devrais en recevoir quelques uns d'ici 1 à 2 semaines. J'ai très hâte de l'essayer!




Troisième volet: Boîtier

Plusieurs vendeurs eBay offrent des « boitiers de remplacement » pour jeux SNES. J'en ai commandé quelques uns, mais je ne suis pas certain de les recevoir à temps. Au pire je réaliserai un modèle 3D que j'imprimerai.


goto top


Section 11: Support des manettes standard

Maintenant que les PCBs sont en commande, j'ai continué à travailler sur le jeu. J'ai d'abord rendu possible l'utilisation d'une manette standard, car la NTT Data Keypad ne court pas les rues.

Il suffit simplement d'utiliser les boutons L et R pour faire apparaître à tour de rôle des chiffres dans la case sous le curseur. Seuls les chiffres qui sont des coups légaux sont proposés.


goto top


Section 12: Résolveur de sudoku

J'ai d'abord amélioré la fonction indice (Hint) tel que déjà discuté pour détecter les cas où un chiffre ne peut apparaître que dans une seule case à l'intérieur d'une ligne ou d'une colonne. En appuyant sur Y, davantage de coups sont à présent proposés.

Pour le résolveur automatique, je fais d'abord appel au code de détection d'indice de manière répétitive jusqu'à ce que la grille soit pleine ou qu'il n'y ait plus de nouveaux coups. Pour les puzzles de niveau simple et easy, c'est généralement suffisant pour compléter la grille.

Mais pour les puzzles plus avancés, cela ne suffit pas. Après quelques itérations, il n'y a plus de nouveaux coups. Le résolveur entre alors en phase 2: La recherche exhaustive.

J'effectue la recherche à l'aide d'une fonction récursive (une fonction qui s'apelle elle-même). Voici l'équivalent en pseudo-code:
function bruteforcer()
{
	Cell cell = getEmptyCell();

	if (cell == null) {
		return true; // no more empty cells! Puzzle solved!
	}

	for (value = 1; value <= 9; value++) {
		if (cell.isLegalMove(value)) {
			cell.insertValue(value);
			if (bruteforcer()) {
				return true;
			}
		}
	}
	cell.clear();
	return false;
}
C'est surprenament simple n'est-ce pas! Le code qui s'occupe de vérifier la légalité des coups n'est pas exposé ci-dessus, mais il fonctionne exactement comme celui qui valide les coups du joueur (voir section 5, Validation des coups), seulement je l'ai modifié un peu pour être efficace dans le contexte du résolveur automatique.

Voici un court vidéo du résultat. On peut facilement repérer les deux phases (phase 1: Logique, phase 2: Recherche exhaustive):


goto top


Section 13: Deuxième version du ROM

Vous aimeriez essayer le jeu? Voici la version 0.2:

Téléchargement: super_sudoku_v0.2.sfc (256K)

Changements depuis la version précédente: Il me reste encore à ajouter des messges dans la boîte au bas de l'écran, à rendre possible l'interruption du résolveur et à ajouter des effets sonores simples, voir de la musique si j'ai le temps.

À suivre...

goto top


Les marques de commerce utilisées dans ce site appartiennent à leurs propriétaires respectifs.
Copyright © 2002-2019, Raphaël Assenat
Site codé avecSite codé avec vimDernière mise à jour: 18 mars 2019 (Lundi)