Résolu Système de vote avec annulation du vote

...

Architecte en herbe
13 Mars 2016
71
9
97
28
Bonjour,

Toujours sur ma map loups-garou, je cherche à créer un système de vote qui permet aux loups de voter leur victime ou encore aux villageois de voter pendant le jour. J'aimerai donc pouvoir faire en sorte qu'ils puissent voter (jusque là pas de souci) et qu'ils puissent annuler leur vote si ils veulent changer de cible. Il faudrait donc pouvoir savoir qui a voté pour qui ce qui revient pour un jeu à 12 joueurs à faire un système de 12x11 scoreboard car 11 possibilités pour chaque joueur.
J'aurai voulu savoir si il y avait plus simple et moins complexe. J'en appelle donc à votre imagination.

Merci d'avance.
 

Oromis

Command-blocker slimesque
Staff
Modérateur
Support
11 Février 2014
3 345
2
1 053
297
24
Bretagne
Hey !

Pourquoi as-tu besoin de savoir qui a voté pour qui ?
 

...

Architecte en herbe
13 Mars 2016
71
9
97
28
Pour pouvoir enlever 1 de score au loup qui a voté pour tel ou tel victime si il veut changer de vote. De même avec le vote du village, si quelqu'un veut changer de vote il faut savoir qui a voté pour cette personne et donc qui doit avoir 1 de score en moins.
 

Oromis

Command-blocker slimesque
Staff
Modérateur
Support
11 Février 2014
3 345
2
1 053
297
24
Bretagne
Hey !

Du coup tu as une solution assez simple (>= 1.14) en passant par les NBT !
Dans l'idée :
  • Tu crées un storage dans lequel tu places un tableau vide que l'on nommera "Vote"
  • Tu attribues un nombre (UID) à chaque joueur compris entre 0 et nombre de joueur - 1 de façon à ce que chaque joueur est un id différent
  • Tu remplies ton tableau "Vote" d'autant de tableau vide qu'il y a de joueurs

Lorsqu'une personne vote pour quelqu'un :
  • Tu récupères l'id de la personne pour qui le joueur courant à voté
  • Tu places l'id du joueur courant dans le tableau dont l'index est l'id du joueur pour qui la personne à voté

