Récemment, lors du nouveau Puzzling.SE , il y avait un problème avec les espions jetant des pierres dans une rivière qui était en fait assez difficile:
Deux espions doivent se passer deux numéros secrets (un numéro par espion), inaperçus par leurs ennemis. Ils se sont mis d'accord sur une méthode pour ce faire en utilisant seulement 26 pierres indiscernables à l'avance.
Ils se rencontrent à une rivière, où il y a un tas de 26 pierres. En commençant par le premier espion, ils jettent à tour de rôle un groupe de pierres dans la rivière: le premier espion lance un certain nombre de pierres, puis la seconde, puis la première encore ...
Chaque espion doit lancer au moins une pierre à son tour, jusqu'à ce que toutes les pierres soient parties.
Ils observent tous les lancers et divergent lorsqu'il n'y a plus de pierres. Ils gardent le silence tout le temps et aucune information n'est échangée sauf le nombre de pierres lancées à chaque tour.
Comment peuvent-ils échanger les numéros avec succès si les numéros peuvent aller de 1 à M?
Votre tâche consiste à créer une paire de programmes, spy1
et spy2
cela peut résoudre ce problème pour le plus haut possible M
.
Vos programmes prendront chacun un numéro de 1
votre choix M
en entrée. Ensuite, spy1
sortira un nombre représentant le nombre de pierres qu'il jette dans la rivière, qui sera entré dans spy2
lequel sortira également un nombre à entrer spy1
, et ainsi de suite jusqu'à ce que les nombres sortants s'additionnent 26
. À la fin du lancement, chaque programme affichera le nombre qu'il pense que l'autre programme avait, qui doit correspondre au nombre qui a été réellement entré dans l'autre programme.
Votre programme doit fonctionner pour toutes les paires de numéros ordonnées possibles (i, j)
où les deux i
et j
peuvent varier de 1
à M
.
Le programme qui fonctionne pour le plus grand M
sera le gagnant, avec la première réponse à être publiée en cas d'égalité. De plus, j'accorderai une prime de réputation de +100 à la première solution qui a fait ses preuves M >= 2286
et +300 à la première solution qui a fait ses preuves M >= 2535
.
Réponses:
C #, M = 2535
Cela implémente * le système que j'ai décrit mathématiquement sur le fil qui a provoqué ce concours. Je réclame le bonus de 300 rep. Le programme s'auto-teste si vous l'exécutez sans arguments de ligne de commande ou avec
--test
comme argument de ligne de commande; pour spy 1, run with--spy1
et pour spy 2 with--spy2
. Dans chaque cas, il prend le numéro que je dois communiquer de stdin, puis effectue les lancers via stdin et stdout.* En fait, j'ai trouvé une optimisation qui fait une énorme différence (de plusieurs minutes pour générer l'arbre de décision à moins d'une seconde); l'arbre qu'il génère est fondamentalement le même, mais je travaille toujours sur une preuve de cela. Si vous voulez une implémentation directe du système que j'ai décrit ailleurs, voir la révision 2 , bien que vous souhaitiez peut-être rétroporter la journalisation supplémentaire
Main
et les meilleures communications inter-threadTestSpyIO
.Si vous souhaitez un scénario de test qui se termine en moins d'une minute, passez
N
à16
etM
à87
.Instructions pour les utilisateurs Linux
Vous devrez
mono-csc
compiler (sur les systèmes basés sur Debian, c'est dans lemono-devel
paquet) etmono
exécuter (mono-runtime
paquet). Ensuite, les incantations sontetc.
la source
yum install mono-core
(en tant que root). 2.dmcs Puzzle625.cs
3.mono Puzzle625.exe --test
Programme de testeur Python
Je pense qu'il serait utile d'avoir un programme de test qui puisse vérifier que votre implémentation fonctionne. Les deux scripts ci-dessous fonctionnent avec Python 2 ou Python 3.
Programme de testeur (
tester.py
):Protocole: les deux programmes espions spécifiés sur la ligne de commande seront exécutés. On s'attend à ce qu'ils interagissent uniquement via stdin / stdout. Chaque programme recevra son numéro attribué comme première ligne d'entrée. À chaque tour, l'espion 1 sort le nombre de pierres à lancer, l'espion 2 lit un nombre à partir de stdin (représentant le jet de l'espion 1), puis ils répètent (avec les positions inversées). Lorsque l'un ou l'autre espion détermine que 26 pierres ont été lancées, il s'arrête et émet sa supposition pour le numéro de l'autre espion.
Exemple de session avec un spy1 compatible (
>
indique l'entrée à l'espion)Si vous choisissez un M très grand, et il prend trop de temps à courir, vous pouvez passer
test(
àtestrand(
la dernière ligne pour effectuer des tests aléatoires. Dans ce dernier cas, laissez le programme en cours d'exécution pendant au moins quelques milliers d'essais pour renforcer la confiance.Exemple de programme (
spy.py
), pour M = 42:Exemple d'utilisation:
la source
Java, M = 2535
OK, voici mon implémentation. À chaque étape, un espion fait un pas. Chaque mouvement possible représente une gamme de codes. L'espion choisit le coup correspondant à son code secret. Comme ils jettent plus de pierres, la gamme de codes possibles se réduit jusqu'à ce que, pour les deux espions, un seul code reste possible en fonction des mouvements qu'ils ont effectués.
Pour récupérer les codes secrets, vous pouvez rejouer tous les mouvements et calculer les plages de codes correspondantes. À la fin, il ne reste qu'un code pour chaque espion, c'est le code secret qu'il voulait transmettre.
Malheureusement, l'algorithme repose sur une grande table précalculée avec des centaines de milliers d'entiers. La méthode ne pouvait pas être appliquée mentalement avec plus de 8 à 10 pierres peut-être.
Le premier fichier implémente l'algorithme de Spy. La partie statique précalcule une
codeCount
table qui est ensuite utilisée pour calculer chaque déplacement. La deuxième partie met en œuvre 2 procédures, l'une pour sélectionner le nombre de pierres à lancer, l'autre pour rejouer un coup pour aider à reconstruire les codes secrets.Le deuxième fichier teste la classe Spy de manière approfondie. La méthode
simulate
simule le processus. Il utilise la classe Spy pour générer une séquence de lancers à partir des codes secrets, puis reconstruit les codes à partir de la séquence.Spy.java
ThrowingStones.java
Pour référence, le tableau codeCount précalculé contient les valeurs suivantes:
Cela était directement lié aux ensembles Tk de Peter Taylor. Nous avons:
la source
range
champs. Mais je suis très intrigué par votre méthode de calcul du tableau. Avez-vous une preuve d'exactitude? Et êtes-vous intéressé à collaborer sur un article qui traite du problème et à calculer sa solution?ksh / zsh, M = 126
Dans ce système simple, chaque espion envoie des chiffres binaires à l'autre espion. Dans chaque lancer, la première pierre est ignorée, les pierres suivantes sont chaque bit 0, et la dernière pierre est le bit 1. Par exemple, pour lancer 20, un espion lancerait 4 pierres (ignorer, 0, 2, ajouter 4), puis lancez 3 pierres (ignorer, 8, ajouter 16), car 4 + 16 = 20.
L'ensemble des nombres n'est pas contigu. 0 à 126 sont entrés, mais 127 sont sortis. (Si les deux espions en ont 127, ils ont besoin de 28 pierres, mais ils ont 26 pierres.) Ensuite, 128 à 158 sont entrés, 159 sont sortis, 160 à 174 sont entrés, 175 sont sortis, 176 à 182 sont entrés, 183 est sorti, 184 à 186 est entré, 187 est sorti, etc.
Exécutez un échange automatique avec
ksh spy.sh 125 126
ou exécutez des espions individuels avecksh spy.sh spy1 125
etksh spy.sh spy2 126
. Ici,ksh
peut être ksh93, pdksh ou zsh.EDIT 14 juin 2014: correction d'un problème avec certains co-processus dans zsh. Ils resteraient inactifs pour toujours et ne sortiraient pas, jusqu'à ce que l'utilisateur les tue.
la source