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()






