paint-brush
ফ্লাটারের মাধ্যমে মজাদার উপায়ে ডেটা স্ট্রাকচার কীভাবে শিখবেন তা এখানে দেওয়া হলদ্বারা@dhruvam
নতুন ইতিহাস

ফ্লাটারের মাধ্যমে মজাদার উপায়ে ডেটা স্ট্রাকচার কীভাবে শিখবেন তা এখানে দেওয়া হল

দ্বারা Dhruvam23m2025/03/04
Read on Terminal Reader

অতিদীর্ঘ; পড়তে

এই প্রবন্ধটি Flutter-এ তত্ত্ব এবং হাতে-কলমে বাস্তবায়নের সমন্বয় সাধন করেছে। এটি Google-এর *Applied CS with Android দ্বারা অনুপ্রাণিত। মাত্র ৩-৪ ঘন্টার মধ্যে, আপনি এই মৌলিক ডেটা স্ট্রাকচারগুলির আরও গভীর ধারণা অর্জন করতে পারবেন।
featured image - ফ্লাটারের মাধ্যমে মজাদার উপায়ে ডেটা স্ট্রাকচার কীভাবে শিখবেন তা এখানে দেওয়া হল
Dhruvam HackerNoon profile picture
0-item

গেম তৈরি করুন এবং কম্পিউটার বিজ্ঞান শিখুন।


ডেটা স্ট্রাকচার দক্ষ সফটওয়্যার ডেভেলপমেন্টের ভিত্তি তৈরি করে, তবুও ঐতিহ্যবাহী শেখার পদ্ধতিগুলি প্রায়শই এগুলিকে বিমূর্ত এবং বাস্তব-জগতের অ্যাপ্লিকেশন থেকে বিচ্ছিন্ন করে তোলে। এই নিবন্ধটি একটি ভিন্ন পদ্ধতি গ্রহণ করে - ফ্লটারে তত্ত্বের সাথে হাতে-কলমে বাস্তবায়নের সমন্বয় করে শেখাকে আকর্ষণীয় এবং ব্যবহারিক উভয়ই করে তোলে।


গুগলের অ্যাপ্লাইড সিএস উইথ অ্যান্ড্রয়েড দ্বারা অনুপ্রাণিত হয়ে, ফ্লটারের জন্য এই অভিযোজনটি অ্যারে, হ্যাশসেট এবং হ্যাশম্যাপ বোঝার একটি ইন্টারেক্টিভ উপায় প্রদান করে। মাত্র ৩-৪ ঘন্টার মধ্যে, আপনি এই মৌলিক ডেটা স্ট্রাকচারগুলিকে একটি অর্থপূর্ণ প্রেক্ষাপটে প্রয়োগ করার সময় আরও গভীরভাবে বুঝতে পারবেন।


আপনি যদি আপনার সিএসের মৌলিক বিষয়গুলো আরও শক্তিশালী করতে চান, অথবা আপনার দক্ষতা বৃদ্ধির লক্ষ্যে অভিজ্ঞ ডেভেলপার হন, তাহলে এই নির্দেশিকাটি প্রয়োজনীয় ডেটা স্ট্রাকচারে দক্ষতা অর্জনের একটি দক্ষ এবং উপভোগ্য উপায় প্রদান করে। চলুন শুরু করা যাক।

এই প্রবন্ধের উদ্দেশ্য:

  1. অভিধান কীভাবে তথ্য সংরক্ষণের জন্য ব্যবহার করা যেতে পারে (এই ক্ষেত্রে শব্দ) তা জানুন।
  2. শব্দের গ্রুপিং সংরক্ষণ করতে হ্যাশ ম্যাপ ব্যবহার করুন, যা অ্যানাগ্রাম।
  3. বৃহৎ ডেটা সেট নিয়ে কাজ করার সময় কিছু ডেটা স্ট্রাকচার যে সীমাবদ্ধতার সম্মুখীন হয় তা ব্যাখ্যা করতে সক্ষম হও।

প্রস্তুতি:

আমরা কর্মশালার কার্যকলাপে কয়েকটি ডেটা স্ট্রাকচার ব্যবহার করব, তাই দয়া করে Lists , HashSets এবং HashMaps পর্যালোচনা করুন। আপনি Dart-এ এই ডেটা স্ট্রাকচারগুলি ব্যবহার করে আত্মবিশ্বাসের সাথে উপাদানগুলি সন্নিবেশ করতে, মুছে ফেলতে, অ্যাক্সেস করতে এবং অস্তিত্ব পরীক্ষা করতে সক্ষম হবেন।


এটি ডেটা স্ট্রাকচার, হ্যাশসেটস এবং হ্যাশম্যাপের একটি ছোট ভূমিকা।


একটি ছোট প্রারম্ভিক ব্যায়াম ওয়ার্ম-আপ:

HashMaps ব্যবহার করে একটি উদাহরণ হিসেবে, এমন একটি প্রোগ্রাম তৈরি করুন (অগত্যা একটি Flutter অ্যাপ নয় — কমান্ড-লাইন ঠিক আছে) যা একটি তিন-অক্ষরের দেশের কোড গ্রহণ করবে ( ISO-3166 দেখুন) এবং এটি যে দেশের সাথে সম্পর্কিত তার পুরো নাম ফেরত দেবে।


উদাহরণস্বরূপ:


 Input | Output ----- | ---------------------------------------------------- GBR | United Kingdom of Great Britain and Northern Ireland IDN | Indonesia IND | India


এক্সটেনশন হিসেবে, যদি ইনপুটটি ৩ অক্ষরের বেশি হয়, তাহলে এটিকে একটি দেশের নাম হিসেবে বিবেচনা করুন এবং এর জন্য তিন অক্ষরের কোডটি ফেরত দিন। যদি ইনপুটটি কোনও বৈধ কোড বা দেশের নাম না হয় তবে একটি সহায়ক ত্রুটি বার্তা লিখুন।


চলো শুরু করি।


অ্যানাগ্রাম

অ্যানাগ্রাম হলো এমন একটি শব্দ যা অন্য একটি শব্দের অক্ষর পুনর্বিন্যাস করে তৈরি হয়। উদাহরণস্বরূপ, সিনেমা হলো আইসম্যানের একটি অ্যানাগ্রাম।

গেমটির মেকানিক্স নিম্নরূপ:

  1. গেমটি ব্যবহারকারীকে অভিধান থেকে একটি শব্দ প্রদান করে।


  2. ব্যবহারকারী যতটা সম্ভব শব্দ তৈরি করার চেষ্টা করেন যাতে প্রদত্ত শব্দের সমস্ত অক্ষর এবং একটি অতিরিক্ত অক্ষর থাকে। মনে রাখবেন যে অন্যান্য অক্ষরগুলিকে পুনর্বিন্যাস না করে শুরুতে বা শেষে অতিরিক্ত অক্ষর যোগ করা অবৈধ। উদাহরণস্বরূপ, যদি গেমটি 'আকরিক' শব্দটিকে শুরু হিসাবে বেছে নেয়, তাহলে ব্যবহারকারী 'গোলাপ' বা 'শূন্য' অনুমান করতে পারে কিন্তু 'ঘা' নয়।


  3. ব্যবহারকারী হাল ছেড়ে দিতে পারেন এবং এমন শব্দ দেখতে পারেন যা তারা অনুমান করেনি।




আমরা আপনাকে কিছু স্টার্টার কোড দিয়েছি যাতে ১০,০০০ শব্দের একটি অভিধান রয়েছে এবং এই গেমের UI অংশগুলি পরিচালনা করে এবং আপনি AnagramBlocclass লেখার জন্য দায়ী থাকবেন যা সমস্ত শব্দের হেরফের পরিচালনা করে।


কোড ভ্রমণ

স্টার্টার কোডটি তিনটি প্রধান ডার্ট ক্লাস নিয়ে গঠিত:


anagrams_page.dart

