Créer des boucles non-interchangeables

Bonjour !

Pour un escape game, je cherche un moyen de créer un jeu type puzzle de câbles. But : Relier les points A B C D, etc aux bornes 1 2 3 4, etc.

Matériel :
Arduino nano
Câbles mâle mâle (quel que soi le connecteur) 1 seul pôle utilisé
Prises femelles

En soit, quand le câble relie les 2 prises, ça fait une boucle fermée, comme si un interrupteur est sur ON. Donc pas de soucis. Le sketch sera du genre « si l’interrupteur de la pin 6 est ON = validé.

Mon soucis c’est plutôt qu’avec cette technique, on ne repère pas les mauvais branchements.
Si la bonne réponse est « B relié à 3 », ça va aussi fonctionner si C est relié à 3…

Je n’arrive pas à trouver la logique (câblage ou sketch) qui ferait que 1 seule solution soit la bonne. Un idée (simple) ?

Bonjour danyschibli

Chaque câble a un A OUTPUT et un 1 INPUT_PULLUP, exemple câble A va de D6 (OUTPUT) à 1 D7 (INPUT)
Tu mets A à HIGH et tu contrôle que 1 est bien HIGH
Tu mets A à LOW et tu contrôle que 1 est bien LOW
Si pas 2 x ==, connexion erronée.

Si tu veux un exemple, il n'y a pas de problème :wink:

Cordialement
jpbbricole

Volontiers :wink:
Je me réjouis de tester ça

pendant qu'on cherche les connections certaines pins destination seront en l'air.

si elles ne sont qu'en INPUT, elle vont flotter et pourraient aléatoirement dire HIGH ou LOW et conduire à un faux résultat.

un pullup (celui de la carte) ou pulldown (externe ou interne si la carte le propose) serait utile.

Bonsoir J-M-L

Oui, c'est une évidence, j'aurais du le spécifier :wink:

Cordialement
jpbbricole

Bonjour,

Au plus simple, je pense que l'utilisation d'un circuit logique avec 4 portes AND ferait l'affaire.

Les portes logiques sont chaînées. La sortie de chaque porte étant conditionnée par l'activation de la précédente et le câblage correct.

Capture d’écran du 2022-03-20 13-29-28

Avec:

  • fils rouge alimentation 5V
  • fils noirs masse
  • fils bleus connexion entre les portes
  • fils verts les 4 câbles A1, B2, C3, D4.

La led peut être remplacée par un port d'entrée Arduino.

A+

Bonjour

Donc, si j'ai bien compris, tu proposes de câbler, "en dur" ?
Comment on fait pour savoir que le point D est bien sur la borne 1 par exemple?
Comment faire si l'on veut changer le code secret?

Cordialement
jpbbricole

on change les fils bleus je suppose

Bonjour,

Heu oui, c'est une proposition, peut être pas la solution. Effectivement qui dit proposition matérielle, dit effectivement modification matérielle pour changer le code. Le choix à l'utilisateur de modifier le câblage ou le code logiciel si il retient une solution logicielle.
A+

J’ai pas vraiment besoin de changer le code…

Par contre, que fait une puce 74HC08 là au milieu ?

lisez la réponse #7.. le ET se fait en hardware

Oui, mais cela ne répond pas vraiment à la demande initiale car, par exemple, si on place un fil entre le premier fil rouge et l'une quelconque des entrées on bypass toute ou partie de la chaine.

La proposition de @jpbbricole au #2 me parait, jusqu'ici, la meilleure réponse à la demande

il faudrait sans doute des pull-down en plus de façon à ce qu'une entrée bypassée soit fausse

Bonjour

Si je comprend bien l'énoncé le problème est analogue à celui de la détection d'une touche particulière parmi 16 dans un clavier matriciel 4x4, le bon câblage ('boucle') à découvrir établissant une connection entre une des 4 'lignes' et une des 4 'colonnes'

https://github.com/nickgammon/Keypad_Matrix (diodes inutiles ici)

dans ce cas la librairie Keypad , présente dans le gestionnaire de librairies ferait l'affaire
https://playground.arduino.cc/Main/KeypadTutorial/

Il peut ou devrait y avoir 4 touches enfoncées en même temps. Elle détecte 4 touches?

Bonsoir danyschibli

