IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Gestion d'un classement de scores


Sujet :

JavaScript

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre à l'essai
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Décembre 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2018
    Messages : 5
    Par défaut Gestion d'un classement de scores
    Bonjour,

    je souhaite mettre en place un petit jeu web assez simple en javascript (pas de souci pour cet aspect là) en gérant un classement des joueurs en fonction de leur score maximal. N'ayant pas de BDD accessible, je voudrais sauvegardé les scores au sein d'un fichier JSON. J'ai toutefois quelques soucis sur les méthodes à utiliser.

    Mon but serait :
    - de pouvoir, en fin de chaque partie, vérifier si le joueur a déjà un score sauvegardé dans le JSON. Si oui, on le met à jour; si non, on l'ajoute
    - les score n'ont pas besoin d'être triés dans le JSON, le javascript qui les récupère peut le faire
    - pour lire/écrire dans le fichier JSON, je pense passer par un appel de XMLHttpRequest

    Je ne sais pas si je peux mettre à jour 1 seul score dans le fichier JSON sans avoir à le ré-écrire entièrement.

    Pour l'instant j'ai cette structure de fichier :

    rankJSON.js
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    var ranking = [
       {"name":"player", "score":100},
       {"name":"ohterOne", "score":102},
       {"name":"someone", "score":88},
       {"name":"somebody", "score":123},
       {"name":"whoAreYou", "score":67}
    ];
    Je pense utiliser XMLHTTPRequest pour faire un appel à un fichier PHP qui se chargerait de l'écrire dans le fichier lors d'insertion ou de modification mais je ne sais pas si je peux modifier une partie du fichier.

    Auriez vous des conseils pour m'aider à avancer?

    Merci d'avance.

  2. #2
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    La façon de faire la plus facile à coder est sans doute de traiter le JSON dans son ensemble, en le lisant en entier puis en le réécrivant en entier. En effet, PHP t’offre des facilités avec les fonctions file_get_contents et file_put_contents. Pour manipuler le JSON en mémoire, il suffit alors de décoder / encoder les chaînes avec json_decode et json_encode.

    Attention, avant PHP 7.3 (version sortie ce mois-ci) ces fonctions json ont le mauvais goût de ne pas lever d’exception en cas d’erreur, il faut donc aller chercher les messages d’erreur à la main.

    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?php
    error_reporting(E_ALL);
     
    $contents = file_get_contents('chemin/du/fichier.json');
    if (false === $contents) {
      die('Erreur lors de la lecture du fichier');
    }
     
    $json = json_decode($contents);
    if (null === $json) {
        die('Erreur lors du décodage json: ' . json_last_error_msg());
    }
     
    ...
    ...
    ...
     
    $encodedString = json_encode($json);
    if (false === $encodedString) {
        die('Erreur lors de l’encodage json: ' . json_last_error_msg());
    }
     
    $result = file_put_contents('chemin/du/fichier.json', $encodedString);
    if (false === $result) {
        die('Erreur lors de l’écriture du fichier');
    }

    L’objet json en mémoire volatile de ton script PHP ressemblera à ceci :
    Code text : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    array(5) {
      [0] => class stdClass#1 (2) {
        public $name => string(6) "player"
        public $score => int(100)
      }
     
      [1] => class stdClass#2 (2) {
        public $name => string(8) "ohterOne"
        public $score => int(102)
      }
     
      [2] => class stdClass#3 (2) {
        public $name => string(7) "someone"
        public $score => int(88)
      }
     
      [3] => class stdClass#4 (2) {
        public $name => string(8) "somebody"
        public $score => int(123)
      }
     
      [4] => class stdClass#5 (2) {
        public $name => string(9) "whoAreYou"
        public $score => int(67)
      }
    }

    Pour accéder par exemple au score du second item, il faut écrire ceci :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    echo $json[1]->score;

    Si tu préfères travailler avec des tableaux associatifs, il faut passer true en second paramètre à json_decode, ce qui te permettra d’accéder aux propriétés de cette façon :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    echo $json[1]['score'];

    Choisis selon ton style.

    La partie la plus compliquée consiste à retrouver un item à partir du nom du joueur. Tu peux le faire à la main avec une bonne vieille boucle foreach :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $player = 'someone';
    $found = false;
    foreach ($json as $item) {
      if ($item->name === $player) {
          $found = true;
          break;
      }
    }
    if ($found) {
        echo 'Score = ' . $item->score;
    }
    else {
        echo 'Joueur ' . $player . ' pas trouvé';
    }

    Ou bien avec array_filter :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $player = 'someone';
    $filtered_array = array_filter($json, function ($item) use ($player) {
        return $item->name === $player;
    });

    Cette dernière technique te permettra de repérer les doublons s’il y en a.




    Ton idée de vouloir réécrire seulement une partie du fichier est une bonne idée, on sent bien intuitivement que ça peut augmenter la performance. Seulement, il faudrait gérer les décalages d’octets, par exemple si le score passe de 67 à 123 : il y a un chiffre en plus, ça fait un octet en plus dans le fichier, et là il faut décaler tous les octets suivants jusqu’à la fin du fichier. Grosse perte de temps.

    En fait, si on prend un peu de recul, on se rend compte qu’on est en train de faire une sorte de moteur de stockage, exactement comme une base de données. Ces dernières proposent souvent un type de colonne à taille fixe, par exemple les types CHAR(40), INT(5), etc.

    En ajoutant un peu de complexité dans ton script PHP, tu pourrais contraindre le champ "name" à avoir toujours une longueur de 15 caractères par exemple, et le champ "score" serait converti en string pour pouvoir contraindre sa longueur de la même manière (en ajoutant des zéros devant quand il y a besoin).

    Par exemple :
    Code json : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    [
       { "name": ".........player", "score": "100" },
       { "name": ".......ohterOne", "score": "102" },
       { "name": "........someone", "score": "088" },
       { "name": ".......somebody", "score": "123" },
       { "name": "......whoAreYou", "score": "067" }
    ]

    Tout ça représente beaucoup d’efforts, et on n’est même pas sûrs que ça sera vraiment plus efficace, il faudrait faire des tests. Les bases de données utilisent des moteurs de stockage qui ont été moult fois testés et éprouvés.

    D’autre part, comme indiqué dans la doc, la fonction file_get_contents est assez intelligente pour utiliser un tampon de mémoire. Je ne sais pas ce qu’il en est de json_decode, mais mon conseil c’est de ne pas trop te préoccuper de la performance de ton script. Tant que ton fichier ne fait pas des centaines de milliers de lignes, tu ne verras probablement pas d’impact significatif.

    Bien sûr, l’idéal serait de pouvoir utiliser une vraie base de données
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  3. #3
    Membre à l'essai
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Décembre 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2018
    Messages : 5
    Par défaut
    Merci pour cette réponse très complète

    Je me pose toutefois une question : si j'efface et ré-écris le fichier JSON à chaque mise à jour de score, cela ne risque-t-il pas de poser problème si 2 joueurs terminent leur partie en même temps?

    Le joueur D va récupérer le fichier qui contiendra la liste A,B,C
    Le joueur E va récupérer le fichier qui contiendra aussi la liste A,B,C
    Le joueur D va écraser le fichier avec la liste A,B,C,D
    Le joueur E va écraser le fichier avec la liste A,B,C,E

    Du coup, on perdrait le score du joueur D

  4. #4
    Membre Expert
    Avatar de badaze
    Homme Profil pro
    Chef de projets info
    Inscrit en
    Septembre 2002
    Messages
    1 412
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets info
    Secteur : Transports

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 412
    Par défaut
    Pour pallier le problème tu peux bloquer l'accès au fichier en écriture le temps que les mises à jour soient faites.

    A peine testé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?php
    // on ouvre le fichier
    $handle     = fopen('monfichier.txt','w+');
    // bloque et teste l'état du fichier - boucle tant que le fichier n'est pas libéré
    while (!flock($handle,LOCK_EX))
    {
     // on ne fait rien
    }
    // quand on arrive ici c'est qu'on vient de bloquer le fichier
    // ceux qui arrivent avant la libération seront en attente grâce au while... mise à jour du fichier
    // echo "je mets à jour le fichier <br/>";
    // sleep(10);
    // on libère le fichier
    flock($handle,LOCK_UN);
    // on ferme le fichier
    fclose($handle);

  5. #5
    Membre à l'essai
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Décembre 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2018
    Messages : 5
    Par défaut
    J'ai tenté d'assembler le tout mais j'ai une erreur 500. J'avais oublié que le PhP était moins pratique à débugger que le JS

    Voila mon code source :

    La partie JS :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function updateScores() {
    	xhr=getXMLHttpRequest();
    	xhr.open("POST", "./js/log.php", true);
    	xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    	xhr.send("name="+pseudo+"&score="+score.count);
    }
     
    function getXMLHttpRequest() {
    	if (xhr==null) {
    		if (window.XMLHttpRequest || window.ActiveXObject) {
    			if (window.ActiveXObject) {
    				try {
    					xhr = new ActiveXObject("Msxml2.XMLHTTP");
    				} catch(e) {
    					xhr = new ActiveXObject("Microsoft.XMLHTTP");
    				}
    			} else {
    				xhr = new XMLHttpRequest(); 
    			}
    		} else {
    			alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest...");
    			return null;
    		}
    	}
    	return xhr;
    }
    Et le fichier log.php :
    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    <?php
     
    // 1 : on récupère les variables
    $nomFichier = './rank.js';
    $pseudo = $_POST["pseudo"];
    $score = $_POST["score"];
     
    // 2 : on ouvre le fichier
    $monfichier = fopen($nomFichier, 'w+');
     
    while (!flock($monfichier,LOCK_EX)) {
     // tant que le fichier n est pas dispo, on ne fait rien
    }
     
    // 3 : on lit et on ecrit dans le fichier
    $contents = file_get_contents($nomFichier);
    if (false === $contents) {
      die('Erreur lors de la lecture du fichier');
    }
     
    $json = json_decode($contents);
    if (null === $json) {
        die('Erreur lors du décodage json: ' . json_last_error_msg());
    }
     
    //recherche
    $found = false;
    foreach ($json as $item) {
      if ($item->name === $pseudo) {
          $found = true;
          break;
      }
    }
    if ($found) {
        $player = $item;
    	if ($player->score < $score) {
    		$player->score = $score;
    	}
    } else {
        $player = array('pseudo' => $pseudo, 'score' => $score);
    	array_push($json, $player);
    }
     
    $encodedString = json_encode($json);
    if (false === $encodedString) {
        die('Erreur lors de l’encodage json: ' . json_last_error_msg());
    }
     
    $result = file_put_contents($nomFichier, $encodedString);
    if (false === $result) {
        die('Erreur lors de l’écriture du fichier');
    }
     
    // 4 : quand on a fini de l'utiliser, on deverrouille et on ferme le fichier
    flock($monfichier,LOCK_UN);
    fclose($monfichier);
     
    ?>

  6. #6
    Membre Expert
    Avatar de badaze
    Homme Profil pro
    Chef de projets info
    Inscrit en
    Septembre 2002
    Messages
    1 412
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets info
    Secteur : Transports

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 412
    Par défaut
    Un truc.

    il faut débloquer/fermer le fichier avant de faire les die.

Discussions similaires

  1. gestion d'un classement mensuel
    Par helene5152 dans le forum VBA Access
    Réponses: 1
    Dernier message: 21/08/2013, 22h50
  2. Gestions des doublons dans un classement de clients par CA
    Par nianko dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 09/04/2011, 23h33
  3. [AC-2007] Classement par Equipe sur le total des 3 meilleurs scores
    Par ctsblv dans le forum Access
    Réponses: 10
    Dernier message: 07/12/2010, 13h20
  4. gestion du score avec Array et push
    Par clem037 dans le forum ActionScript 3
    Réponses: 0
    Dernier message: 22/03/2009, 16h16
  5. [Requête] Classement de Scores
    Par thefutureisnow dans le forum Langage SQL
    Réponses: 13
    Dernier message: 01/10/2006, 19h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo