【Python】コンソールの一人用なんちゃって海底探険

一人用の海底探検ゲームを作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439672/c0477937-4e05-4cf2-a60c-cfac0356aa59.png)

**※海底探検は、人が宝物を拾うと共通のタンクの酸素が減っていくというところが面白さのキモなので、一人用ではそんなに面白くありません。**
お気楽な運試しです。

- 進行中の様子

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439672/41b57ccb-53b7-0c0a-76f9-ccecebab385f.png)

一人だと、何も持たずに一番奥に戻ってから浮かび上がるのが最適な感じがあるので戦略性がないですね。
（次はもうちょっと面白いのを作るか、NPCも入れたいですね。）

## 仕様

一人用の「海底探検」（Deep Sea Adventure）ボードゲームのテキストベースのコンソール版です。プレイヤーは海底に潜り、宝物を集めながら酸素の残量に注意し、無事に潜水艦に戻ることを目指します。プレイヤーは深く潜れば潜るほど高価な宝物を得ることができますが、酸素の消費も増えます。

- ゲームの目的
より多くの宝物を集め、無事に潜水艦に戻ること。

- ゲームの流れ
プレイヤーの酸素は25単位、位置は0からスタートします。

- ボード
全長63マスのボードが生成されます。
各セクションに応じた宝物の価値が異なります。
浅い部分（1〜21マス）：低得点の宝物（1, 2）
中間部分（22〜42マス）：中得点の宝物（3, 4）
深い部分（43〜63マス）：高得点の宝物（5, 6）

- ターンの進行
プレイヤーは3つのダイスを振り、その合計値で進むマス数を決定します。
プレイヤーは進むか戻るかの選択を行います。

進む場合、指定されたマス数だけ進みます。最後のマスに到達すると、引き返します。
戻る場合、指定されたマス数だけ戻ります。潜水艦に戻るまでの道中も宝物を拾うことができます。

- 宝物の取得

プレイヤーが止まったマスに宝物がある場合、その宝物を拾うかどうかを選択できます。
拾った宝物はプレイヤーの得点に加算されます。もともとの海底探検は何点かはめくってみるまでわかりませんが、これは一人用なので止まったマスは開示されています。

- 酸素の消費

各ターンごとに、持っている宝物の数に応じて酸素が消費されます（宝物1つにつき1単位の酸素）。
もし酸素が0になった場合、ゲームオーバーとなり、得点は0となります。

現在位置：👤
宝物（低得点）：□
宝物（中得点）：▩
宝物（高得点）：■
何もない：☑

## すべてのコード

```python
import random

class DeepSeaAdventure:
    def __init__(self):
        self.oxygen = 25
        self.position = 0
        self.treasures = []
        self.board = self.generate_board()
        self.returning = False

    def generate_board(self):
        board = []
        for i in range(21):
            board.append(random.choice([1, 2]))  # 浅い部分：低得点の宝物
        for i in range(21, 42):
            board.append(random.choice([3, 4]))  # 中間部分：中得点の宝物
        for i in range(42, 63):
            board.append(random.choice([5, 6]))  # 深い部分：高得点の宝物
        return board

    def roll_dice(self):
        return random.randint(1, 3), random.randint(1, 3), random.randint(1, 3)

    def display_status(self):
        print(f"現在位置: {self.position}")
        print(f"酸素: {self.oxygen}")
        print(f"宝物: {self.treasures}")
        print("ボード: ", end="")
        for idx, val in enumerate(self.board):
            if idx == self.position:
                print("👤", end=" ")  # 現在位置
            elif val == 0:
                print("☑", end=" ")  # 何もない
            elif val == -1:
                print("⚰️", end=" ")  # 終了ポイント
            elif val in [1, 2]:
                print("□", end=" ")  # 低得点の宝物
            elif val in [3, 4]:
                print("▩", end=" ")  # 中得点の宝物
            else:
                print("■", end=" ")  # 高得点の宝物
        print()

    def move(self, direction):
        dice1, dice2, dice3 = self.roll_dice()
        steps = dice1 + dice2 + dice3
        print(f"さいころの結果: {dice1} + {dice2} + {dice3} = {steps}")
        input("Enterキーを押して続けます...")

        if direction == 'm' and not self.returning:
            self.position += steps
            if self.position >= len(self.board):
                self.position = len(self.board) - 1
                self.returning = True  # 最後のマスに到達したら引き返しを開始
        elif direction == 'r' or self.returning:
            self.position -= steps
            if self.position < 0:
                self.position = 0

        if self.treasures:
            self.oxygen -= 1 + len(self.treasures)
            if self.oxygen <= 0:
                self.board[self.position] = -1  # ゲームオーバーの位置に棺桶を表示
                self.display_status()  # ゲームオーバー前に表示
                self.game_over()

        if self.position == 0 and self.returning:
            self.successful_return()

        if self.board[self.position] != 0 and self.board[self.position] != -1:
            self.pick_treasure()

    def pick_treasure(self):
        if self.board[self.position] != 0 and self.board[self.position] != -1:
            treasure_value = self.board[self.position]
            choice = input(f"宝物 (価値: {treasure_value}ポイント) を拾いますか？ (y/n): ")
            if choice.lower() == 'y':
                self.treasures.append(treasure_value)
                self.board[self.position] = 0
                print(f"{treasure_value}ポイントの宝物を拾いました！")

    def game_over(self):
        print("ゲームオーバー⚰️")
        score = 0
        print(f"あなたの得点: {score}")
        exit()

    def successful_return(self):
        print("おかえりなさい！")
        score = sum(self.treasures)
        print(f"あなたの得点: {score}")
        exit()

    def play(self):
        print("""
        Welcome to Deep Sea Adventure!

          ___
         / _ \\
        | / \\ |
        ||   || _______
        ||   || |     |
        ||   || |SUB  |
        ||   || |_____|
        | \\_/  |
         \\___ /

        """)

        while self.oxygen > 0:
            self.display_status()
            if not self.returning:
                action = input("行動を選んでください - Enterで進む または 潜水艦に戻る (r): ")
                if action == 'r':
                    self.returning = True
                    self.move('r')
                else:
                    self.move('m')
            else:
                self.move('r')


        self.game_over()

if __name__ == "__main__":
    game = DeepSeaAdventure()
    game.play()

```

# 元ネタ

https://oinkgames.com/ja/games/analog/deep-sea-adventure/