Comme proposé, ma « vision » de la chose, je me suis bien amusé, joli sujet de réflexion :wink:
Dans la terminologie, il y a des Points A, B, C, D.. (ports en sortie) et des Bornes 1, 2, 3, 4… (ports en entrée avec PULL_UP interne), si le lieu est perturbé, il serait utile d'ajouter des PULL_UP externes.

Le programme s’articule autour du tableau à 2 dimensions :

const int puzzPoiBor[][2] =
{//   A  1    B   2    C   3    D   4    E   5    F   6
	{A0, 6}, {A1, 7}, {A2, 8}, {A3, 9}, {4, 10}, {5, 11}      // Pin Points (sorties) et Bornes (Entrées)
};

{port du Point, port de la Borne}
Pour ajouter ou supprimer un couple Point/Borne, il suffit d’ajouter ou de supprimer une paire d’accolades {Point, Borne},

La solution à trouver est dans la variable :
String puzzSolution = "F0-B1-C2-D3-E4-A5";
Elle doit bien sûre avoir autant de paires PointBorne qu’il y en a dans le tableau puzzPoiBor[ ][2].
Les numéros de Bornes doivent aller de 0 à nombre de Bornes en ordre croissant, seuls les lettres des Points peuvent être intervertis, pour créer une nouvelle énigme.

Pendant le déroulement du jeu, il y a des indications dans le moniteur (115200)

Il n'y a que 3 cables sur 6
Pas encore ca avec E0-B1-C2-D3-F4-A5
Gagne avec F0-B1-C2-D3-E4-A5

D’autres indications se trouvent dans le programme.

/*
    Name:       ARDFR_boucles_non_interchangeables.ino
    Created:	19.03.2022 19:14:50
    Author:     jpbbricole
*/

enum puzzPortsTypeIndex { portPoint, portBorne};

const int puzzPoiBor[][2] =
{//   A  1    B   2    C   3    D   4    E   5    F   6
	{A0, 6}, {A1, 7}, {A2, 8}, {A3, 9}, {4, 10}, {5, 11}      // Pin Points (sorties) et Bornes (Entrées)
};

const int puzzIndexMax = (sizeof(puzzPoiBor) / sizeof(puzzPoiBor[0]))-1;
int puzzNombreDeCables = puzzIndexMax +1;     // Nombre de pièces

String puzzSolution = "F0-B1-C2-D3-E4-A5";

void setup()
{
	Serial.begin(115200);
	
	// Initialisation des ports
	for (int p = 0; p <= puzzIndexMax; p ++)
	{
		pinMode(puzzPoiBor[p][portPoint], OUTPUT);     // Ports en sortie
		digitalWrite(puzzPoiBor[p][portPoint], LOW);     // Port à LOW
		pinMode(puzzPoiBor[p][portBorne], INPUT_PULLUP);     // Bornes en entrée
	}
}

void loop()
{
	int cablesConnectes = puzzNombreConnectes();
	if (cablesConnectes == puzzNombreDeCables)     // Si tout les câbles connectés
	{
		String solutionJoueur = puzzLireSolutionJoueur();
		if (solutionJoueur == puzzSolution)
		{
			Serial.println("Gagne avec " + solutionJoueur);
			// Action quand solution trouvée
		} 
		else
		{
			Serial.println("Pas encore ca avec " + solutionJoueur);
		}
	}
	else
	{
		Serial.print("Il n'y a que " + String(cablesConnectes));
		Serial.println(" cables sur " + String(puzzNombreDeCables));
	}
	
	delay(1000);

}


/*-------------------------------------------------------------- 
	Retourne la solution proposée par le joueur'*--------------------------------------------------------------
'*--------------------------------------------------------------
*/
String puzzLireSolutionJoueur()
{
	String soluceJoueur = "";     // Solution sous forme A3-C0-D1 ... si XX pas de Point connecté sur cette Borne
	
	for (int b = 0; b <= puzzIndexMax; b ++)     // Toutes les bornes
	{
		soluceJoueur += puzzLiaisonPointBorne(b) + "-";
	}
	return soluceJoueur.substring(0, soluceJoueur.length()-1);     // Pour supprimer le dernier -
}

