За последние 24 часа нас посетили 32890 программистов и 1819 роботов. Сейчас ищут 1000 программистов ...

Второй час туплю над рекурсивной функцией...

Тема в разделе "PHP для новичков", создана пользователем SkyKiller, 29 окт 2012.

  1. SkyKiller

    SkyKiller Активный пользователь

    С нами с:
    1 ноя 2007
    Сообщения:
    166
    Симпатии:
    0
    Адрес:
    Новосибирск
    Приветствую всех!
    Пишу ребёнку тест по математике (чтобы решала примеры, а скрипт проверял их правильность). Примеры генерируются рекурсивной функцией, которая сама себя запускает ещё раз, если результат примера получается отрицательный (рано дочке ещё отрицательные числа учить, первый класс всё-таки). Вот код:
    Код (Text):
    1. <?php
    2. function generateHigh($min, $max) {
    3.     $a = mt_rand($min, $max);
    4.     $b = mt_rand($min, $max);
    5.     $c = mt_rand($min, $max);
    6.     $d = mt_rand($min, $max);
    7.     $operator1 = mt_rand(1, 2);
    8.     $operator2 = mt_rand(1, 2);
    9.     $operator3 = mt_rand(1, 2);
    10.     switch ( $operator1 ) {
    11.         case 1 : { $result = $a + $b; $showOp1 = " + "; } break;
    12.         case 2 : { $result = $a - $b; $showOp1 = " - "; } break;
    13.     }
    14.     if ( $result < 0 ) { generateHigh($id, $min, $max); }
    15.     switch ( $operator2 ) {
    16.         case 1 : $result = $result + $c; $showOp2 = " + "; break;
    17.         case 2 : $result = $result - $c; $showOp2 = " - "; break;
    18.     }
    19.     if ( $result < 0 ) { generateHigh($id, $min, $max); }
    20.     switch ( $operator3 ) {
    21.         case 1 : $result = $result + $d; $showOp3 = " + "; break;
    22.         case 2 : $result = $result - $d; $showOp3 = " - "; break;
    23.     }
    24.     if ( $result < 0 ) { generateMed($id, $min, $max); }
    25.  
    26.     $_SESSION['QUIZ'] = $a.$showOp1.$b.$showOp2.$c.$showOp3.$d;        // строка, которую нарисуем
    27.     $_SESSION['RESULT'] = $result;            // результат
    28. }
    29. ?>
    В нём случайно генерятся 4 слагаемых и случайно генерятся операторы - "+" или "-". Результатом работы функции должен быть пример вида: 3 + 12 - 14 + 19. Причём: 1) общий результат должен быть неотрицательный. 2) результат операции с каждой парой чисел тоже должен быть неотрицательный.
    Вроде всё правильно написал, но функция всё равно генерит иногда примеры вида 1 - 18 + 2 + 1. То есть, ребёнок явно не сможет от 1 отнять 18... Это всё меня очень печалит...
    Мне пора в первый класс по программированию, да? :(

    Взываю к коллективному разуму!
    Всем заранее спасибо.
     
  2. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    попробуйте такую, без рекурсии
    Код (PHP):
    1. function genExample($min, $max) {
    2.     $s = '';
    3.     $last = 0;
    4.     $ops = array_slice(str_split(str_shuffle('+-+-')),0,3);
    5.     foreach($ops as $k=>$op) {
    6.         if ($op=='-') {
    7.             if ($k==0) {
    8.                 $b = mt_rand($min,$max);
    9.                 $a = mt_rand($b,$max+$b);
    10.                 $last = $a-$b;
    11.                 $s = $a.$op.$b;
    12.             } else {
    13.                 $c = mt_rand($min,$last);
    14.                 $last -= $c;
    15.                 $s .= $op.$c;
    16.             }
    17.         }
    18.         elseif ($op=='+') {
    19.             if ($k==0) {
    20.                 list($a,$b)=array(mt_rand($min,$max), mt_rand($min,$max));
    21.                 $last = $a+$b;
    22.                 $s = $a.$op.$b;
    23.             } else {
    24.                 $c = mt_rand($min,$max);
    25.                 $last += $c;
    26.                 $s .= $op.$c;
    27.             }
    28.         }
    29.     }
    30.     return $s;
    31. }
    32. //
    33. $s = genExample(1,10); // 11-5+3-3
    34. echo $s; 
     
  3. SkyKiller

    SkyKiller Активный пользователь

    С нами с:
    1 ноя 2007
    Сообщения:
    166
    Симпатии:
    0
    Адрес:
    Новосибирск
    runcore, спасибо, попробовал. Работает хорошо, но в 1-м случае из 10 проскакивает подобное: 7+3-10-2. Отрицательный результат. Поэтому, still trying... :(
     
  4. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    а ну да. там получается 0 в одной из операций, и для того чтоб небыло отрицального результата при вычитании нужно брать вторым числом тоже ноль, а при вызове функции мы задали диапазон от 1 до 10. тоесть ноль никак не взять.
    вот подправил
    Код (PHP):
    1. function genExample($min, $max) {
    2.     $s = '';
    3.     $last = 0;
    4.     $ops = array_slice(str_split(str_shuffle('+-+-')),0,3);
    5.     foreach($ops as $k=>$op) {
    6.         if ($op=='-') {
    7.             if ($k==0) {
    8.                 $b = mt_rand($min,$max-1);
    9.                 $a = mt_rand($b,$max);
    10.                 $last = $a-$b;
    11.                 $s = $a.$op.$b;
    12.             } else {
    13.                 $c = mt_rand(min($min,$last),$last);
    14.                 $last -= $c;
    15.                 $s .= $op.$c;
    16.             }
    17.         }
    18.         elseif ($op=='+') {
    19.             if ($k==0) {
    20.                 list($a,$b)=array(mt_rand($min,$max), mt_rand($min,$max));
    21.                 $last = $a+$b;
    22.                 $s = $a.$op.$b;
    23.             } else {
    24.                 $c = mt_rand($min,$max);
    25.                 $last += $c;
    26.                 $s .= $op.$c;
    27.             }
    28.         }
    29.     }
    30.     return $s;
    31. } 
     
  5. drfunjohn

    drfunjohn Активный пользователь

    С нами с:
    22 окт 2012
    Сообщения:
    2
    Симпатии:
    0
    Я не вкурсе, но при вызове функции внутри её ты передаёшь три параметра: $id,$min,$max, тогда как сама функция описана только с двумя.
     
  6. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    там еще и generateMed() какаято встречается )
     
  7. SkyKiller

    SkyKiller Активный пользователь

    С нами с:
    1 ноя 2007
    Сообщения:
    166
    Симпатии:
    0
    Адрес:
    Новосибирск
    $id - это всего лишь номер вопроса. У меня их 20. Передаю id, генерю вопрос, ответ, и по номеру вопроса возвращаю из функции вопрос и ответ через сессию. Согласен, топорно, да. Но по-другому пока не придумал. Просто, когда задавал вопрос тут, $id я опустил.

    Это - сложность вопроса. У меня 3 функции: generateLow (генерирует 2 слагаемых, типа 2+2), generateMed(три слагаемых, типа 6+11-14) и generateHigh(самая сложная, 4 слагаемых, типа 11+16-9+4)
     
  8. SkyKiller

    SkyKiller Активный пользователь

    С нами с:
    1 ноя 2007
    Сообщения:
    166
    Симпатии:
    0
    Адрес:
    Новосибирск
    В-общем, джентльмены, переписал я свою функцию. Вот что значит - работать на свежую голову! :) Ночью сидел, ничего не соображал. Сейчас отдохнувший и выспавшийся - написал за 10 минут :)
    Вот что получилось в итоге:
    Код (Text):
    1.  
    2. <?php
    3. function genMed($id, $min, $max) {
    4. // Функция генерирует пример из трёх слагаемых по следующим условиям:
    5. //    1. Общий результат должен быть неотрицательным
    6. //    2. Результат операции над каждой из двух пар тоже должен быть неотрицательным
    7.  
    8.     $result = 0;
    9.     $a = mt_rand($min, $max);
    10.     $b = mt_rand($min, $max);
    11.     $operator1 = mt_rand(1, 2); // 1 - "-", 2 - "+"
    12.     if ( $operator1 == 1 && ($b >= $a) ) {
    13.         genMed($id, $min, $max);
    14.     } else {
    15.         switch ( $operator1 ) {
    16.             case 1: $result = $a - $b; $showOp1 = " - "; break;
    17.             case 2: $result = $a + $b; $showOp1 = " + "; break;
    18.         }
    19.         $c = mt_rand($min, $max);
    20.         $operator2 = mt_rand(1, 2); // 1 - "-", 2 - "+"
    21.         if ( $operator2 == 1 && ($c >= $result) ) {
    22.             genMed($id, $min, $max);
    23.         } else {
    24.             switch ( $operator2 ) {
    25.                 case 1: $result = $result - $b; $showOp2 = " - "; break;
    26.                 case 2: $result = $result + $b; $showOp2 = " + "; break;
    27.             }
    28.             $_SESSION[$id.'_QUIZ'] = $a.$showOp1.$b.$showOp2.$c;
    29.             $_SESSION[$id.'_RESULT'] = $result;
    30.         }
    31.     }
    32. unset($a, $b, $c, $result, $showOp1, $showOp2, $operator1, $operator2);
    33. }
    34. ?>
    Всем - большое спасибо за помощь и советы!