Возникла необходимость написать алгоритм генерирующий простую математическую формулу и список возможных ответ, включая правильный ответ. На Хабре нашел пример «Матановая капча», но она слишком сложная, скорей подойдет для сайта математиков. Пришлось изобретать самому. Предварительно озвучим условия которым должна удовлетворят наша функция:
- формула- вопрос должна быть достаточно сложной, что бы боты могли ее прочитать, то есть что-то тип: 1+2 = ? нам не подходит
- формула вопрос должен быть в тоже время достаточно простой, чтобы человек мог в уме посчитать результат
- сложность формулы должна как-то регулироваться
Привожу код функции:
function formula($tmpl = », $max_result = 50, $max_abcdf = 20 ){ $arr_tmpl = array( ‘(%d %s %d) %s (%d %s %d)’, ‘%d %s (%d %s %d) %s %d’, ‘(%d %s %d) %s (%d %s %d) %s %d’, ‘(%d %s %d) %s %d’, ‘%d %s (%d %s %d)’, ‘%d %s %d %s %d %s %d %s %d’, ‘%d %s %d %s %d %s %d’, ‘%d %s %d %s %d’, ); if(!$tmpl) $tmpl = $arr_tmpl[array_rand($arr_tmpl)]; $operators = array(‘*’, ‘/’, ‘+’, ‘-‘); do{ shuffle($operators); list($p1, $p2, $p3, $p4) = $operators; $a = rand(1,$max_abcdf); $b = rand(1,$max_abcdf); $c = rand(1,$max_abcdf); $d = rand(1,$max_abcdf); $f = rand(1,$max_abcdf); $st = sprintf ($tmpl, $a, $p1, $b, $p2, $c, $p3, $d, $p4, $f); $e_st = ‘$result = ‘. $st.’;’; @eval($e_st); $mod = fmod($result, 1); }while($result <= 0 OR $mod!=0 OR $result>$max_result); $arr_rand = range(0,$max_result); unset($arr_rand[$result]); shuffle($arr_rand); return array_merge( array($st, $result), $arr_rand); }
1234567891011121314151617181920212223242526272829303132 | function formula($tmpl = », $max_result = 50, $max_abcdf = 20 ){ $arr_tmpl = array( ‘(%d %s %d) %s (%d %s %d)’, ‘%d %s (%d %s %d) %s %d’, ‘(%d %s %d) %s (%d %s %d) %s %d’, ‘(%d %s %d) %s %d’, ‘%d %s (%d %s %d)’, ‘%d %s %d %s %d %s %d %s %d’, ‘%d %s %d %s %d %s %d’, ‘%d %s %d %s %d’, ); if(!$tmpl) $tmpl = $arr_tmpl[array_rand($arr_tmpl)]; $operators = array(‘*’, ‘/’, ‘+’, ‘-‘); do{ shuffle($operators); list($p1, $p2, $p3, $p4) = $operators; $a = rand(1,$max_abcdf); $b = rand(1,$max_abcdf); $c = rand(1,$max_abcdf); $d = rand(1,$max_abcdf); $f = rand(1,$max_abcdf); $st = sprintf ($tmpl, $a, $p1, $b, $p2, $c, $p3, $d, $p4, $f); $e_st = ‘$result = ‘. $st.‘;’; @eval($e_st); $mod = fmod($result, 1); }while($result <= 0 OR $mod!=0 OR $result>$max_result); $arr_rand = range(0,$max_result); unset($arr_rand[$result]); shuffle($arr_rand); return array_merge( array($st, $result), $arr_rand);} |
Аргументы функции:
- $tmpl — тут можно задать свой шаблон для формулы, необязательный параметр, если шаблон не задан, будет выбран случайный шаблон массива $arr_tmpl
- $max_result — максимальное значение, правильного ответа, чем меньше этот параметр тем проще получится формула
- $max_abcdf — операнды формулы генерируются случайным образом, этот параметр задает максимально допустимое значение
Принцип работы:
Генерация формулы происходит в цикле do-while, опишу последовательность действий по пунктам:
- массив операторов (+, -, *, /) всего четыре – перемешивается и присваивается переменным $p1-$p4
- генерируются 5 случайных чисел $a-$f операнды, установить максимально значение операнда можно параметром $max_abcdf
- эти значения подставляются в шаблон с помощью функции sprintf () в итоге после этого мы должны получить правильный php код
- затем делаем eval кода – получаем результат $result
- вычисляем дробную часть $mod
- теперь проверяем полученные результат :
- меньше или равно 0
- есть дробная часть $mod
- $result результат больше заданного $max_result
если одно из этих условий выполнено – значит нас не устроит токай результат и мы начинаем цикл заново.
Таким образом мы подбираем такую комбинацию чисел и операторов, чтобы у нас получился простой ответ. При значении $max_result = 50 на подбор уходит 2-4 циклов. Чем меньше $max_result — тем больше времени уйдет на подбор аргументов. Меньше 20 не рекомендую ставить.
Функция возвращает массив: [0] — строка формула, [1] — правильный ответ, далее идут случайные числа это если нам надо организовать возможность выбора из вариантов ответа.
Пример работы :
$arr = formula(); echo ‘[crayon-5f366510c615c252661898 ]’;print_r($arr);echo ‘
12 | $arr = formula();echo ‘[crayon-5f366510c615c252661898 ]’;print_r($arr);echo ‘ |
’;
[/crayon]
смотреть формулу