Pour savoir qui a le plus de vote :
- Tu fais un "execute store result score" avec pour commande un "data get storage [nom du storage] Vote", ça aura pour effet de te retourner le nombre d'éléments qu'il y a dans le tableau (et donc le nombre de joueurs ayant voté pour la personne dont l'index est son id)

Pour retirer un joueur des tableaux de vote :
- Tu cherches la valeur dans tous les sous-tableaux de "Vote" puis tu la supprimes

Avantage :
  • Simple et élégant
  • Flexible pour autant de joueurs que l'on veut

Faiblesse :
- Assez coûteux en nombre de boucle pour parcourir les tableaux, bien que tout peut s'exécuter sur 1 seul tick


C'est la solution la plus élégante je trouve, mais je peux t'en proposer une autre qui ne se base que sur un scoreboard (ou deux pour stocker les UID) :

L'idée est de se baser sur les propriétés des nombres premiers.

Initialisation :
- Tu attribues à chaque joueur un UID qui est un nombre premier (2, 3, 5, 7, 11, 13, 17, 23, ...)

Pour les votes :
  • Tu définis le score de chaque joueur à 0
  • Pour chaque personne qui vote pour X, tu multiplies le score de X par l'id de la personne votant

Savoir qui gagne le vote :
- Celui qui a le score le plus gros

Annuler le vote d'une personne :
- Les nombres premiers ont une particularité, ils ne sont divisibles par aucun nombre outre 1 et eux-même. Le produit de 2 nombres premiers n'est donc divisibles que par ces deux nombres premiers. De façon plus généralisé, le produit de N nombre premier n'est divisible que par ces N nombres premiers.
On se base donc sur cela pour annuler le vote : si la personne n'a voté que pour une personne, il n'existe qu'un seul score étant divisible par l'id de la personne en question. Il suffit donc de faire le test suivant sur tous les scores S à partir de l'id I : S % I = 0 ? Si c'est le cas, alors le score est divisible entièrement par I et donc pour peut diviser S par I de façon à annuler le vote, si non, on continue à chercher.

Avantage :
  • Léger
  • Entièrement calculatoire

Faiblesse :
  • On ne peut pas récupérer facilement le nombre de vote pour une personne, bien que l'on peut tenter de le modulo du score par tous les id que l'on a, puis compter le nombre de réussite
  • Tous les joueurs ne peuvent pas voter pour une même personne : le produit des 12 premiers nombres premiers à pour résultat ~4*10^12 ce qui est largement plus grand que la capacité d'un scoreboard : ~2*10^9

Une dernière solution qui se rapproche un peu de celle utilisant les nombres premiers, c'est de passer par les nombres de la base de 2 :

Initialisation :
- Tu attribues à chaque joueur un UID appartenant à la base de 2 (1, 2, 4, 8, 16, 32, 64...) de façon à ce que, pour 12 joueurs, le dernier joueur est l'id 2^11 et le premier 2^0

Pour les votes :
- Même système que le précédent, sauf que tu additionnes au lieu de multiplier

Savoir qui gagne le vote :
- Celui qui se décompose en le plus de facteurs de 2. Pour cela, petit algorithme :
Code:
entier max
entier nb1
pour tout score S :
    copier score S dans S'
    entier compteur = 0
    tant que S' != 0 :
        si S' % 2 == 1 :
            compteur = compteur + 1
        S' = S' / 2
     si compteur > nb1 :
        max = S
        nb1 = compteur
retourner (max, nb1)
Dans cet algorithme, max est donc le score du joueur ayant le plus de vote, et nb1 le nombre de personne ayant voté pour.
Si tu ne comprends pas comment cela fonctionne, on peut se pencher du côté du binaire :
À chaque fois que tu ajoutes un nombre de la base de 2 à un nombre quelconque ne possédant pas ce nombre de la base de 2, tu ajoutes un "1" dans son nombre binaire, par exemple : 3 + 4 = 7 ce qui se traduit par : 11 + 100 = 111, on a donc bien un 1 de plus que notre nombre initial (11).
Pour savoir le nombre de joueurs, il suffit donc de compter le nombre de 1, et pour cela, il faut vérifier que le nombre inclu bien la puissance de 2 en question. On divise donc en boucle le nombre par 2 jusqu'à ce que celui-ci valle 0, et on compte au passage le nombre de fois où l'on n'arrive pas à le diviser entièrement (Donc le nombre de fois où le modulo par 2 vaut 1).

Annuler un vote :
- Un peu plus compliqué que les deux autres sytèmes, il faut reprendre l'algorithme du dessus, mais tu ajoutes une variable V initialisée à 2^11 (2048), puis à chaque fois que tu divises S' par 2, tu divises aussi cette variable par 2. Ainsi, si S' % 2 = 1 lorsque V vaut l'id de la personne dont tu veux annuler le vote, alors cette personne à voté pour le titulaire du score S, tu as juste à faire S - le score du votant donc.

Avantage :
  • Calculatoire
  • Fonctionne pour un grand nombre de joueur (jusqu'à 30 ou 31)

Faiblesse :
  • Est plus compliqué à mettre en place
  • Demande pas mal de calculs


Voilà pour les 3 systèmes que je peux te proposer ! Il y en a sans doute plein d'autres et des plus optimisés, mais ce sont ceux qui me sont venu à l'idée à la lecture du ta question.
On peut les résumer ainsi : Soit tu passes par une structure de données, soit tu codes le résultat des votes.
 
  • J'aime
Reactions: ... et FunkyToc

...

Architecte en herbe
13 Mars 2016
71
9
97
28
D'accord je vois ! Je pense avoir compris les 3 systèmes que tu proposes et je suis pas mal séduis par le deuxième. Je vais voir si je peux en adapter un à mon systèmes déjà en cours. Mais un grand merci pour ta réponse complète comme d'habitude.
 
  • J'aime
Reactions: Oromis