/*-------------------------------------------------------------- 
	Retourne la liaison entre la borne borneNum et 
	son point A4 ou C2 ou XX si pas de liaison sur cette Borne
'*--------------------------------------------------------------
*/
String puzzLiaisonPointBorne(int borneNum)
{
	String lienPoiBor = "";     // Liaison entre Point et Borne
	
	for (int p = 0; p <= puzzIndexMax; p ++)     
	{
		lienPoiBor = "XX";     // Liaison entre Point et Borne
		int test = 0;
		digitalWrite(puzzPoiBor[p][portPoint], LOW);     // Port à OFF
		if (digitalRead(puzzPoiBor[borneNum][portBorne]) == LOW)     // Contrôle si continuité LOW
		{ test ++; }
		digitalWrite(puzzPoiBor[p][portPoint], HIGH);     // Port à ON
		if (digitalRead(puzzPoiBor[borneNum][portBorne]) == HIGH)     // Contrôle si continuité HIGH
		{ test ++; }

		if (test  == 2)     // Si tout OK
		{
			lienPoiBor = char('A' + p) + String(borneNum);
			break;
		}
	}
	return lienPoiBor;
}

/*-------------------------------------------------------------- 
	Compte le nombre de câble(s) connecté(s)
	entre Point et Borne
'*--------------------------------------------------------------
*/
int puzzNombreConnectes()
{
	int connTotal = 0;
	
	for (int b = 0; b <= puzzIndexMax; b ++)     // Tout les ports à OFF
	{
		digitalWrite(puzzPoiBor[b][portPoint], LOW);     
	}
	
	for (int b = 0; b <= puzzIndexMax; b ++)     // Tout les bornes
	{
		if (digitalRead(puzzPoiBor[b][portBorne]) == LOW)
		{ connTotal ++; }
	}
	return connTotal;
}

Pour le fun, on pourrait ajouter un interface Bluetooth, afin de modifier l’énigme à distance et ou de voir le déroulement du jeu.

A ta disposition pour tout renseignements supplémentaires.

PS : Le programme est testé « en vrai » mais….

Cordialement
jpbbricole

Bonjour,

Je me permet de revenir sur "ma proposition matérielle" qui me semble pourtant bien fonctionnelle même si je ne l'ai pas testée et qu'elle est bien moins aboutie que celle proposée par @jpbbricole

Pour aider à la compréhension je vous propose un schéma du montage.

Ce montage, ne contient que des portes logique ET et une led qui s'allume quand tous les câbles sont correctement branchés. Pour que la sortie d'une porte passe à 1 il faut que la valeur de ses 2 entrées soient à 1. Tant que la sortie de la porte précédente n'est pas à 1, la porte suivante reste à 0.
Avec ce montage, il n'est pas possible de connaître le nombre de bons branchements, ce n'est que quand tous les câbles sont correctement branchés que la led s'allume.
La led peut être remplacée par un port Arduino en INPUT.

J'espère que grâce à ce schéma et mes explications que c'est plus clair.

A+

Cela me semble fonctionner. Il faut quand même mettre des pulldown en entrée. Les portes peuvent être faites avec une Arduino. En mettant des OU avec des pullup, on peut faire la même chose (test final à 0). Ce qui permet de le faire avec une Arduino qui n'a que des pullup.

Si vous reliez A et 4 vous avez un VRAI en entrée du dernier ET et l’autre pin est indéterminée d’où le besoin de pulldown mentionné en #14

L’idée de @vileroi permet d’utiliser le pullup hardware en inversant la logique

(X et Y) c’est pareil que l’inverse de NOT( NOT X ou NOT Y)

V ET V ➜ V | NOT(NOT V OU NOT V) ➜ V
V ET F ➜ F | NOT(NOT V OU NOT F) ➜ F
F ET V ➜ F | NOT(NOT F OU NOT V) ➜ F
F ET F ➜ F | NOT(NOT F OU NOT F) ➜ F

Bonjour !

Mais quelle efficacité sur ce forum :wink: !!!

La solution logicielle fonctionne à merveille, et j'ai même à peu près compris le sketch (quoi que je sois incapable de l'écrire... pour le moment, soyons positifs).
Testé avec des câbles, c'est parfait !

Plus qu'à coder un truc genre "une fois que c'est gagné, mettre la pin12 sur high", j'en fais mon affaire.

MERCI !!!
Merci aussi aux autres solutions :wink: qui m'ont l'air très bien aussi.
J'aime bien aussi la solution de jelopo, elle fait uniquement appel à de la logique et ça je comprends nettement mieux.

Je tâcherai de revenir mettre une photo du montage fini sur ce post quand il sera réalisé (faudra un peu de patience, mais ça va le faire).