2012-07-08 25 views
9

Disculpe el título largo.
Quería que fuera lo más descriptivo posible.Juego de adivinar palabras PHP (resaltar letras en posición correcta e incorrecta - como la mente maestra)

Descargo de responsabilidad: Podría encontrar un código de "encontrar las diferencias" aquí y en otros lugares en Stackoverflow, pero no exactamente la funcionalidad que estaba buscando.

voy a estar utilizando estos terminoligy más adelante:
'userguess': una palabra que será introducido por el usuario
'solución': la palabra secreta que necesita ser adivinado .

Lo que necesito para crear

Palabras juego de adivinanzas donde:

  • el usuario introduce una palabra (Me aseguraré de que a través de Javascript/jQuery que la palabra introducida contiene la misma cantidad de letras que la palabra , adivine).

    función
  • Un PHP comprueba entonces la 'userguess' y pone de relieve (en verde) las letras de la palabra que esté en el sitio correcto, y Destacados (en rojo) las cartas que aún no están en el lugar correcto , pero aparece en otro lugar de la palabra.
    Las letras que no aparecen en la 'solución' se dejan en negro.



trampa Escenario: - Digamos que la 'solución' es 'aabbc' y el usuario adivina 'abaac'
En el escenario anterior esto se traduciría en: (verde) un (/ verde) (rojo) b (/ rojo) (rojo) un (/ rojo) (negro)un (/ negro) (verde) c (/ verde)
Note como el último "un" es causa negro 'userguess' tiene 3 una es pero 'solución' sólo tiene 2

Lo que tengo hasta ahora

Código está trabajando más o menos, pero tengo la sensación de que puede ser 10 veces más esbelto y mezquino.
Lleno 2 nuevas matrices (una para solución y una para usuario) a medida que avanzo para evitar que la trampa (ver más arriba) estropee las cosas.

function checkWord($toCheck) { 
     global $solution;  // $solution word is defined outside the scope of this function 
     $goodpos = array(); // array that saves the indexes of all the right letters in the RIGHT position 
     $badpos = array(); // array that saves the indexes of all the right letters in the WRONG position 
     $newToCheck = array(); // array that changes overtime to help us with the Pitfall (see above) 
     $newSolution = array();// array that changes overtime to help us with the Pitfall (see above) 

     // check for all the right letters in the RIGHT position in entire string first 
     for ($i = 0, $j = strlen($toCheck); $i < $j; $i++) { 
      if ($toCheck[$i] == $solution[$i]) { 
       $goodpos[] = $i; 
       $newSolution[$i] = "*"; // RIGHT letters in RIGHT position are 'deleted' from solution 
      } else { 
       $newToCheck[] = $toCheck[$i]; 
       $newSolution[$i] = $solution[$i]; 
      } 
     } 

     // go over the NEW word to check for letters that are not in the right position but show up elsewhere in the word 
     for ($i = 0, $j = count($newSolution); $i <= $j; $i++) { 
      if (!(in_array($newToCheck[$i], $newSolution))) { 
       $badpos[] = $i; 
       $newSolution[$i] = "*"; 
      } 
     } 

     // use the two helper arrays above 'goodpos' and 'badpos' to color the characters 
     for ($i = 0, $j = strlen($toCheck), $k = 0; $i < $j; $i++) { 
      if (in_array($i,$goodpos)) { 
       $colored .= "<span class='green'>"; 
       $colored .= $toCheck[$i]; 
       $colored .= "</span>"; 
      } else if (in_array($i,$badpos)) { 
       $colored .= "<span class='red'>"; 
       $colored .= $toCheck[$i]; 
       $colored .= "</span>"; 
      } else { 
       $colored .= $toCheck[$i]; 
      } 
     } 

     // output to user 
     $output = '<div id="feedbackHash">'; 
     $output .= '<h2>Solution was : &nbsp;' . $solution . '</h2>'; 
     $output .= '<h2>Color corrected: ' . $colored . '</h2>'; 
     $output .= 'Correct letters in the right position : ' . count($goodpos) . '<br>'; 
     $output .= 'Correct letters in the wrong position : ' . count($badpos) . '<br>'; 
     $output .= '</div>'; 

     return $output; 
    } // checkWord 
+0

"// verifique todas las letras correctas en la posición DERECHA" ¿no es exactamente lo mismo que un === control? Si la mayoría de las personas lo hacen bien, entonces debes hacer lo contrario de "falla primero", es decir, verificar, pasar primero, regresar. – Cups

+0

+1, ¡Nunca he visto a un recién llegado escribir una pregunta tan detallada! :) – SuperSaiyan

+0

+1 por una buena pregunta ... – Red

Respuesta

2

Buena pregunta. Probablemente lo haría de manera ligeramente diferente a usted :) (¡Creo que eso es lo que esperaba!)

Puede encontrar toda la función de solución aquí http://ideone.com/8ojAG - pero la voy a desglosar paso a paso también.

En primer lugar, intente y evite el uso de global. No hay ninguna razón por la que no puede definir su función como:

