@namif017

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

特定のクラスのみユーザーからの入力が必要な時の対処法

こういった場での質問が初めてなので勝手が分かりません。多少のことは多めに見ていただけると嬉しいです。

本題

現在c#の勉強中でオセロのコンソールアプリを作っています。

MVCとオブジェクト指向の練習としてそれらの原則に従ったプログラミングをしたいのですが問題が発生しました。


//このアプリの大元。全体の進行や画面描画の指示、入力の受け取りや加工はここでやりたい
class Othello{
    Game game = new Game();
    Display display = new Display(game);

    While(!ゲームセット){
        display.盤面表示
        game.PlayTurn();
    }

    display.結果表示
}

//ゲームのロジックを全部担当させる
class Game{
    IPlayer[] players;
    int trunPlayerIndex = 0;

    //初期化など色々

    // 1ターン進める
    public PlayTurn(){
        IPlayer turnPlayer = players[turnPlayerIndex];
    }
}

//ゲームの表示関連を全部担当させる
class Display{
    
}

//コマを置いたりひっくり返したりをここに任せたい
interface IPlayer{
    void Place()
}

abstract class Player: IPlayer{
    public abstract void Place(){
        (int x, int y) = selectPlaceSquare();

        //x, yのマスに駒を置き裏返したりの処理を色々
    }

    //駒を置くマスを決める
    abstract (int x, int y) selectPlaceSquare()
}

class ComputerPlayer: Player{
    public override (int x, int y) SelectPlaceSquare(){
        //置けるマスからランダムなマスを返す
    }
}

class UserPlayer{
    public override (int x, int y) SelectPlaceSquare(){
        //ReadLine()した値を返り値にしたい
        //でもWriteLineとかReadLineとかはここに書きたくない
    }
}

とりあえず今できてる部分がこんな感じの流れです。
ここでUserPlayerのSelectPlaceSquare()で

Console.WriteLine(”駒を置くマスを入力してください”);
string placeData = Console.ReadLine();

という処理を挟んでそれを加工したものをPlayerのSelectPlaceSquareの返り値としたいのです。

オブジェクト指向としてはturnPlayerがUserPlayerの時だけifなどでOthelloクラスに返して表示、入力を行うのもおかしいでしょうし、かと言ってUserPlayerのSelectPlaceSquareにConsole.Writelineなどを書くのもMVCとして違う気がします。

目標としてはOthelloクラスやGameの中で

if(turnPlayer is UserPlayer){}

等を使わずに

・ユーザーからの入力が必要だということをUserPlayerで決める。
・入力が必要であるという表示はOthelloがDisplayの関数を呼ぶことによって行う。

という事です

どうしたらこの状態を綺麗に実装できるでしょうか。ご協力お願いします

0 likes

1Answer

クリーンアーキテクチャも考慮するといいですよ。

  • Playerが欲しいのは座標データ
  • 座標データを返す interface SelectPlace を定義
  • ランダムな座標を返す RandomSelectPlace implements SelectPlace を実装
  • ユーザに座標入力させる KeyboardSlectPlace implements SelectPlace も実装
  • Playerに コンストラクタかPlace(SelectPlace) で座標入力オブジェクトを渡す

参考: Strategyパターン

1Like

Comments

  1. @namif017

    Questioner

    回答ありがとうございます。

    この場合SelectPlaceはどこに実装することにすればいいのでしょうか。
    Game等に置いておくならそこからPlayTurnの中でそれぞれのPlayerに会ったSelectPlaceを渡すのはifやswitch無しで可能ですか?

    私が考えると下のようになってしまいます…

    ```C#
    if(turnPlayer is UserPlayer) turnPlayer.Place(KeyboardSlectPlace)
    else if ...
    ```
  2. Playerを作るときに確定するならコンストラクタで渡せばいいです。
    Playerを作るのはGameクラスでいいと思います。

    players[0] = new Player("あなた", new KeyboardSelectPlace());
    players[1] = new Player("コンピューター", new RandomSelectPlace());
    とか。

    盤面をAI解析して最適座標を返す AISelectPlace クラスなんかも作れますよね。
  3. @namif017

    Questioner

    なるほど。そもそもPlayerを継承したクラスを作るのではなくPlayerのフィールド(?)として特定のインターフェースを継承したクラスのインスタンスを持たせるのですね。
    大変参考になりました。ここ暫くこれで悩んでいたのがやっとスッキリしました。ありがとうございます。

Your answer might help someone💌