এটি একটি সহজ কোড যা উপরে দেখানো স্ক্রিনটিকে প্রতিনিধিত্ব করে। আমরা স্ক্রিনের জন্য স্টেট ম্যানেজমেন্টের জন্য একটি ব্লক ব্যবহার করব। আমরা ব্লকে একটি ইভেন্ট ফায়ার করে এবং স্ক্রিনটি বিভিন্ন গেম স্টেটে সাড়া দিলে কী ঘটবে তা নির্ধারণ করে গেমটি সেট আপ করে শুরু করব।


 import 'package:anagrams/anagrams/bloc/anagram_bloc.dart'; import 'package:anagrams/anagrams/domain/word.dart'; import 'package:anagrams/l10n/l10n.dart'; import 'package:bloc_presentation/bloc_presentation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class AnagramsPage extends StatelessWidget { const AnagramsPage({super.key}); @override Widget build(BuildContext context) { return BlocProvider( create: (_) => AnagramBloc() ..add( SetupAnagrams( DefaultAssetBundle.of(context), ), ), child: const AnagramsView(), ); } } class AnagramsView extends StatelessWidget { const AnagramsView({super.key}); @override Widget build(BuildContext context) { final l10n = context.l10n; return Scaffold( appBar: AppBar(title: Text(l10n.anagramAppBarTitle)), body: BlocBuilder<AnagramBloc, AnagramState>( builder: (context, state) { switch (state.status) { case AnagramGameStatus.gameError: return const Center( child: Text('An error occurred'), ); case AnagramGameStatus.loaded: return Padding( padding: const EdgeInsets.all(20), child: ListView( children: const [ _SelectedWord(), SizedBox(height: 20), _AnagramsTextField(), SizedBox(height: 10), _GuessListView(), ], ), ); case AnagramGameStatus.initial: return const Center( child: CircularProgressIndicator(), ); } }, ), floatingActionButton: const _NextWordButton(), ); } } class _SelectedWord extends StatelessWidget { const _SelectedWord(); @override Widget build(BuildContext context) { return BlocSelector<AnagramBloc, AnagramState, String>( selector: (state) => state.currentWord, builder: (context, currentWord) { return Text.rich( TextSpan( text: 'Find as many words as possible that can be ' 'formed by adding one letter to ', children: [ TextSpan( text: currentWord.toUpperCase(), style: const TextStyle(fontWeight: FontWeight.bold), ), TextSpan( text: ' (but that do not contain the substring' ' ${currentWord.toUpperCase()}).', ), ], ), ); }, ); } } class _AnagramsTextField extends StatelessWidget { const _AnagramsTextField(); @override Widget build(BuildContext context) { final controller = TextEditingController(); return TextField( controller: controller, decoration: const InputDecoration( hintText: 'Enter an anagram', border: OutlineInputBorder(), ), keyboardType: TextInputType.text, textInputAction: TextInputAction.done, onSubmitted: (value) { controller.clear(); context.read<AnagramBloc>().add(ProcessWord(value)); }, ); } } class _GuessListView extends StatelessWidget { const _GuessListView(); @override Widget build(BuildContext context) { return BlocSelector<AnagramBloc, AnagramState, List<Word>>( selector: (state) => state.guesses, builder: (context, guesses) { return Column( children: guesses.map((word) { return ListTile( minTileHeight: 0, contentPadding: EdgeInsets.zero, visualDensity: VisualDensity.compact, title: Text(word.value), leading: Icon( word.isAnagram ? Icons.check : Icons.close, color: word.isAnagram ? Colors.green : Colors.red, ), ); }).toList(), ); }, ); } } class _GameResult extends StatelessWidget { const _GameResult(this.currentWord, this.result); final List<Word> result; final String currentWord; @override Widget build(BuildContext context) { return ListView( shrinkWrap: true, children: [ const SizedBox(height: 20), Padding( padding: const EdgeInsets.symmetric( horizontal: 20, ), child: Text( 'Game Result for $currentWord', style: const TextStyle(fontSize: 20), ), ), Padding( padding: const EdgeInsets.all(20), child: SizedBox( width: double.infinity, child: DataTable( decoration: BoxDecoration( border: Border.all( color: Colors.grey.shade400, ), borderRadius: BorderRadius.circular(10), ), columns: const [ DataColumn(label: Text('Possible Anagrams')), DataColumn(label: Text('Your Guesses')), ], rows: result.map((word) { return DataRow( cells: [ DataCell(Text(word.value)), DataCell( Center( child: Icon( word.isAnagram ? Icons.check : Icons.close, color: word.isAnagram ? Colors.green : Colors.red, ), ), ), ], ); }).toList(), ), ), ), ], ); } } class _NextWordButton extends StatelessWidget { const _NextWordButton(); @override Widget build(BuildContext context) { final l10n = context.l10n; return BlocPresentationListener<AnagramBloc, AnagramPresenterEvent>( listener: (context, event) { if (event is FinishGuess) { // show a bottom sheet with the anagrams that were not guessed showModalBottomSheet<void>( context: context, useSafeArea: true, builder: (context) { return _GameResult(event.currentWord, event.result); }, ); } }, child: FloatingActionButton.extended( onPressed: () async { context.read<AnagramBloc>().add(ResetGame()); }, label: Text(l10n.nextWordButton), ), ); } }


  • _SelectWord : গেমটির জন্য নির্বাচিত শব্দ দেখায় যা থেকে অ্যানাগ্রাম তৈরি করা হবে।


  • _AnagramsTextField : ব্যবহারকারীর টাইপ করা শব্দটি প্রক্রিয়া করার জন্য শব্দটি গ্রহণ করে এবং একটি ইভেন্ট ফায়ার করে।


  • _GuessListView : ব্যবহারকারীর প্রবেশ করানো অনুমান এবং সেগুলি সঠিক কিনা তা দেখায়।


  • _NextWordButton : গেমটি রিসেট করে এবং ব্যবহারকারীকে বর্তমান শব্দের সমস্ত অ্যানাগ্রাম এবং ব্যবহারকারী কোনটি অনুমান করেছেন তা উপস্থাপন করে।


