আমি মনে করি যে এখানে সমস্যাটি হ'ল কোন শ্রেণীর দ্বারা কোন কাজগুলি পরিচালনা করতে হবে তার একটি পরিষ্কার বিবরণ আপনি দেন নি। আমি প্রতিটি বর্গের কী করা উচিত তার একটি ভাল বর্ণনা বলে আমি যা বর্ণনা করি তা বর্ণনা করব, তারপরে আমি জেনেরিক কোডের একটি উদাহরণ দেব যা ধারণাগুলির চিত্র তুলে ধরে। আমরা দেখতে পাব যে কোডটি কম সংযুক্ত হয়েছে, এবং তাই এটিতে আসলে বিজ্ঞপ্তি সংক্রান্ত রেফারেন্স নেই।
আসুন প্রতিটি ক্লাস কী করে তা বর্ণনা দিয়ে শুরু করি।
GameState
ক্লাসে কেবল গেমের বর্তমান অবস্থা সম্পর্কে তথ্য থাকা উচিত। গেমের অতীতের রাজ্যগুলি কী কী বা ভবিষ্যতের পদক্ষেপগুলি কী কী সম্ভব তা সম্পর্কে কোনও তথ্য থাকা উচিত নয়। এতে কেবল দাবাতে কোন স্কোয়ারে টুকরো রয়েছে বা ব্যাকগ্যামনের কোন পয়েন্টগুলিতে কতগুলি এবং কী ধরণের চেকার রয়েছে সে সম্পর্কে কেবলমাত্র তথ্য থাকতে হবে। GameState
দাবা অথবা ব্যাকগ্যামন মধ্যে দ্বিগুন ঘনক্ষেত্র সম্পর্কে castling সম্পর্কে তথ্য চাই, কিছু অতিরিক্ত তথ্য থাকে করতে হবে।
Move
বর্গ একটি সামান্য চতুর হয়। আমি বলব যে আমি মুভটি খেলতে GameState
পেরে ফলাফলগুলি নির্দিষ্ট করে প্লে করার জন্য একটি পদক্ষেপ নির্দিষ্ট করতে পারি। সুতরাং আপনি কল্পনা করতে পারেন যে একটি পদক্ষেপ শুধু হিসাবে প্রয়োগ করা যেতে পারে GameState
। যাইহোক, যেতে যেতে (উদাহরণস্বরূপ) আপনি ধারণা করতে পারেন যে বোর্ডে একক পয়েন্ট উল্লেখ করে একটি চালচলন নির্দিষ্ট করা অনেক সহজ। আমরা চাই আমাদের Move
ক্লাস এগুলির যে কোনও একটির ক্ষেত্রে পরিচালনা করতে যথেষ্ট নমনীয় হোক। অতএব Move
বর্গ আসলে একটি পদ্ধতি যা একটি প্রি-পদক্ষেপ নেয় সঙ্গে একটি ইন্টারফেস হতে যাচ্ছে GameState
এবং একটি নতুন পোস্ট পদক্ষেপ ফেরৎ GameState
।
এখন RuleBook
নিয়ম সম্পর্কে সমস্ত কিছু জানার জন্য ক্লাস দায়বদ্ধ। এটি তিনটি জিনিস ভেঙে দেওয়া যেতে পারে। প্রাথমিকটি GameState
কী তা জানা দরকার, কী পদক্ষেপ বৈধ হয় তা জানতে হবে এবং খেলোয়াড়দের মধ্যে কেউ জিতেছে কিনা তা জানাতে সক্ষম হওয়া প্রয়োজন।
আপনি GameHistory
তৈরি করা সমস্ত চাল এবং GameStates
যা ঘটেছিল তার সমস্ত নজর রাখার জন্য একটি শ্রেণি তৈরি করতে পারেন। একটি নতুন শ্রেণি আবশ্যক কারণ আমরা স্থির করেছিলাম যে এর আগে যে GameState
সবকটি GameState
ঘটেছিল সেগুলি জানার জন্য একটি অবিবাহিতকে দায়বদ্ধ করা উচিত নয় ।
এটি আমি আলোচনা করব ক্লাস / ইন্টারফেস সমাপ্ত। Board
আপনারও একটা ক্লাস আছে। তবে আমি মনে করি বিভিন্ন গেমের বোর্ডগুলি এতটা আলাদা যে বোর্ডগুলির সাথে সাধারণভাবে কী করা যায় তা দেখা মুশকিল। এখন আমি জেনেরিক ইন্টারফেস দেবো এবং জেনেরিক ক্লাসগুলি প্রয়োগ করব।
প্রথমটি GameState
। যেহেতু এই শ্রেণিটি সম্পূর্ণ গেমের উপর সম্পূর্ণ নির্ভরশীল, তাই জেনেরিক Gamestate
ইন্টারফেস বা শ্রেণি নেই।
পরেরটি Move
। যেমনটি আমি বলেছি, এটি এমন একটি ইন্টারফেসের সাথে প্রতিনিধিত্ব করা যেতে পারে যার একক পদ্ধতি রয়েছে যা প্রাক-মুভ স্টেট গ্রহণ করে এবং পোস্ট-মুভ স্টেট তৈরি করে। এই ইন্টারফেসের জন্য কোড এখানে:
package boardgame;
/**
*
* @param <T> The type of GameState
*/
public interface Move<T> {
T makeResultingState(T preMoveState) throws IllegalArgumentException;
}
লক্ষ্য করুন যে এখানে একটি টাইপ প্যারামিটার রয়েছে। এটি কারণ, উদাহরণস্বরূপ, ChessMove
ইচ্ছার প্রাক-পদক্ষেপের বিশদগুলি সম্পর্কে জানতে হবে ChessGameState
। সুতরাং, উদাহরণস্বরূপ, শ্রেণীর ঘোষণা ChessMove
হবে would
class ChessMove extends Move<ChessGameState>
,
আপনি ইতিমধ্যে একটি ChessGameState
ক্লাস সংজ্ঞায়িত করা হবে যেখানে ।
এরপরে আমি জেনেরিক RuleBook
ক্লাস নিয়ে আলোচনা করব । কোডটি এখানে:
package boardgame;
import java.util.List;
/**
*
* @param <T> The type of GameState
*/
public interface RuleBook<T> {
T makeInitialState();
List<Move<T>> makeMoveList(T gameState);
StateEvaluation evaluateState(T gameState);
boolean isMoveLegal(Move<T> move, T currentState);
}
আবার GameState
ক্লাসের জন্য একটি টাইপ প্যারামিটার রয়েছে । যেহেতু RuleBook
প্রাথমিক অবস্থাটি কী তা জানা থাকার কথা, তাই আমরা প্রাথমিক রাষ্ট্রটি দেওয়ার জন্য একটি পদ্ধতি রেখেছি। যেহেতু RuleBook
কোন পদক্ষেপ বৈধ তা জেনে রাখা উচিত বলে আমাদের দেওয়া পদ্ধতিতে কোনও পদক্ষেপ বৈধ কিনা তা পরীক্ষা করার এবং প্রদত্ত রাষ্ট্রের জন্য আইনী পদক্ষেপের একটি তালিকা দেওয়ার জন্য আমাদের পদ্ধতি রয়েছে। অবশেষে, মূল্যায়ন করার একটি পদ্ধতি রয়েছে GameState
। লক্ষ্য করুন যে RuleBook
কেবলমাত্র একজন বা অন্য খেলোয়াড় ইতিমধ্যে জিতেছে কিনা তা বর্ণনা করার জন্য দায়বদ্ধ হওয়া উচিত তবে কোনও খেলার মাঝখানে আরও ভাল অবস্থানে কে নেই। কে আরও ভাল অবস্থানে আছে তা সিদ্ধান্ত নেওয়া একটি জটিল বিষয় যা তার নিজস্ব শ্রেণিতে স্থানান্তরিত হওয়া উচিত। সুতরাং StateEvaluation
ক্লাসটি আসলে নীচে দেওয়া কেবল একটি সাধারণ এনাম:
package boardgame;
/**
*
*/
public enum StateEvaluation {
UNFINISHED,
PLAYER_ONE_WINS,
PLAYER_TWO_WINS,
DRAW,
ILLEGAL_STATE
}
শেষ পর্যন্ত, আসুন GameHistory
ক্লাসটি বর্ণনা করি । এই ক্লাসটি গেমটিতে পৌঁছেছে এমন সমস্ত পজিশনের পাশাপাশি যে চালানো হয়েছে সেগুলি মনে রাখার জন্য দায়বদ্ধ। এটি করতে সক্ষম হওয়া উচিত প্রধান বিষয়টি খোলার Move
মতো রেকর্ড করা । আপনি পূর্বাবস্থায় ফিরে আসার জন্য কার্যকারিতা যুক্ত করতে পারেন Move
। আমি নীচে একটি বাস্তবায়ন আছে।
package boardgame;
import java.util.ArrayList;
import java.util.List;
/**
*
* @param <T> The type of GameState
*/
public class GameHistory<T> {
private List<T> states;
private List<Move<T>> moves;
public GameHistory(T initialState) {
states = new ArrayList<>();
states.add(initialState);
moves = new ArrayList<>();
}
void recordMove(Move<T> move) throws IllegalArgumentException {
moves.add(move);
states.add(move.makeResultingState(getMostRecentState()));
}
void resetToNthState(int n) {
states = states.subList(0, n + 1);
moves = moves.subList(0, n);
}
void undoLastMove() {
resetToNthState(getNumberOfMoves() - 1);
}
T getMostRecentState() {
return states.get(getNumberOfMoves());
}
T getStateAfterNthMove(int n) {
return states.get(n + 1);
}
Move<T> getNthMove(int n) {
return moves.get(n);
}
int getNumberOfMoves() {
return moves.size();
}
}
অবশেষে, আমরা Game
সবকিছুকে এক সাথে বেঁধে রাখার জন্য ক্লাস তৈরি করার কল্পনা করতে পারি । এই Game
শ্রেণীর এমন পদ্ধতি উদ্ঘাটিত করার কথা রয়েছে যা মানুষের পক্ষে কারেন্টটি কী তা দেখতে সক্ষম করে GameState
, কার কার কাছে যদি থাকে তবে কী চলাচল করা যায় তা দেখুন এবং একটি চালচলন খেলবেন তা দেখুন। আমি নীচে একটি বাস্তবায়ন আছে
package boardgame;
import java.util.List;
/**
*
* @author brian
* @param <T> The type of GameState
*/
public class Game<T> {
GameHistory<T> gameHistory;
RuleBook<T> ruleBook;
public Game(RuleBook<T> ruleBook) {
this.ruleBook = ruleBook;
final T initialState = ruleBook.makeInitialState();
gameHistory = new GameHistory<>(initialState);
}
T getCurrentState() {
return gameHistory.getMostRecentState();
}
List<Move<T>> getLegalMoves() {
return ruleBook.makeMoveList(getCurrentState());
}
void doMove(Move<T> move) throws IllegalArgumentException {
if (!ruleBook.isMoveLegal(move, getCurrentState())) {
throw new IllegalArgumentException("Move is not legal in this position");
}
gameHistory.recordMove(move);
}
void undoMove() {
gameHistory.undoLastMove();
}
StateEvaluation evaluateState() {
return ruleBook.evaluateState(getCurrentState());
}
}
এই শ্রেণিতে লক্ষ্য করুন যে RuleBook
বর্তমানটি কী তা জানার জন্য দায়বদ্ধ নয় GameState
। এটাই GameHistory
কাজ। সুতরাং Game
প্রশ্নগুলি GameHistory
বর্তমান রাষ্ট্রটি কী তা জিজ্ঞাসা করে এবং আইনী পদক্ষেপগুলি কী তা বা কেউ জিতেছে কিনা তা RuleBook
যখন Game
বলার দরকার পড়ে তখন এই তথ্যটি দেয় ।
যাইহোক, এই উত্তরের মূল বক্তব্যটি হ'ল একবার আপনি প্রতিটি বর্গ কিসের জন্য দায়বদ্ধ তা নিয়ে একটি যুক্তিসঙ্গত সিদ্ধান্ত নিয়েছেন এবং আপনি প্রতিটি শ্রেণিকে অল্প সংখ্যক দায়িত্বের উপর মনোনিবেশ করেন এবং আপনি প্রতিটি দায়িত্ব একটি অনন্য শ্রেণীর উপর অর্পণ করেন, তারপরে ক্লাসগুলি ডিকপলড হয়ে যায়, এবং সবকিছু কোড করা সহজ হয়ে যায়। আশা করি আমি যে কোড উদাহরণ দিয়েছি তা থেকে এটি স্পষ্ট।
RuleBook
উদাহরণস্বরূপState
একটি আর্গুমেন্ট হিসাবে গ্রহণ করে এবং বৈধটি ফেরত দেয়MoveList
, অর্থাৎ "আমরা এখন যেখানে আছি, এর পরে কী করা যায়?"