Cursorを使用してSwiftでCLI RPGを作ってみる(作らせてみる)
「SwiftでCLIでRPGを作ってください」から始まり、
少しずつ改良を命令していった、現状態。
ゲームの説明(当然Cursorにさせる)
ゲームの説明をしてください
はい、このRPGゲームの説明をさせていただきます:
ゲームの基本システム:
プレイヤーは勇者として、15種類のモンスターと戦闘を行います
モンスターを倒すと経験値(EXP)とゴールドを獲得できます
レベルアップすると、HP、攻撃力、防御力が上昇します
勇者の特徴:
名前と日付に基づいて初期ステータスが決定されます
基本値(HP: 100、攻撃力: 20、防御力: 10)を基準に、0%から50%の範囲でランダムな増加値が付加されます
レベルアップ時の成長:
HP: +20
攻撃力: +5
防御力: +3
モンスターの特徴:
15種類のモンスターが存在し、それぞれ異なるステータスを持っています
ゲーム開始時に、各モンスターの基本ステータスに±50%のランダムな変動が加えられます
モンスターは総合力(HP + 攻撃力 + 防御力)の順に弱い順から強い順にソートされます
ゲームの進行:
メインメニュー:
戦闘:モンスターと戦闘を行います
休憩:100Gを支払ってHPを全回復できます
終了:ゲームを終了します
戦闘システム:
ランダムなモンスターが出現します
各ターンで以下の選択が可能:
攻撃:モンスターにダメージを与えます
逃げる:戦闘から撤退します
ダメージ計算:攻撃力 – 防御力(最小1ダメージ)
報酬システム:
モンスターを倒すとEXPとゴールドを獲得
獲得EXPはモンスターの基本EXP値
獲得ゴールドはモンスターのEXP値の2倍
ゲームの目的:
全てのモンスター(15種類)を倒すこと
モンスターを倒すと記録され、進行状況が表示されます
全てのモンスターを倒すとゲームクリア
HPが0になるとゲームオーバー
表示される情報:
勇者の現在のステータス(HP、攻撃力、防御力、レベル、EXP、所持金)
モンスター一覧(総合力順)
倒したモンスターの記録(マークで表示)
このゲームは、戦略性と運の要素を組み合わせたシンプルなRPGとなっています。
Program
import Foundation // キャラクターの基本クラス class Character { var name: String var level: Int var hp: Int var maxHp: Int var attack: Int var defense: Int var exp: Int var expToNextLevel: Int var gold: Int // 所持金を追加 init(name: String) { self.name = name self.level = 1 // 名前と日付からステータスを計算 let calendar = Calendar.current let today = Date() let components = calendar.dateComponents([.year, .month, .day], from: today) // 名前の文字列を数値に変換 let nameValue = name.unicodeScalars.reduce(0) { $0 + Int($1.value) } // 日付と名前から乱数のシードを生成 let seed = (components.year ?? 0) * 10000 + (components.month ?? 0) * 100 + (components.day ?? 0) + nameValue // シードを使用して乱数を生成 var random = seed func nextRandom() -> Double { random = (random * 1103515245 + 12345) & 0x7fffffff return Double(random) / Double(0x7fffffff) } // 基本値からランダムな増加値を計算 let baseHp = 100 let baseAttack = 20 let baseDefense = 10 // 0%から50%の範囲でランダムな増加 let hpBonus = Int(Double(baseHp) * nextRandom() * 0.5) let attackBonus = Int(Double(baseAttack) * nextRandom() * 0.5) let defenseBonus = Int(Double(baseDefense) * nextRandom() * 0.5) self.maxHp = baseHp + hpBonus self.hp = maxHp self.attack = baseAttack + attackBonus self.defense = baseDefense + defenseBonus self.exp = 0 self.expToNextLevel = 100 self.gold = 1000 // 初期ステータスを表示 print("\n\(name)の初期ステータス:") print("HP: \(maxHp) (基本値: \(baseHp) + \(hpBonus))") print("攻撃力: \(attack) (基本値: \(baseAttack) + \(attackBonus))") print("防御力: \(defense) (基本値: \(baseDefense) + \(defenseBonus))") } func levelUp() { level += 1 maxHp += 20 hp = maxHp attack += 5 defense += 3 expToNextLevel *= 2 print("\(name)はレベル\(level)になりました!") print("HP: \(maxHp) (+20)") print("攻撃力: \(attack) (+5)") print("防御力: \(defense) (+3)") } func gainExp(_ amount: Int) { exp += amount while exp >= expToNextLevel { exp -= expToNextLevel levelUp() } } } // モンスタークラス class Monster { var name: String var hp: Int var attack: Int var defense: Int var exp: Int init(name: String, hp: Int, attack: Int, defense: Int, exp: Int) { self.name = name self.hp = hp self.attack = attack self.defense = defense self.exp = exp } } // ゲームクラス class Game { private var player: Character private var defeatedMonsters: Set<String> = [] // 倒したモンスターの名前を記録 private let monsterNames = [ "スライム", "ゴブリン", "オーク", "ドラゴン", "キメラ", "ミノタウロス", "グリフォン", "ケルベロス", "フェニックス", "ハイドラ", "バジリスク", "サイクロプス", "メデューサ", "ケンタウロス", "ミイラ" ] private let baseMonsterStats: [(hp: Int, attack: Int, defense: Int, exp: Int)] = [ (50, 15, 5, 30), // 弱い (80, 25, 10, 50), (120, 35, 15, 80), (150, 40, 18, 120), (160, 38, 15, 100), (170, 40, 18, 130), (180, 42, 18, 150), (190, 45, 20, 160), (200, 45, 20, 150), (220, 48, 25, 180), (230, 52, 30, 190), (250, 50, 28, 200), (180, 42, 22, 140), (160, 38, 15, 120), (140, 35, 12, 100) // 強い ] private var monsterStats: [(hp: Int, attack: Int, defense: Int, exp: Int)] = [] init() { print("勇者の名前を入力してください: ", terminator: "") let name = readLine() ?? "勇者" player = Character(name: name) // モンスターの初期ステータスを設定 monsterStats = baseMonsterStats.map { stats in let hpVariation = Int(Double(stats.hp) * 0.5) let attackVariation = Int(Double(stats.attack) * 0.5) let defenseVariation = Int(Double(stats.defense) * 0.5) let expVariation = Int(Double(stats.exp) * 0.5) let hp = max(1, stats.hp + Int.random(in: -hpVariation...hpVariation)) let attack = max(1, stats.attack + Int.random(in: -attackVariation...attackVariation)) let defense = max(1, stats.defense + Int.random(in: -defenseVariation...defenseVariation)) let exp = max(1, stats.exp + Int.random(in: -expVariation...expVariation)) return (hp: hp, attack: attack, defense: defense, exp: exp) } // 初期モンスターステータスを表示 print("\nモンスターの初期ステータス:") for (index, stats) in monsterStats.enumerated() { print("\(monsterNames[index]): HP\(stats.hp) 攻撃力\(stats.attack) 防御力\(stats.defense) EXP\(stats.exp)") } } private func showProgress() { // モンスターの総合力を計算してソート let sortedMonsters = monsterNames.enumerated().map { (index, name) -> (name: String, power: Int) in let stats = monsterStats[index] let power = stats.hp + stats.attack + stats.defense return (name: name, power: power) }.sorted { $0.power < $1.power } print("\n進行状況: \(defeatedMonsters.count)/\(monsterNames.count)") print("\nモンスター一覧(総合力順):") for monster in sortedMonsters { let stats = monsterStats[monsterNames.firstIndex(of: monster.name)!] print("\(monster.name): HP\(stats.hp) + 攻撃力\(stats.attack) + 防御力\(stats.defense) = 総合力\(monster.power)") } print("\n倒したモンスター: ", terminator: "") for monster in sortedMonsters { print(defeatedMonsters.contains(monster.name) ? "*" : "-", terminator: "") } print("\n*: 倒したモンスター") } private func showEnding() { print("\n🎉 おめでとうございます! 🎉") print("\(player.name)は全てのモンスターを倒しました!") print("\n最終ステータス:") print("レベル: \(player.level)") print("HP: \(player.maxHp)") print("攻撃力: \(player.attack)") print("防御力: \(player.defense)") print("所持金: \(player.gold)G") print("\nゲームクリア!") } private func showBadEnding() { print("\n💀 ゲームオーバー 💀") print("\(player.name)は倒れてしまいました...") print("\n最終ステータス:") print("レベル: \(player.level)") print("HP: \(player.maxHp)") print("攻撃力: \(player.attack)") print("防御力: \(player.defense)") print("所持金: \(player.gold)G") print("倒したモンスター: \(defeatedMonsters.count)/\(monsterNames.count)") print("\nまた挑戦してください!") } private func createMonster() -> Monster { // ランダムな名前とステータスを選択 let index = Int.random(in: 0..<monsterNames.count) let name = monsterNames[index] let stats = monsterStats[index] return Monster(name: name, hp: stats.hp, attack: stats.attack, defense: stats.defense, exp: stats.exp) } func start() { while true { print("\n=== \(player.name)のステータス ===") print("レベル: \(player.level)") print("HP: \(player.hp)/\(player.maxHp)") print("攻撃力: \(player.attack)") print("防御力: \(player.defense)") print("EXP: \(player.exp)/\(player.expToNextLevel)") print("所持金: \(player.gold)G") showProgress() print("\n1: 戦闘") print("2: 休憩(100G)") print("3: 終了") print("選択してください (1-3): ", terminator: "") if let choice = readLine(), let choiceInt = Int(choice) { switch choiceInt { case 1: battle() if defeatedMonsters.count == monsterNames.count { showEnding() return } case 2: if player.gold >= 100 { player.hp = player.maxHp player.gold -= 100 print("HPが全回復しました!(100G支払いました)") } else { print("所持金が足りません!(100G必要です)") } case 3: print("ゲームを終了します。") return default: print("無効な選択です。") } } } } private func battle() { let monster = createMonster() print("\n\(monster.name)が現れた!") print("HP: \(monster.hp)") print("攻撃力: \(monster.attack)") print("防御力: \(monster.defense)") while monster.hp > 0 && player.hp > 0 { print("\n\(player.name)のHP: \(player.hp)") print("\(monster.name)のHP: \(monster.hp)") print("\n1: 攻撃") print("2: 逃げる") print("選択してください (1-2): ", terminator: "") if let choice = readLine(), let choiceInt = Int(choice) { switch choiceInt { case 1: // プレイヤーの攻撃 let damage = max(0, player.attack - monster.defense) monster.hp -= damage print("\(player.name)の攻撃!\(monster.name)に\(damage)のダメージ!") // モンスターの攻撃 if monster.hp > 0 { let monsterDamage = max(0, monster.attack - player.defense) player.hp -= monsterDamage print("\(monster.name)の攻撃!\(player.name)に\(monsterDamage)のダメージ!") } case 2: print("逃げ出した!") return default: print("無効な選択です。") } } } if monster.hp <= 0 { print("\n\(monster.name)を倒した!") player.gainExp(monster.exp) // モンスターの強さに応じて獲得金を設定 let goldReward = monster.exp * 2 player.gold += goldReward print("\(goldReward)Gを獲得しました!") // 倒したモンスターを記録 defeatedMonsters.insert(monster.name) // 初めて倒したモンスターの場合、特別なメッセージを表示 if defeatedMonsters.count == 1 { print("\n初めてのモンスターを倒しました!") } else if defeatedMonsters.count == monsterNames.count { print("\n全てのモンスターを倒しました!") } } else if player.hp <= 0 { print("\n\(player.name)は倒れてしまった...") showBadEnding() exit(0) } } } // シード付き乱数生成器 struct SeededRandomNumberGenerator: RandomNumberGenerator { private var seed: UInt64 init(seed: UInt64) { self.seed = seed } mutating func next() -> UInt64 { seed = seed &* 6364136223846793005 &+ 1 return seed } } // ゲームを開始 let game = Game() game.start()