anagram_states.dart


 enum AnagramGameStatus { initial, loaded, gameError } const minNumAnagrams = 5; const defaultWordLength = 3; const maxDefaultWordLength = 7; @immutable final class AnagramState extends Equatable { factory AnagramState({ AnagramGameStatus status = AnagramGameStatus.initial, List<String> words = const [], String currentWord = '', List<String> anagrams = const [], List<Word> guesses = const [], HashSet<String>? wordSet, HashMap<String, List<String>>? anagramMap, HashMap<int, List<String>>? sizeToWords, int wordLength = defaultWordLength, }) { return AnagramState._( status: status, words: words, currentWord: currentWord, anagrams: anagrams, guesses: guesses, wordSet: wordSet ?? HashSet<String>(), anagramMap: anagramMap ?? HashMap<String, List<String>>(), sizeToWords: sizeToWords ?? HashMap<int, List<String>>(), wordLength: wordLength, ); } const AnagramState._({ required this.status, required this.words, required this.currentWord, required this.anagrams, required this.guesses, required this.wordSet, required this.anagramMap, required this.sizeToWords, this.wordLength = defaultWordLength, }); // The current status of the game final AnagramGameStatus status; // All the words in the game final List<String> words; // Currently chosen word of the game to form anagrams final String currentWord; // All the anagrams for the current word final List<String> anagrams; // All the guesses user has made final List<Word> guesses; // A set of all the words in the game final HashSet<String> wordSet; // A map of anagrams for each word final HashMap<String, List<String>> anagramMap; // Stores the words in increasing order of their length final HashMap<int, List<String>> sizeToWords; final int wordLength; AnagramState copyWith({ AnagramGameStatus? status, List<String>? words, String? currentWord, List<String>? anagrams, List<Word>? guesses, HashSet<String>? wordSet, HashMap<String, List<String>>? anagramMap, HashMap<int, List<String>>? sizeToWords, int? wordLength, }) { return AnagramState( status: status ?? this.status, words: words ?? this.words, currentWord: currentWord ?? this.currentWord, anagrams: anagrams ?? this.anagrams, guesses: guesses ?? this.guesses, wordSet: wordSet ?? this.wordSet, anagramMap: anagramMap ?? this.anagramMap, sizeToWords: sizeToWords ?? this.sizeToWords, wordLength: wordLength ?? this.wordLength, ); } @override List<Object?> get props => [ status, words, currentWord, anagrams, guesses, wordSet, anagramMap, sizeToWords, wordLength, ]; }


গেমটি চালানোর জন্য প্রয়োজনীয় সমস্ত স্টেট ভেরিয়েবল AnagramState-এ থাকে।

  • status : গেমটি লোড হচ্ছে (প্রাথমিক), লোড হচ্ছে, অথবা কোনও ত্রুটি হচ্ছে কিনা তা ধরে রাখে।
  • words : word.txt ফাইল থেকে লোড করা সমস্ত শব্দের তালিকা তৈরি করে।
  • anagrams : নির্বাচিত শব্দের জন্য সমস্ত অ্যানাগ্রাম ধরে রাখে।
  • currentword : একটি শব্দ তালিকা থেকে নির্বাচিত শব্দ এবং যে শব্দ থেকে অ্যানাগ্রাম তৈরি করা হবে।
  • guesses : ব্যবহারকারী যে সমস্ত পছন্দগুলি প্রবেশ করে এবং সেগুলি সঠিক নাকি ভুল।


বাকি বিস্তারিত আমরা পরে প্রবন্ধে আলোচনা করব।


anagram_bloc.dart


 import 'dart:async'; import 'dart:collection'; import 'dart:convert'; import 'package:anagrams/anagrams/domain/word.dart'; import 'package:bloc_presentation/bloc_presentation.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'anagram_events.dart'; part 'anagram_states.dart'; class AnagramBloc extends Bloc<AnagramEvent, AnagramState> with BlocPresentationMixin<AnagramState, AnagramPresenterEvent> { AnagramBloc() : super(AnagramState()) { on<SetupAnagrams>(_onSetupAnagrams); on<ProcessWord>(_onProcessWord); on<ResetGame>(_onResetGame); } Future<void> _onSetupAnagrams( SetupAnagrams event, Emitter<AnagramState> emit, ) async { try { // this should not be done here, // but for the sake of simplicity, we will do it here final wordsFile = await event.defaultAssetBundle.loadString('assets/words.txt'); // read each line in the file final words = const LineSplitter().convert(wordsFile); // change the state of the game emit( state.copyWith( status: AnagramGameStatus.loaded, words: words, ), ); // reset the game _onRestartGame(emit); } catch (e) { emit( state.copyWith( status: AnagramGameStatus.gameError, ), ); } } Future<void> _onProcessWord( ProcessWord event, Emitter<AnagramState> emit, ) async { try { final word = event.word.trim().toLowerCase(); if (word.isEmpty) { return; } if (_isGoodWord(word) && state.anagrams.contains(word)) { // remove the word from the list of anagrams // add the word to the list of guesses emit( state.copyWith( anagrams: state.anagrams..remove(word), guesses: [...state.guesses, Word(word, isAnagram: true)], ), ); // if there are no more anagrams, the game is over // call _onResetGame to reset the game if (state.anagrams.isEmpty) { add(ResetGame()); } } else { emit( state.copyWith( guesses: [...state.guesses, Word(word)], ), ); } } catch (e) { // show an error message } } FutureOr<void> _onResetGame(ResetGame event, Emitter<AnagramState> emit) { _onGameFinished(); _onRestartGame(emit); } void _onRestartGame(Emitter<AnagramState> emit) { final starterWord = _pickGoodStarterWord(emit); emit( state.copyWith( status: AnagramGameStatus.loaded, currentWord: starterWord, anagrams: _getAnagrams(starterWord), guesses: [], ), ); } void _onGameFinished() { emitPresentation(FinishGuess(_result, state.currentWord)); } List<Word> get _result { // All the anagrams that were not guessed final notGuessedAnagrams = state.anagrams.map(Word.new).toList(); // All the guesses that were made final guesses = state.guesses.where((word) => word.isAnagram).toList(); // return the list of anagrams that were not guessed return [...guesses, ...notGuessedAnagrams]; } /// create a function to find all the anagrams of the target word List<String> _getAnagrams(String targetWord) { // find all the anagrams of the target word final anagrams = <String>[]; // return the list of anagrams return anagrams; } // ignore: unused_element List<String> _getAnagramsWithOneMoreLetter(String targetWord) { final anagrams = HashSet<String>(); // return the list of anagrams return anagrams.toList(); } /// Picks a good starter word for the game. String _pickGoodStarterWord(Emitter<AnagramState> emit) { const word = 'skate'; return word; } /// Checks if the word is a good word. bool _isGoodWord(String word) { return true; } }


  • onSetupAnagrams : ফাইলটি পড়ে, শব্দগুলিকে বিভক্ত করে এবং তালিকায় যোগ করে। এটি বর্তমান শব্দটিও খুঁজে বের করে, নির্বাচিত শব্দের জন্য অ্যানাগ্রাম খুঁজে বের করে এবং অবস্থা আপডেট করে।


  • onProcessWord : ব্যবহারকারী যখন একটি অনুমান প্রবেশ করে এবং অবস্থা আপডেট করে তখন এটি হ্যান্ডলার নামে ডাকা হয়।
  • onReset : পরবর্তী শব্দ বোতামে ক্লিক করার পর কল করা হয় এবং গেমটি রিসেট করা হয়।
  • isGoodWord : দাবি করে যে প্রদত্ত শব্দটি অভিধানে রয়েছে এবং মূল শব্দের শুরু বা শেষে কোনও অক্ষর যোগ করে এটি গঠিত হয় না।
  • getAnagrams : একটি প্রদত্ত শব্দের সম্ভাব্য সকল অ্যানাগ্রামের একটি তালিকা তৈরি করে।
  • getAnagramsWithOneMoreLetter : প্রদত্ত শব্দে একটি অক্ষর যোগ করে তৈরি করা যেতে পারে এমন সমস্ত সম্ভাব্য শব্দের একটি তালিকা তৈরি করে।
  • pickGoodStarterWord : কমপক্ষে কাঙ্ক্ষিত সংখ্যক অ্যানাগ্রাম সহ একটি শব্দ এলোমেলোভাবে নির্বাচন করুন।

মাইলস্টোন ১: অপরিহার্য বিষয়গুলি

প্রথম মাইলফলকটি একটি খুব সহজ কার্যকরী প্রোগ্রাম তৈরির উপর দৃষ্টি নিবদ্ধ করে। আপনি মাইলস্টোন ২ এবং ৩-এ ভিত্তিগুলি বাস্তবায়ন করবেন যা পরবর্তীতে নির্মিত হবে।


আমরা anagram_bloc.dart নিয়ে কাজ করব।

অ্যানাগ্রাম পান

getAnagrams প্রয়োগ করুন যা একটি স্ট্রিং নেয় এবং আমাদের ইনপুটে সেই স্ট্রিংয়ের সমস্ত অ্যানাগ্রাম খুঁজে বের করে। এখন আমাদের কৌশলটি সহজ হবে: কেবল প্রতিটি স্ট্রিংকে words তালিকার সাথে ইনপুট শব্দের তুলনা করে নির্ধারণ করুন যে সেগুলি অ্যানাগ্রাম কিনা। কিন্তু আমরা এটি কীভাবে করব?


দুটি স্ট্রিং একে অপরের অ্যানাগ্রাম কিনা তা নির্ধারণ করার জন্য আপনি বিভিন্ন কৌশল ব্যবহার করতে পারেন (যেমন প্রতিটি অক্ষরের উপস্থিতির সংখ্যা গণনা করা), তবে আমাদের উদ্দেশ্যে আপনি একটি সহায়ক ফাংশন তৈরি করবেন (এটিকে sortLetters বলুন) যা একটি String নেয় এবং বর্ণানুক্রমিক ক্রমে একই অক্ষর সহ অন্য একটি String ফেরত দেয় (যেমন "পোস্ট" -> "পোস্ট")।


দুটি স্ট্রিং অ্যানাগ্রাম কিনা তা নির্ধারণ করা তখন একটি সহজ বিষয় হল তাদের দৈর্ঘ্য একই কিনা (গতির জন্য) এবং তাদের অক্ষরের সাজানো সংস্করণগুলি সমান কিনা তা পরীক্ষা করা।

ওয়ার্ডসেট এবং অ্যানাগ্রামম্যাপ

দুর্ভাগ্যবশত, এই সহজ কৌশলটি আমাদের জন্য এই খেলার বাকি অংশ বাস্তবায়নের জন্য খুব ধীর হবে। তাই, আমাদের onSetupAnagrams পুনরায় দেখতে হবে এবং এমন কিছু ডেটা স্ট্রাকচার খুঁজে বের করতে হবে যা আমাদের উদ্দেশ্যে সুবিধাজনক উপায়ে শব্দ সংরক্ষণ করে। আমরা দুটি নতুন ডেটা স্ট্রাকচার তৈরি করব ( words ছাড়াও):


  • একটি HashSet (যাকে wordSet বলা হয়) যা আমাদের দ্রুত (O(1) তে) যাচাই করতে সাহায্য করবে যে কোনও শব্দ বৈধ কিনা।


  • একটি HashMap (যাকে anagramMap বলা হয়) যা আমাদের অ্যানাগ্রামগুলিকে গ্রুপ করার সুযোগ দেবে। আমরা এটি একটি স্ট্রিং এর sortLetters সংস্করণকে কী হিসেবে ব্যবহার করে এবং সেই কী-এর সাথে সম্পর্কিত শব্দের একটি তালিকা আমাদের মান হিসেবে সংরক্ষণ করে করব। উদাহরণস্বরূপ, আমাদের কাছে এই ফর্মের একটি এন্ট্রি থাকতে পারে: key: "opst" মান: ["post", "spot", "pots", "tops", ...]।


ইনপুট শব্দগুলি প্রক্রিয়া করার সময়, প্রতিটিতে sortLetters কল করুন এবং পরীক্ষা করুন যে anagramMap ইতিমধ্যেই সেই কী-এর জন্য একটি এন্ট্রি আছে কিনা। যদি থাকে, তাহলে সেই কী-তে বর্তমান শব্দটি List এ যোগ করুন। অন্যথায়, একটি নতুন তৈরি করুন, এতে শব্দটি যোগ করুন এবং সংশ্লিষ্ট কী দিয়ে HashMap এ সংরক্ষণ করুন।


একবার আপনি এটি সম্পন্ন করলে, আপনি মাইলস্টোন ১ এর শেষে পৌঁছে গেছেন! আপনি এখন দ্বিতীয় মাইলফলকে যেতে প্রস্তুত, যেখানে আপনি আপনার প্রোগ্রামে আরও জটিলতা যোগ করবেন।


মাইলফলক ১ এর সমাধান

মাইলস্টোন ২: গুণমান বৃদ্ধি

মাইলস্টোন ২-এর মূল লক্ষ্য হলো বাছাই করা শব্দগুলো অ্যানাগ্রাম গেমের জন্য উপযুক্ত কিনা তা নিশ্চিত করা। এর বিপরীতে। আগের মাইলস্টোনটি তিনটি ভাগে বিভক্ত।

isGoodWord

আপনার পরবর্তী কাজ হল isGoodWord বাস্তবায়ন করা যা পরীক্ষা করে:

  • প্রদত্ত শব্দটি একটি বৈধ অভিধান শব্দ (অর্থাৎ, wordSet তে), এবং
  • শব্দটিতে সাবস্ট্রিং হিসেবে মূল শব্দটি নেই।




কোনও শব্দ একটি বৈধ অভিধানিক শব্দ কিনা তা পরীক্ষা করার জন্য wordSet দেখে দেখা যেতে পারে যে এতে শব্দটি আছে কিনা। শব্দটিতে সাবস্ট্রিং হিসেবে মূল শব্দটি নেই কিনা তা পরীক্ষা করা একটি চ্যালেঞ্জ হিসেবে রয়ে গেছে!

getAnagramsWithOneMoreLetter

অবশেষে, getAnagramsWithOneMoreLetter প্রয়োগ করুন যা একটি স্ট্রিং নেয় এবং সেই শব্দে একটি অক্ষর যোগ করে তৈরি করা যেতে পারে এমন সমস্ত অ্যানাগ্রাম খুঁজে বের করে।


আপনার রিটার্ন মান হিসেবে একটি নতুন List তৈরি করতে ভুলবেন না, তারপর anagramMap এ থাকা এন্ট্রিগুলির বিপরীতে প্রদত্ত শব্দ + বর্ণমালার প্রতিটি অক্ষর এক এক করে পরীক্ষা করুন।


এছাড়াও, getAnagrams এর পরিবর্তে getAnagramsWithOneMoreLetter ব্যবহার করতে onRestartGame আপডেট করুন।


pickGoodStarterWord

যদি আপনার গেমটি কাজ করছে, তাহলে গেমটিকে আরও আকর্ষণীয় করে তুলতে pickGoodStarterWord প্রয়োগ করুন। List শব্দ থেকে একটি এলোমেলো শুরুর বিন্দু নির্বাচন করুন এবং অ্যারের প্রতিটি শব্দ পরীক্ষা করুন যতক্ষণ না আপনি এমন একটি খুঁজে পান যাতে কমপক্ষে minNumAnagrams আছে। প্রয়োজনে অ্যারের শুরু পর্যন্ত র‍্যাপিং পরিচালনা করতে ভুলবেন না।



দুই-তৃতীয়াংশ পথ! মাত্র একটি মাইলফলক আর তোমার কাজ শেষ হওয়ার আগে আরও একটি এক্সটেনশন।


মাইলফলক ২ এর সমাধান


মাইলস্টোন ৩: রিফ্যাক্টরিং

এই মুহূর্তে, গেমটি কার্যকরী কিন্তু যদি আপনি একটি দীর্ঘ বেস ওয়ার্ড দিয়ে শুরু করেন তবে খেলা বেশ কঠিন হতে পারে। এটি এড়াতে, আসুন onSetupGame রিফ্যাক্টর করি যাতে ক্রমবর্ধমান দৈর্ঘ্যের শব্দ দেওয়া যায়।


এই রিফ্যাক্টরটি onSetupGame এ শুরু হয় যেখানে word তালিকা তৈরি করার পাশাপাশি, আপনার প্রতিটি শব্দ একটি HashMap (আসুন একে sizeToWords বলি) তে সংরক্ষণ করা উচিত যা শব্দের দৈর্ঘ্যকে সেই দৈর্ঘ্যের সমস্ত শব্দের List সাথে ম্যাপ করে। এর অর্থ, উদাহরণস্বরূপ, আপনি sizeToWords.get(4) কল করে অভিধানে সমস্ত চার-অক্ষরের শব্দ পেতে সক্ষম হবেন।


pickGoodStarterWord এ, আপনার অনুসন্ধানকে length wordLength শব্দের মধ্যে সীমাবদ্ধ রাখুন, এবং একবার আপনার কাজ শেষ হয়ে গেলে, wordLength বৃদ্ধি করুন (যদি না এটি ইতিমধ্যে axWordLength এ থাকে) যাতে পরবর্তী আমন্ত্রণটি একটি বড় শব্দ ফেরত দেয়।


মাইলফলক ৩ এর সমাধান


এক্সটেনশন

এই কার্যকলাপে (ভবিষ্যতের সকল কার্যকলাপের মতো) কিছু ঐচ্ছিক এক্সটেনশন রয়েছে। যদি সময় অনুমতি দেয়, তাহলে নীচের তালিকা থেকে অন্তত একটি এক্সটেনশন চেষ্টা করুন অথবা আপনার নিজের তৈরি একটি এক্সটেনশন ব্যবহার করুন।


  • দুই-অক্ষরের মোড: ব্যবহারকারীকে অ্যানাগ্রাম তৈরি করতে দুটি অক্ষর যোগ করার অনুমতি দেওয়ার জন্য স্যুইচ করুন।


  • সম্ভাব্য প্রাথমিক শব্দের পুল থেকে পর্যাপ্ত অ্যানাগ্রাম নেই এমন শব্দগুলি সরিয়ে শব্দ নির্বাচন অপ্টিমাইজ করুন। মনে রাখবেন যে শব্দগুলি wordSet এ থাকা উচিত কারণ সেগুলি এখনও অন্য শব্দে অ্যানাগ্রাম হিসাবে ব্যবহার করা যেতে পারে।


  • দুই-শব্দ মোড: ব্যবহারকারীকে দুটি নতুন বৈধ শব্দ তৈরি করতে এক জোড়া শব্দে একটি অক্ষর যোগ করার অনুমতি দিন।



শেষ পর্যন্ত পৌঁছানোর জন্য অভিনন্দন! আপনি আবিষ্কার করেছেন যে তালিকা, হ্যাশসেট এবং হ্যাশম্যাপগুলি কীভাবে ফ্লটারে দক্ষ ডেটা হ্যান্ডলিংকে শক্তিশালী করে, ঠিক যেমনটি তারা যেকোনো সু-অপ্টিমাইজড অ্যাপ্লিকেশনে করে। এই কাঠামোগুলি বোঝা আপনাকে স্কেলেবল এবং পারফর্ম্যান্ট কোড লেখার ক্ষেত্রে একটি সুবিধা দেয়। তাই এগিয়ে যান, এবং নিজের পিঠে একটি উপযুক্ত চাপ দিন! এখন, এই জ্ঞানকে কাজে লাগান এবং আশ্চর্যজনক জিনিস তৈরি করতে থাকুন!