こんにちは!今回は、PHPの標準関数であるshuffle()について詳しく解説していきます。配列の要素をランダムに並び替える便利な関数です!
shuffle関数とは?
shuffle()関数は、配列の要素をランダムな順序に並び替える関数です。
元の配列を直接変更し(破壊的操作)、インデックスは0から振り直されます。クイズ、抽選、ゲームなどランダム性が必要な場面で活躍します!
基本的な構文
shuffle(array &$array): bool
- $array: シャッフルする配列(参照渡し)
- 戻り値: 成功時は
true、失敗時はfalse
基本的な使用例
シンプルなシャッフル
// 数値の配列
$numbers = [1, 2, 3, 4, 5];
shuffle($numbers);
print_r($numbers);
/*
Array (
[0] => 3
[1] => 1
[2] => 5
[3] => 2
[4] => 4
)
// 実行ごとに異なる順序になる
*/
文字列の配列をシャッフル
// 文字列の配列
$fruits = ['apple', 'banana', 'orange', 'grape'];
shuffle($fruits);
print_r($fruits);
/*
Array (
[0] => grape
[1] => apple
[2] => orange
[3] => banana
)
*/
インデックスの振り直し
// 連想配列のキーは失われる
$data = [
'a' => 'Apple',
'b' => 'Banana',
'c' => 'Cherry'
];
shuffle($data);
print_r($data);
/*
Array (
[0] => Banana
[1] => Cherry
[2] => Apple
)
// キー(a, b, c)は失われて0から振り直される
*/
複数回シャッフル
$cards = ['A', 'K', 'Q', 'J'];
echo "元の配列: " . implode(', ', $cards) . "\n";
for ($i = 1; $i <= 3; $i++) {
shuffle($cards);
echo "シャッフル{$i}: " . implode(', ', $cards) . "\n";
}
/*
元の配列: A, K, Q, J
シャッフル1: Q, A, J, K
シャッフル2: K, J, A, Q
シャッフル3: J, Q, K, A
*/
実践的な使用例
例1: カードゲームシステム
class CardDeck {
private $cards = [];
/**
* デッキを初期化
*/
public function __construct() {
$this->reset();
}
/**
* デッキをリセット
*/
public function reset() {
$suits = ['ハート', 'ダイヤ', 'クラブ', 'スペード'];
$ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
$this->cards = [];
foreach ($suits as $suit) {
foreach ($ranks as $rank) {
$this->cards[] = "{$suit}の{$rank}";
}
}
return $this;
}
/**
* デッキをシャッフル
*/
public function shuffle() {
shuffle($this->cards);
return $this;
}
/**
* カードを引く
*/
public function draw($count = 1) {
return array_splice($this->cards, 0, $count);
}
/**
* 残りのカード枚数
*/
public function count() {
return count($this->cards);
}
/**
* すべてのカードを取得
*/
public function getCards() {
return $this->cards;
}
/**
* 手札を配る
*/
public function deal($players, $cardsPerPlayer) {
$hands = [];
for ($i = 0; $i < $players; $i++) {
$hands["プレイヤー" . ($i + 1)] = $this->draw($cardsPerPlayer);
}
return $hands;
}
/**
* カットする(デッキを分割して入れ替え)
*/
public function cut($position = null) {
if ($position === null) {
$position = rand(1, count($this->cards) - 1);
}
$top = array_slice($this->cards, 0, $position);
$bottom = array_slice($this->cards, $position);
$this->cards = array_merge($bottom, $top);
return $this;
}
}
// 使用例
echo "=== カードゲーム ===\n";
$deck = new CardDeck();
// シャッフル
$deck->shuffle();
echo "デッキ枚数: {$deck->count()}枚\n";
// カードを5枚引く
$cards = $deck->draw(5);
echo "\n引いたカード:\n";
foreach ($cards as $card) {
echo " - {$card}\n";
}
echo "\n残り枚数: {$deck->count()}枚\n";
// 新しいデッキで4人に5枚ずつ配る
echo "\n=== 手札配布 ===\n";
$deck->reset()->shuffle();
$hands = $deck->deal(4, 5);
foreach ($hands as $player => $hand) {
echo "\n{$player}:\n";
foreach ($hand as $card) {
echo " - {$card}\n";
}
}
echo "\n残り枚数: {$deck->count()}枚\n";
例2: クイズシステム
class QuizManager {
/**
* 問題をシャッフル
*/
public static function shuffleQuestions($questions) {
shuffle($questions);
return $questions;
}
/**
* 選択肢をシャッフル
*/
public static function shuffleChoices($question) {
$correctAnswer = $question['answer'];
// 選択肢をシャッフル
shuffle($question['choices']);
// 正解のインデックスを更新
$question['answer_index'] = array_search($correctAnswer, $question['choices']);
return $question;
}
/**
* すべての選択肢をシャッフル
*/
public static function shuffleAllChoices($questions) {
foreach ($questions as &$question) {
$question = self::shuffleChoices($question);
}
return $questions;
}
/**
* ランダムにN問選択
*/
public static function selectRandomQuestions($questions, $count) {
$shuffled = self::shuffleQuestions($questions);
return array_slice($shuffled, 0, $count);
}
/**
* 難易度別にランダム選択
*/
public static function selectByDifficulty($questions, $easy, $medium, $hard) {
$byDifficulty = [
'easy' => [],
'medium' => [],
'hard' => []
];
// 難易度別に分類
foreach ($questions as $question) {
$level = $question['difficulty'];
$byDifficulty[$level][] = $question;
}
// 各難易度からランダムに選択
$selected = [];
if ($easy > 0) {
shuffle($byDifficulty['easy']);
$selected = array_merge($selected, array_slice($byDifficulty['easy'], 0, $easy));
}
if ($medium > 0) {
shuffle($byDifficulty['medium']);
$selected = array_merge($selected, array_slice($byDifficulty['medium'], 0, $medium));
}
if ($hard > 0) {
shuffle($byDifficulty['hard']);
$selected = array_merge($selected, array_slice($byDifficulty['hard'], 0, $hard));
}
// 最終的にシャッフル
shuffle($selected);
return $selected;
}
/**
* クイズを生成
*/
public static function generateQuiz($questions, $count = 10) {
$quiz = self::selectRandomQuestions($questions, $count);
$quiz = self::shuffleAllChoices($quiz);
return $quiz;
}
}
// 使用例
echo "=== クイズシステム ===\n";
$questions = [
[
'question' => 'PHPの開発者は?',
'choices' => ['Rasmus Lerdorf', 'Guido van Rossum', 'Brendan Eich', 'James Gosling'],
'answer' => 'Rasmus Lerdorf',
'difficulty' => 'easy'
],
[
'question' => 'PHPはどの言語から影響を受けた?',
'choices' => ['Perl', 'Python', 'Ruby', 'Java'],
'answer' => 'Perl',
'difficulty' => 'medium'
],
[
'question' => 'PHP 8.0の新機能は?',
'choices' => ['JIT', 'Async/Await', 'Generics', 'Pattern Matching'],
'answer' => 'JIT',
'difficulty' => 'hard'
]
];
// 問題をシャッフル
echo "シャッフル前:\n";
foreach ($questions as $i => $q) {
echo ($i + 1) . ". {$q['question']}\n";
}
$shuffled = QuizManager::shuffleQuestions($questions);
echo "\nシャッフル後:\n";
foreach ($shuffled as $i => $q) {
echo ($i + 1) . ". {$q['question']}\n";
}
// 選択肢をシャッフル
echo "\n=== 選択肢シャッフル ===\n";
$question = $questions[0];
echo "元の選択肢:\n";
foreach ($question['choices'] as $i => $choice) {
echo ($i + 1) . ". {$choice}\n";
}
$shuffledQuestion = QuizManager::shuffleChoices($question);
echo "\nシャッフル後:\n";
foreach ($shuffledQuestion['choices'] as $i => $choice) {
$mark = ($i === $shuffledQuestion['answer_index']) ? ' ← 正解' : '';
echo ($i + 1) . ". {$choice}{$mark}\n";
}
例3: 抽選システム
class LotterySystem {
/**
* 単純抽選(全員から指定人数を選ぶ)
*/
public static function simpleDraw($participants, $winners) {
shuffle($participants);
return array_slice($participants, 0, $winners);
}
/**
* 重み付き抽選
*/
public static function weightedDraw($items, $count = 1) {
$pool = [];
foreach ($items as $item => $weight) {
for ($i = 0; $i < $weight; $i++) {
$pool[] = $item;
}
}
shuffle($pool);
$winners = [];
$selected = [];
foreach ($pool as $item) {
if (!in_array($item, $selected)) {
$winners[] = $item;
$selected[] = $item;
if (count($winners) >= $count) {
break;
}
}
}
return $winners;
}
/**
* 複数回抽選(重複なし)
*/
public static function multipleDraws($participants, $rounds) {
$results = [];
$remaining = $participants;
for ($i = 1; $i <= $rounds; $i++) {
if (empty($remaining)) {
break;
}
shuffle($remaining);
$winner = array_shift($remaining);
$results["第{$i}回"] = $winner;
}
return $results;
}
/**
* グループ抽選
*/
public static function groupDraw($participants, $groupSize) {
shuffle($participants);
$groups = [];
$groupNumber = 1;
foreach (array_chunk($participants, $groupSize) as $group) {
$groups["グループ{$groupNumber}"] = $group;
$groupNumber++;
}
return $groups;
}
/**
* ビンゴ番号生成
*/
public static function generateBingoNumbers($max = 75) {
$numbers = range(1, $max);
shuffle($numbers);
return $numbers;
}
/**
* ペア抽選(ランダムペアリング)
*/
public static function pairDraw($participants) {
shuffle($participants);
$pairs = [];
$pairNumber = 1;
for ($i = 0; $i < count($participants); $i += 2) {
if (isset($participants[$i + 1])) {
$pairs["ペア{$pairNumber}"] = [
$participants[$i],
$participants[$i + 1]
];
$pairNumber++;
} else {
// 奇数の場合、最後の人は余り
$pairs["余り"] = [$participants[$i]];
}
}
return $pairs;
}
}
// 使用例
echo "=== 抽選システム ===\n";
$participants = ['田中', '佐藤', '鈴木', '高橋', '伊藤', '渡辺', '山本', '中村'];
// 単純抽選(3名選出)
echo "単純抽選(3名選出):\n";
$winners = LotterySystem::simpleDraw($participants, 3);
foreach ($winners as $i => $winner) {
echo ($i + 1) . "位: {$winner}\n";
}
// 重み付き抽選
echo "\n=== 重み付き抽選 ===\n";
$items = [
'1等(旅行券)' => 1,
'2等(商品券)' => 3,
'3等(図書カード)' => 10,
'参加賞' => 50
];
$result = LotterySystem::weightedDraw($items, 5);
echo "当選結果:\n";
foreach ($result as $i => $item) {
echo ($i + 1) . ". {$item}\n";
}
// 複数回抽選
echo "\n=== 複数回抽選 ===\n";
$rounds = LotterySystem::multipleDraws($participants, 3);
foreach ($rounds as $round => $winner) {
echo "{$round}: {$winner}\n";
}
// グループ分け
echo "\n=== グループ分け(3人ずつ) ===\n";
$groups = LotterySystem::groupDraw($participants, 3);
foreach ($groups as $groupName => $members) {
echo "{$groupName}: " . implode(', ', $members) . "\n";
}
// ペア抽選
echo "\n=== ペア抽選 ===\n";
$pairs = LotterySystem::pairDraw($participants);
foreach ($pairs as $pairName => $members) {
echo "{$pairName}: " . implode(' & ', $members) . "\n";
}
// ビンゴ
echo "\n=== ビンゴ番号生成 ===\n";
$bingoNumbers = LotterySystem::generateBingoNumbers(20);
echo "最初の10個: " . implode(', ', array_slice($bingoNumbers, 0, 10)) . "\n";
例4: プレイリスト・ランダム再生
class Playlist {
private $songs = [];
private $currentIndex = 0;
private $shuffled = false;
/**
* プレイリストに曲を追加
*/
public function add($song) {
$this->songs[] = $song;
return $this;
}
/**
* 複数の曲を追加
*/
public function addMany($songs) {
$this->songs = array_merge($this->songs, $songs);
return $this;
}
/**
* シャッフル再生を有効化
*/
public function enableShuffle() {
$this->shuffled = true;
shuffle($this->songs);
$this->currentIndex = 0;
return $this;
}
/**
* シャッフル再生を無効化
*/
public function disableShuffle() {
$this->shuffled = false;
$this->currentIndex = 0;
return $this;
}
/**
* 次の曲を取得
*/
public function next() {
if (empty($this->songs)) {
return null;
}
$song = $this->songs[$this->currentIndex];
$this->currentIndex++;
// 最後まで行ったら最初に戻る
if ($this->currentIndex >= count($this->songs)) {
$this->currentIndex = 0;
// シャッフルモードなら再シャッフル
if ($this->shuffled) {
shuffle($this->songs);
}
}
return $song;
}
/**
* 現在の曲を取得
*/
public function current() {
if (empty($this->songs)) {
return null;
}
return $this->songs[$this->currentIndex];
}
/**
* プレイリスト全体を取得
*/
public function getAll() {
return $this->songs;
}
/**
* プレイリストをリセット
*/
public function reset() {
$this->currentIndex = 0;
return $this;
}
/**
* ランダムに曲を選択
*/
public function random() {
if (empty($this->songs)) {
return null;
}
$randomIndex = array_rand($this->songs);
return $this->songs[$randomIndex];
}
}
// 使用例
echo "=== プレイリスト ===\n";
$playlist = new Playlist();
$songs = [
'曲1: Hello World',
'曲2: PHP Blues',
'曲3: Code Symphony',
'曲4: Debug Dance',
'曲5: Function Funk'
];
$playlist->addMany($songs);
// 通常再生
echo "通常再生:\n";
for ($i = 0; $i < 7; $i++) {
echo ($i + 1) . ". " . $playlist->next() . "\n";
}
// シャッフル再生
echo "\nシャッフル再生:\n";
$playlist->reset()->enableShuffle();
for ($i = 0; $i < 7; $i++) {
echo ($i + 1) . ". " . $playlist->next() . "\n";
}
// ランダム選択
echo "\nランダム選択:\n";
for ($i = 0; $i < 3; $i++) {
echo " " . $playlist->random() . "\n";
}
例5: ゲーム要素
class GameHelper {
/**
* ダイスを振る
*/
public static function rollDice($sides = 6, $count = 1) {
$results = [];
for ($i = 0; $i < $count; $i++) {
$results[] = rand(1, $sides);
}
return $results;
}
/**
* ランダムなアイテムを取得
*/
public static function getRandomItem($items) {
shuffle($items);
return $items[0];
}
/**
* ランダムなイベントを発生
*/
public static function triggerRandomEvent($events) {
shuffle($events);
foreach ($events as $event) {
// 確率チェック
if (rand(1, 100) <= $event['probability']) {
return $event;
}
}
return null;
}
/**
* ランダムな敵を出現
*/
public static function spawnEnemy($enemies, $level) {
// レベルに応じた敵をフィルタ
$available = array_filter($enemies, function($enemy) use ($level) {
return $enemy['min_level'] <= $level && $enemy['max_level'] >= $level;
});
if (empty($available)) {
return null;
}
shuffle($available);
return $available[0];
}
/**
* 宝箱の中身をランダム生成
*/
public static function generateTreasure($itemPool, $count = 3) {
shuffle($itemPool);
return array_slice($itemPool, 0, $count);
}
/**
* ランダムマップ生成
*/
public static function generateMap($width, $height, $tiles) {
$map = [];
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
shuffle($tiles);
$map[$y][$x] = $tiles[0];
}
}
return $map;
}
/**
* ランダムクエスト生成
*/
public static function generateQuest($templates, $objectives, $rewards) {
shuffle($templates);
shuffle($objectives);
shuffle($rewards);
return [
'title' => $templates[0]['title'],
'description' => $templates[0]['description'],
'objective' => $objectives[0],
'reward' => $rewards[0]
];
}
}
// 使用例
echo "=== ゲームヘルパー ===\n";
// ダイス
echo "ダイスロール(2個の6面ダイス):\n";
$diceResults = GameHelper::rollDice(6, 2);
echo "出目: " . implode(', ', $diceResults) . " (合計: " . array_sum($diceResults) . ")\n";
// ランダムアイテム
echo "\n=== ランダムアイテム ===\n";
$items = ['ポーション', '魔法の杖', '鋼の剣', '革の鎧', '金貨'];
echo "獲得アイテム: " . GameHelper::getRandomItem($items) . "\n";
// イベント発生
echo "\n=== イベント発生 ===\n";
$events = [
['name' => '宝箱発見', 'probability' => 30],
['name' => '敵遭遇', 'probability' => 50],
['name' => 'NPC出現', 'probability' => 20]
];
$event = GameHelper::triggerRandomEvent($events);
echo "発生イベント: " . ($event ? $event['name'] : 'なし') . "\n";
// 敵出現
echo "\n=== 敵出現 ===\n";
$enemies = [
['name' => 'スライム', 'min_level' => 1, 'max_level' => 5],
['name' => 'ゴブリン', 'min_level' => 3, 'max_level' => 10],
['name' => 'ドラゴン', 'min_level' => 15, 'max_level' => 99]
];
$playerLevel = 5;
$enemy = GameHelper::spawnEnemy($enemies, $playerLevel);
echo "レベル{$playerLevel}で出現: " . ($enemy ? $enemy['name'] : 'なし') . "\n";
// 宝箱
echo "\n=== 宝箱の中身 ===\n";
$treasure = GameHelper::generateTreasure($items, 3);
echo "獲得品: " . implode(', ', $treasure) . "\n";
// クエスト生成
echo "\n=== ランダムクエスト ===\n";
$templates = [
['title' => '討伐依頼', 'description' => 'モンスターを倒せ'],
['title' => '収集依頼', 'description' => 'アイテムを集めろ']
];
$objectives = ['10体倒す', '5個集める', 'ボスを倒す'];
$rewards = ['1000ゴールド', 'レアアイテム', '経験値2倍'];
$quest = GameHelper::generateQuest($templates, $objectives, $rewards);
print_r($quest);
例6: ランダムデータジェネレーター
class RandomDataGenerator {
/**
* ランダムなパスワード生成
*/
public static function generatePassword($length = 12) {
$chars = str_split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*');
shuffle($chars);
return substr(implode('', $chars), 0, $length);
}
/**
* ランダムな色を生成
*/
public static function generateColor() {
$colors = ['赤', '青', '緑', '黄', '紫', 'オレンジ', 'ピンク', '黒', '白', '灰'];
shuffle($colors);
return $colors[0];
}
/**
* ランダムな名前を生成
*/
public static function generateName() {
$firstNames = ['太郎', '次郎', '花子', '美咲', '健太', '愛子'];
$lastNames = ['田中', '佐藤', '鈴木', '高橋', '伊藤', '渡辺'];
shuffle($firstNames);
shuffle($lastNames);
return $lastNames[0] . ' ' . $firstNames[0];
}
/**
* ランダムな日付を生成
*/
public static function generateDate($startYear = 2020, $endYear = 2026) {
$year = rand($startYear, $endYear);
$month = rand(1, 12);
$day = rand(1, 28); // 簡略化のため28日まで
return sprintf('%04d-%02d-%02d', $year, $month, $day);
}
/**
* ランダムなダミーデータ生成
*/
public static function generateDummyData($count = 10) {
$data = [];
for ($i = 0; $i < $count; $i++) {
$data[] = [
'id' => $i + 1,
'name' => self::generateName(),
'color' => self::generateColor(),
'date' => self::generateDate(),
'score' => rand(0, 100)
];
}
return $data;
}
/**
* ランダムなテキストを生成
*/
public static function generateLoremIpsum($wordCount = 50) {
$words = ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur',
'adipiscing', 'elit', 'sed', 'do', 'eiusmod', 'tempor'];
$text = [];
for ($i = 0; $i < $wordCount; $i++) {
shuffle($words);
$text[] = $words[0];
}
return implode(' ', $text);
}
}
// 使用例
echo "=== ランダムデータ生成 ===\n";
// パスワード
echo "ランダムパスワード: " . RandomDataGenerator::generatePassword(16) . "\n";
// 色
echo "ランダム色: " . RandomDataGenerator::generateColor() . "\n";
// 名前
echo "ランダム名前:\n";
for ($i = 0; $i < 3; $i++) {
echo " " . RandomDataGenerator::generateName() . "\n";
}
// ダミーデータ
echo "\n=== ダミーデータ ===\n";
$data = RandomDataGenerator::generateDummyData(5);
foreach ($data as $row) {
echo "ID:{$row['id']} {$row['name']} ({$row['color']}) - {$row['date']} - {$row['score']}点\n";
}
キーを保持したシャッフル
// 連想配列のキーを保持したまま値をシャッフルしたい場合
function shuffle_assoc(&$array) {
$keys = array_keys($array);
shuffle($keys);
$new = [];
foreach ($keys as $key) {
$new[$key] = $array[$key];
}
$array = $new;
return true;
}
// 使用例
$data = [
'a' => 'Apple',
'b' => 'Banana',
'c' => 'Cherry'
];
shuffle_assoc($data);
print_r($data);
/*
Array (
[b] => Banana
[c] => Cherry
[a] => Apple
)
// キーは保持されたまま順序が変わる
*/
まとめ
shuffle()関数の特徴をまとめると:
できること:
- 配列をランダムに並び替え
- ゲーム、クイズ、抽選に活用
- ランダム性が必要な処理
推奨される使用場面:
- カードゲーム
- クイズの問題順・選択肢
- 抽選システム
- プレイリストのシャッフル
- ランダムイベント
特徴:
- 元の配列を直接変更(破壊的)
- キーは0から振り直される
- 擬似乱数を使用
注意点:
- 連想配列のキーは失われる
- 暗号学的に安全な乱数ではない
- 実行ごとに結果が変わる
関連関数:
array_rand(): ランダムなキーを取得rand(): ランダムな整数random_int(): 暗号学的に安全な乱数mt_rand(): より高速な乱数
使い分け:
// 配列全体をシャッフル
shuffle($array);
// ランダムに1つ選ぶ
$key = array_rand($array);
$value = $array[$key];
// ランダムな整数
$number = rand(1, 100);
// 暗号学的に安全な乱数
$secure = random_int(1, 100);
shuffle()は、配列をランダムに並び替える最もシンプルな方法です。ゲーム、クイズ、抽選など、ランダム性が必要な場面で積極的に活用しましょう!
