5

我在 sql 数据库中有一组问答游戏问题(实际上是 javascript 和 sqlite)。这些问题都有一个从 1 到 5 的难度级别,5 是最难的。这是数据的简化可视化...

+---------+-----------+  
| 编号 | 困难|   
+---------+-----------+  
| 1 | 1 |    
| 2 | 5 |    
| 3 | 2 |    
| 4 | 3 |    
| 5 | 2 |
| 6 | 2 |    
| 7 | 4 |    
| 8 | 1 |    
| 9 | 5 |    
| 10 | 3 |      
+---------+-----------+   

现在我可以在 sql 或代码中对这些内容进行洗牌,因此它们的顺序是随机的,没有重复,但我也想控制难度字段的排序方式。

因此,例如,我可以有一组打乱的问题,其中难度级别的顺序看起来像这样......

1,1,5,2,3,3,2,2,2,4

这有几个“难点”,这不是我想要的。玩游戏的用户会得到几组同样困难的问题。这样的订单会更好...

1,2,3,2,5,4,1,2,3,2

我想确保问题被打乱,但没有困难结块。在几乎没有“团块”的情况下均匀分布困难。对 MySQL/javascript(或 PHP)的任何帮助都会很棒。

4

5 回答 5

5

与其将所有 id 分组在一起,为什么不按难度对它们进行分组,将每个部分随机化,然后将它们一个一个地拉出来。或者,一旦它们被随机排序,您就可以将它们从随机难度中拉出来,然后删除该难度级别,直到每个问题都有问题。

这是我在回答 sje397 时所考虑的,所以我会将其添加到我的答案中。

只要所有其他选择加起来最大组减一,您就不会出现聚集(假设您的算法是正确的)。但是,该算法基本上会采用从 A 中挑选(选择数量最多的组)、从另一组中挑选、从 A 中挑选等形式,直到 A 等于其他组的大小。因此,最好的算法会检查以找到最大的组并从中进行选择。然后它会从另一个组中选择,然后检查哪个组是最大的,然后从中进行选择,除非它是先前选择的组,等等。

于 2010-07-22T23:14:18.180 回答
2

下面的策略怎么样,在代码中:(以下是一个项目符号列表,但我无法让代码出现在项目符号列表之后以正确显示 - 我彻底讨厌这个网站使用的这个“降价”垃圾)

按难度排序问题

将问题中途分成两个列表,一个“简单”列表和一个“困难”列表

从简单和困难列表中逐一回答问题,在两者之间交替进行。(这意味着在问题的顺序上,您可能会有从易到难的轻微趋势,您可能会也可能不会接受。)

原始实现:

$resultset = your_preferred_query_function('SELECT id FROM question ORDER BY difficulty');
$questions_temp = array();
while ( $row = mysqli_fetch_assoc() ) {
    $questions_temp[] = $row['id'];
}
if ( count($questions) % 2 ) {
    $loop_limit = (count($questions) - 1) / 2;
    $halfway = (count($questions) + 1) / 2;
    $questions[0] = $questions_temp[$loop_limit];
} else {
    $loop_limit = count($questions) / 2;
    $halfway = count($questions) / 2;
    $questions = array();
}
for ($i=0; $i<$loop_limit; $i++) {
    $questions[] = $questions_temp[$i];
    $questions[] = $questions_temp[$halfway+$i];
}

现在$questions是一个包含按我建议排序的问题的数组。

于 2010-07-22T23:25:32.257 回答
1

那么在一个真正随机的样本中,“团块”自然会出现因此,如果您想删除这些,您必须手动执行某些操作,例如指定难度模式并选择与每个难度级别匹配的随机问题

于 2010-07-22T23:11:57.697 回答
1

遍历一个随机打乱的输入数组,每当您遇到与前一个难度级别相同的元素时,就与下一个难度级别不同的元素进行交换。就在我的脑海中,我认为这会将您的初始输入变成:1,5,1,2,3,2,3,2,4,2

根据输入,这种方法可能会导致最后结块,但可能已经足够好了......

如果您的输入比您需要的大,您也可以删除任何与前一个具有相同难度的元素。

于 2010-07-22T23:14:39.470 回答
0

一个非常简单的解决方案(虽然它不是很有效)将是:

<?php

        define('MAX_QUESTIONS',10);

        $dbh = new PDO("mysql:dbname=so;host=127.0.0.1","","");
        $sql = "SELECT * FROM q group by difficulty order by rand()";
        $data = $dbh->query($sql);
        $rows = $data->fetchAll();
        $ids = getIds($rows);
        while (count($rows) < MAX_QUESTIONS ) {
                $sql = "SELECT * FROM q where id not in ".
                       "(".join(",",$ids).") group by difficulty order by rand()";
                $data = $dbh->query($sql);
                $more_rows = $data->fetchAll();
                $rows = array_merge($rows,$more_rows);
                $ids = getIds($rows);
        }
        print_r($rows);

        function getIds($data) {
                $ids = array();
                foreach ($data as $v) {
                        $ids[] = $v['id'];
                }
                return $ids;
        }

?>

这是必需的,因为 MySQL 的 group by 总是返回相同的 id,无论您之前是否订购过(即使在子查询中)。

这样做的好处是它保证没有“团块”(可能会为最终的问题返回空值,这会产生“团块”,但您可以在特殊情况下这样做)

坏事是您需要的不仅仅是一个查询,而且通过 rand() 进行排序非常低效,但如果您的表很小,它可能实际上并不重要。

于 2010-07-22T23:34:04.433 回答