5

SQLデータベース(実際にはjavascriptとsqlite)に一連のクイズゲームの質問があります。問題にはすべて 1 から 5 までの難易度があり、5 が最も難しいです。これは、データの単純化された視覚化です...

+---------+--------------+  
| | ID | 難易度 |   
+---------+--------------+  
| | 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をグループ化する代わりに、各セクションを難易度別にグループ化してから、1つずつ引き出してみませんか。または、ランダムに並べ替えられたら、ランダムな難易度からそれらを引き出し、それぞれから質問があるまでその難易度を削除することができます。

これは私がsje397に答えて考えていたものなので、それを私の答えに追加します。

他のすべての選択肢が合計して最大のグループから1を引いたものになる限り、凝集は発生しません(アルゴリズムが正しいと仮定します)。ただし、アルゴリズムは基本的に、Aが他のグループのサイズと等しくなるまで、A(選択肢の数が最も多いグループ)からの選択、別のグループからの選択、Aからの選択などの形式を取ります。したがって、最良のアルゴリズムは、最大のグループを見つけてそこから選択するためにチェックします。次に、別のグループから選択し、次にどのグループが最大であるかを確認し、以前に選択したグループでない限り、そのグループから選択します。

于 2010-07-22T23:14:18.180 に答える
2

コードでの次の戦略はどうですか:(以下は箇条書きでしたが、箇条書きの後にコードを表示して正しく表示することができませんでした-このサイトが使用するこの「マークダウン」ガベージを徹底的に嫌います)

難易度順に質問を並べ替える

質問を「簡単な」リストと「難しい」リストの2つのリストに途中で分割します

簡単なリストと難しいリストから1つずつ質問を取り、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

ランダムにシャッフルされた入力配列を反復処理し、前の要素と同じ難易度の要素にヒットするたびに、同じ難易度の次の要素と交換します。私の頭の中で、これはあなたの最初の入力を次のように変えると思います:1,5,1,2,3,2,3,2,4,2

入力によっては、このアプローチは最後に凝集を引き起こす可能性がありますが、十分に良いかもしれません...

入力が必要なものよりも大きい場合は、前の要素と同じ難易度の要素を削除することもできます。

于 2010-07-22T23:14:39.470 に答える
1

本当にランダムなサンプルでは、​​「塊」自然に現れます。したがって、これらを削除したい場合は、手動で何かを強制する必要があります。たとえば、難易度のパターンを指定し、各難易度に一致するランダムな質問を選択します。

于 2010-07-22T23:11:57.697 に答える
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 に答える