function checkWord($toCheck, $solution) {

Se puede pasar la solución y evitar desagradables potenciales más adelante.

me gustaría empezar dividiendo tanto la conjetura de usuario, y la solución en matrices, y tener otra matriz para almacenar mi producción en.

$toCheck = str_split($toCheck, 1); 
$solution = str_split($solution, 1); 
$out = array(); 

En cada etapa del proceso, me quito el caracteres que han sido identificados como correctos o incorrectos por la suposición de los usuarios o la solución, por lo que no es necesario que los marque de ninguna manera, y las etapas restantes de la función se ejecutan de manera más eficiente.

Para comprobar si hay coincidencias.

foreach ($toCheck as $pos => $char) { 
    if ($char == $solution[$pos]) { 
     $out[$pos] = "<span class=\"green\">$char</span>"; 
     unset($toCheck[$pos], $solution[$pos]); 
    } 
} 

Así, por ejemplo su conjetura/solución, $out ahora contiene un verde 'a' en la posición 0, y una c verde en la posición 4. Tanto la respuesta y la solución ya no tienen estos índices, y no lo hará ser revisado nuevamente

Un proceso similar para verificar las letras que están presentes, pero en el lugar incorrecto.

foreach ($toCheck as $pos => $char) { 
    if (false !== $solPos = array_search($char, $solution)) { 
     $out[$pos] = "<span class=\"red\">$char</span>"; 
     unset($toCheck[$pos], $solution[$solPos]); 
    } 
} 

En este caso estamos buscando la letra adivinada en la solución y quitándola si se encuentra. No necesitamos contar el número de ocurrencias porque las letras se eliminan a medida que avanzamos.

Finalmente las únicas cartas que quedan en los usuarios de adivinar, son los que no están presentes en absoluto en la solución, y puesto que hemos mantenido los índices numeradas en todas partes, simplemente podemos combinar las letras sobrantes de nuevo.

$out += $toCheck;

Casi allí. $out tiene todo lo que necesitamos, pero no está en el orden correcto. Aunque los índices son numéricos, no están ordenados. Terminamos con:

ksort($out); 
return implode($out); 

El resultado de todo esto es: la producción

"<span class="green">a</span><span class="red">b</span><span class="red">a</span>a<span class="green">c</span>"

+0

muchas gracias por poner el tiempo en escribir esto. Como dije: mi cerebro es mediocre en lo que respecta a los algoritmos hardcore. Soy más un diseñador web que un desarrollador. No puedo agradecerle lo suficiente por 1) proporcionarme su visión sobre el código y 2) tomarse un tiempo extra para explicar en detalle cómo lo construyó. Simplemente deseé poder elegir 2 respuestas como mi respuesta aceptada. – Wayfarer

+0

@belgianwolfie Estaba tratando de escribir uno más compacto para usted también basado en algunas funciones internas de la biblioteca de matriz. Son funciones útiles y es posible que pueda utilizarlas en sus proyectos futuros de todos modos: ['array_intersect'] (http://php.net/manual/en/function.array-intersect.php) y [' array_diff'] (http://php.net/manual/en/function.array-diff.php) (también tienen versiones '_assoc' para preservar las claves) - Gracias por poner esfuerzo en su pregunta, muchas personas ven SO como un lugar para hacer que otras personas simplemente hagan su trabajo por ellos en estos días. ¡Buena suerte en sus futuras preguntas y respuestas! – Leigh

1

Aquí probar esto, See In Action

Ejemplo: enter image description here

<?php 
echo checkWord('aabbc','abaac').PHP_EOL; 
echo checkWord('funday','sunday').PHP_EOL; 
echo checkWord('flipper','ripple').PHP_EOL; 
echo checkWord('monkey','kenney').PHP_EOL; 

function checkWord($guess, $solution){ 
    $arr1 = str_split($solution); 
    $arr2 = str_split($guess); 
    $arr1_c = array_count_values($arr1); 
    $arr2_c = array_count_values($arr2); 
    $out = ''; 
    foreach($arr2 as $key=>$value){ 
     $arr1_c[$value]=(isset($arr1_c[$value])?$arr1_c[$value]-1:0); 
     $arr2_c[$value]=(isset($arr2_c[$value])?$arr2_c[$value]-1:0); 

     if(isset($arr2[$key]) && isset($arr1[$key]) && $arr1[$key] == $arr2[$key]){ 
      $out .='<span style="color:green;">'.$arr2[$key].'</span>'; 
     }elseif(in_array($value,$arr1) && $arr2_c[$value] >= 0 && $arr1_c[$value] >= 0){ 
      $out .='<span style="color:red;">'.$arr2[$key].'</span>'; 
     }else{ 
      $out .='<span style="color:black;">'.$arr2[$key].'</span>'; 
     } 
    } 
    return $out; 
} 
?> 
+0

No es realmente necesario hacer 'isset ($ arr2 [$ key])' dentro de 'foreach ($ arr2 as $ key => $ value) {' donde no cambia la matriz o la clave. No es particularmente necesario comprobar '$ arr1' ya que el autor de la pregunta sugiere que la validación está en otro lugar para garantizar que la suposición y la solución tengan la misma longitud – Leigh

+0

no duele; p, se requiere un control en' isset ($ arr1 [ $ key]) 'como la palabra de adivinar podría ser más larga –

+0

que es una belleza. Todavía intento envolver mi mediocre cerebro en el funcionamiento interno, incluso si el código es muy compacto :) muchas gracias por tu tiempo. – Wayfarer

Cuestiones relacionadas