0% found this document useful (0 votes)
9 views

FinalReport

The final term report for the Data Structures and Algorithms course at HCMC University of Technology and Education outlines a project involving three exercises focused on practical applications of data structures, including Circular Linked Lists, Queues, and Binary Search Trees. The report acknowledges the guidance of PhD. Le Van Vinh and details the project's objectives, implementation, and user interfaces developed in C#. The document also discusses the strengths and limitations of the project, along with future development ideas.

Uploaded by

jadeyvo364
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

FinalReport

The final term report for the Data Structures and Algorithms course at HCMC University of Technology and Education outlines a project involving three exercises focused on practical applications of data structures, including Circular Linked Lists, Queues, and Binary Search Trees. The report acknowledges the guidance of PhD. Le Van Vinh and details the project's objectives, implementation, and user interfaces developed in C#. The document also discusses the strengths and limitations of the project, along with future development ideas.

Uploaded by

jadeyvo364
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 78

HCMC UNIVERSITY OF TECHNOLOGY AND EDUCATION

FACULTY OF INTERNATIONAL EDUCATION

FINAL TERM REPORT

Course name: Data Structures and Algorithms

Lecturer’s name: PhD. Le Van Vinh

List of members
Student
Student name Contribution (%)
ID
23110004 Võ Nguyễn Ngọc Bích 100
23110019 Huỳnh Gia Hân 100
Ho Chi Minh City, December 2024
ACKNOWLEDGMENTS
First of all, we would like to express our deepest gratitude and heartfelt thanks to
PhD. Le Van Vinh, who has dedicatedly guided and supported us throughout the final
project of the Data Structures and Algorithms course. Through his invaluable
instruction, we have gained not only a solid foundation in essential concepts but also
the opportunity to explore the practical applications of data structures and algorithms
in solving real-world problems.
Dr. Vinh’s patience and expertise in answering our questions, coupled with his
ability to inspire logical thinking and problem-solving skills, have profoundly
impacted our learning process. His dedication has encouraged us to think critically,
analyze complex scenarios, and apply algorithmic techniques effectively.
Thanks to Dr. Vinh’s exceptional guidance, we were able to complete this project,
gaining newfound knowledge and insights into the subject. While we have done our
utmost to deliver a comprehensive project, we acknowledge that there are inevitably
limitations and areas for improvement. We sincerely hope to receive Dr. Vinh’s
feedback to further refine our understanding and skills, which will undoubtedly benefit
us in future academic and professional endeavors.
Once again, we would like to extend our profound appreciation to Dr. Vinh for
his unwavering support, passion for teaching, and commitment to student
development. We wish him good health, happiness, and continued success in his
career, as he continues to inspire and guide generations of students in their academic
journeys.
Best regard,
Group 06
TABLE OF CONTENTS
ACKNOWLEDGMENTS....................................................................................2
TABLE OF CONTENTS.....................................................................................3
TABLE OF FIGURES..........................................................................................4
A. PROJECT DESCRIPTION.........................................................................5
1. Problem statement....................................................................................5
2. Purpose and requirements.......................................................................5
3. Scope and targets......................................................................................5
3.1. Scope.......................................................................................................5
3.2. Target audience........................................................................................5
4. Overview of exercises................................................................................5
B. CONTENT....................................................................................................7
1. BACKGROUND KNOWLEDGE...........................................................7
1.1. Fundamental knowledge..........................................................................7
1.2. Circular Linked List.................................................................................8
1.3. Queue and its applications.......................................................................9
1.4. Binary Search Tree (BST).......................................................................9
1.5. Development environment....................................................................10
1.5.1. IDE..................................................................................................10
1.5.2. Programming language...................................................................10
1.6. Modules and Frameworks.....................................................................10
1.6.1. .NET Framework.............................................................................10
1.6.2. .NET Libraries.................................................................................10
1.7. Programming technique.........................................................................10
2. SYSTEM DESIGN..................................................................................12
2.1. System Architecture...............................................................................12
2.2. Main Functions......................................................................................13
2.2.1. Circular Linked List Functions........................................................13
2.2.2. Circular Linked List Functions in Music Playlist Management......16
2.2.3. Main Functions in Tetris Game.......................................................17
2.2.4. Main functions in Employee Management System..........................19
3. IMPLEMENTATION, TEST CASES, AND RESULTS......................22
3.1. Implementation......................................................................................22
3.1.1. Circular Linked List Implementation..............................................22
3.1.2. Music Playlist Management Implementation..................................32
3.1.3. Tetris Game Implementation...........................................................36
3.1.4. Employee Management System Implementation.............................48
3.1. Test cases and results.............................................................................56
3.2.1. Circular Linked List.........................................................................56
3.2.2. Music Playlist Management............................................................60
3.2.3. Tetris Game......................................................................................64
3.2.4. Employee Management System.......................................................68
C. CONCLUSION..............................................................................................74
1. EVALUATION.............................................................................................74
1.1. Strengths..................................................................................................74
1.2. Limitations..............................................................................................74
2. FUTURE DEVELOPMENT IDEAS.........................................................75
REFERENCES...................................................................................................77
ROLES AND CONTRIBUTIONS....................................................................78
TABLE OF FIGURES
Figure 1: Features of C Sharp.................................................................................9
Figure 2: Circular Singly Linked List.....................................................................9
Figure 3: Circular Doubly Linked List.................................................................10
A. PROJECT DESCRIPTION
1. Problem statement
The final project for the course "Data Structures and Algorithms" consists of
three exercises designed to apply different data structures in solving practical
problems. Each exercise is targeted at the implementation and application of a certain
data structure, with requirements to show the functionality through user interfaces and
meaningful results.
2. Purpose and requirements
• Develop practical programming skills using the implementation of data
structures like Circular Linked Lists, Queues, and Binary Search Trees.
• Investigate real-life applications for these structures with advanced operations
and user interaction.
• Improve problem-solving skills through designing and testing software
solutions.
3. Scope and targets
3.1. Scope
This project are targeted around three major exercises, as follows:
• Exercise 1: Circular Linked List with basic operations like insertion, deletion,
and search, as well as advanced functionalities such as sorting and merging lists. The
solution is implemented in C#.
• Exercise 2: The Tetris game uses a Queue for handling the storage and the
current state of the tetromino. The user interface is developed using C#.NET.
• Exercise 3: An Employee Management System employing a Binary Search Tree
to efficiently manage and search employee records. This system includes an intuitive
user interface developed in C# with WinForms.
3.2. Target audience
This project is for academic use and thus targets the following:
• Understand the usage of basic data structures in real-world scenarios.
• Instructors seek to assess students' skills in designing and implementing
algorithmic solutions.
4. Overview of exercises
Exercise 1: Circular Linked List
 Basic implementations cover insert, delete and find. Advanced operations
include sort and merge.
 Implemented with C# with a simplified user interface to better understand how
these operations work in detail.
Exercise 2: Queue in Tetris
 The Queue data structure allows smooth delivery of blocks during the game in
runtime.
Implemented using Winforms in C#. The provided UI navigates through this
smoothly.

Exercise 3: Employee Management System with BST


 Binary Search Tree is utilized for efficient employee record management.
The application features a comprehensive interface for adding, removing, and
searching employees based on customizable criteria.
B. CONTENT
1. BACKGROUND KNOWLEDGE
1.1. Fundamental knowledge
Programming Language: The project will utilize C# for core development.
C# is a general-purpose, modern and object-oriented programming language
pronounced as “C sharp”. It was developed by Microsoft led by Anders Hejlsberg and
his team within the .Net initiative and was approved by the European Computer
Manufacturers Association (ECMA) and International Standards Organization (ISO).
C# is among the languages for Common Language Infrastructure and the current
version of C# is version 7.2. C# is a lot similar to Java syntactically and is easy for the
users who have knowledge of C, C++ or Java, a bit about .Net Framework .Net
applications are multi-platform applications and framework can be used from
languages like C++, C#, Visual Basic, COBOL etc. It is designed in a manner so that
other languages can use it, know more about .Net Framework.
Why C#? C# has many other reasons for being popular and in demand. Few of
the reasons are mentioned below:
1. Easy to start: C# is a high-level language so it is closer to other popular
programming languages like C, C++, and Java, thus, becomes easy to learn for
anyone.
2. Widely used for developing Desktop and Web Application: C# is
widely used for developing web applications and Desktop applications. It is one of the
most popular languages that is used in professional desktop. If anyone wants to create
Microsoft apps, C# is their first choice.
3. Community: The larger the community the better it is as new tools and
software will be developing to make it better. C# has a large community, so the
developments are done to make it exist in the system and not become extinct.
4. Game Development: C# is widely used in game development and will
continue to dominate. C# integrates with Microsoft, thus, has a large target audience.
The C# features such as Automatic Garbage Collection, interfaces, object-oriented, etc,
which make C# a popular game developing language.
Figure 1: Features of C Sharp
1.2. Circular Linked List
A circular linked list is a data structure where the last node connects back to the
first, forming a loop. This structure allows for continuous traversal without any
interruptions. Circular linked lists are especially helpful for tasks
like scheduling and managing playlists, this allowing for smooth navigation. In this
tutorial, we’ll cover the basics of circular linked lists, how to work with them, their
advantages and disadvantages, and their applications.
A circular linked list is a special type of linked list where all the nodes are
connected to form a circle. Unlike a regular linked list, which ends with a node
pointing to NULL, the last node in a circular linked list points back to the first node.
This means that you can keep traversing the list without ever reaching a NULL value.
1.2.1. Circular Singly Linked List
In Circular Singly Linked List, each node has just one pointer called the “next”
pointer. The next pointer of last node points back to the first node and this results in
forming a circle. In this type of Linked List, we can only move through the list in one
direction.

Figure 2: Circular Singly Linked List


1.2.2. Circular Doubly Linked List
In circular doubly linked list, each node has two pointers prev and next, similar to
doubly linked list. The prev pointer points to the previous node and the next points to
the next node. Here, in addition to the last node storing the address of the first node,
the first node will also store the address of the last node.

Figure 3: Circular Doubly Linked List


1.3. Queue and its applications
Definition:
In computer science, a queue is a collection of entities that are maintained in a
sequence and can be modified by the addition of entities at one end of the sequence
and the removal of entities from the other end of the sequence. Basically, a queue is a
linear data structure that follows the First In, First Out principle. Elements are added
from the rear and removed from the front, making it suitable for managing tasks in
sequence.
Application in the project Tetris Game:
The Tetris game handles a sequence of tetromino blocks with the help of a
Queue. The current and next pieces are queued to provide fluent gameplay and logical
movement. This helps the players to strategize and think in advance about their moves.
Advantages:
 Predictable behavior due to the FIFO structure.
 It simplifies the implementation of sequential task management.
 Enhances system efficiency in scenarios where the preservation of order is
crucial, such as multimedia buffering or print job management.
Challenges:
In static queues, fixed size can lead to overflow or underutilization. In dynamic
implementations, these require careful management to avoid memory leaks or
fragmentation.
1.4. Binary Search Tree (BST)
Definition: A Binary Search Tree is a tree data structure in which each node has
no more than two children, known as left and right child nodes. The nodes are
arranged such that the values of the nodes to the left of any given node are less than
those of the parent node, while values of nodes to the right are greater. This ordering
facilitates searching, insertion, and deletion processes in the tree.
Applications in the Employee Management System: In the project, employee
records are stored and maintained in a BST. Finding an employee by name, inserting
new employees, or removing existing ones can be efficiently done. This provides
scalability and fast access to the records in real-time applications.
Advantages:
 Provides logarithmic time complexity for search, insert, and delete operations in
balanced trees.
 Ensures efficient organization and retrieval of data, particularly in applications
with dynamic datasets.
 Facilitates range queries and ordered data traversal using in-order traversal
techniques.
Challenges:
 Imbalanced trees can degrade performance to linear time complexity. To
mitigate this, self-balancing variants like AVL trees or Red-Black trees are often used.
 This requires a careful implementation regarding edge cases, such as duplicated
keys or node deletion when there are multiple children.
1.5. Development environment
1.5.1. IDE
Microsoft Visual Studio 2022 is used for the development of the Coffee Shop
Management System. This IDE provides great functionality in C# to develop and
manage multiple forms within a Windows Forms application.
1.5.2. Programming language
C# is the programming language to be used for this project. Object-oriented
programming Supported, along with the integration with the.NET ecosystem, makes it
perfect for creating robust, multi-form applications with smooth workflows.
1.6. Modules and Frameworks
1.6.1. .NET Framework
The .NET Framework is the backbone of the application, enabling the design and
execution of a multi-form graphical user interface.
Multi-Form Management: Allows seamless navigation between different forms,
such as login, order placement, payment, and feedback forms.
Event Handling: Simplifies the management of interactions between forms.
1.6.2. .NET Libraries
System.Windows.Forms: Providing controls like buttons, labels, text boxes,... for
forms like login, ordering, and payment.
Ensures smooth transitions and data exchange between forms.
1.7. Programming technique
Programming techniques are the backbone of this project, ensuring that the
implementation of data structures is efficient, user interactions are strong, and all
exercises are done with the best performance. This section outlines methodologies and
approaches taken in the course of this project, showing their reflection in design and
implementation.
 Object-Oriented Programming (OOP): OOP principles were crucial in the
development of the project, allowing modularity, code reusability, and scalability. Key
concepts applied include:
• Encapsulation: Classes like Queue, CircularLinkedList, and BinarySearchTree
encapsulate their attributes and methods internally, hence there is no interaction with
the internal details. This maintains the integrity of the data while simplifying code
maintenance.
• Inheritance: The project applies inheritance to create specialized classes for
specific applications, such as TetrominoQueue for the Tetris game and EmployeeBST
for managing employee records. In this way, redundant code is minimized because
core functionalities are inherited from base classes.
• Polymorphism: Dynamic behaviors are achieved by polymorphism, allowing
methods such as Insert() and Delete() to act differently in different contexts of the
application.
 Event-Driven Programming: The project relies a great deal on event-driven
programming in order to enhance interactivity; especially in WinForms applications.
Examples include:
• Dynamic User Interaction: Buttons, text fields, and other GUI elements trigger
specific actions, such as inserting data into a BST or displaying the next tetromino in
the Tetris queue.
• Real-Time Feedback: Events like OnClick() or OnChange() give immediate
responses to user inputs and maintain continuity in the user experience. For example,
in the Employee Management System, it automatically refreshes the UI after adding or
removing a record.
• Error Handling in Events: Events provide error handling mechanisms that can
help avoid crashes and ensure user-friendly error messages in cases of invalid input or
failed operations.
 Algorithm Optimization: Stress on efficient algorithms in data manipulation
ensures that the performance is optimal in both Queue and BST. The core algorithmic
optimization of the project rests mainly on how to deal with the dataset size and
maintain real-time performance. Strategies that contribute towards this goal include
but are not limited to the following:
• Efficiency of Data Structures: Implement efficient algorithms for operations
such as searching, sorting, and traversal. For example, a recursive in-order traversal of
BST maintains a tradeoff between readability and efficiency.
• Queue Management in Tetris: The tetromino queue employs the circular queue
algorithm for minimal memory utilization with seamless continuation.
• Balancing BSTs: Even though the project does not use self-balancing trees,
considerations to maintain the balance of insertions and deletions have been made to
optimize the search time.
 Data Validation and Error Handling: The project has robust data validation and
error handling mechanisms at each level of the project:
• Input validation: In this, the user inputs are checked for validity. For example,
numeric fields reject non-numeric characters to maintain data consistency.
• Exception handling: Exception handling is employed to deal with errors that
might arise during runtime, such as invalid payment amounts or unavailable items in
the inventory. Try-catch blocks are used to catch exceptions, ensuring that the
application remains robust and user-friendly even when an error occurs.
• Boundary checks: Operations related to data structures, such as dequeueing
from an empty queue and inserting duplicate keys in the BST, are performed with
boundary checks to maintain structural integrity.
2. SYSTEM DESIGN
2.1. System Architecture
3.1.1. Overview
The system integrates multiple components to solve the problems. The main
components include:
1. Data Structures:
 Used to organize and store input data.
 Structures such as linked lists, trees, graphs, etc, ensure efficient data
access and manipulation.
2. Algorithms:
 Includes processing algorithms such as sorting, searching, and
specialized algorithms for the specific problem.
 Examples: Quick Sort, Selection Sort, etc.
3. User Interface:
 Enables users to interact with the system through a simple and intuitive
interface.
 Supports data input, result display, and management of configuration
options.
3.1.2. Components
The system consists of the following main components:
1. Data Structure Module:
 Manages all stored and manipulated data.
 Provides APIs for basic operations such as adding, deleting, searching, or
updating data.
2. Algorithm Module:
 Contains the core algorithms used in the system.
 Algorithms are implemented optimally to ensure minimal time
complexity.
3. User Interaction Module:
 Facilitates communication between the user and the system through buttons,
forms, or graphical interfaces.
 Includes functions for data input, running algorithms, and displaying results.
3.1.3. Interaction between components
The interaction between system components is described as follows:
1. User and User Interface:
 Users input data or requests via the interface.
 The interface forwards these requests to the logic layer.
2. Interface and Logic:
 The interface sends input information to the logic layer.
 The logic layer performs computations or invokes processing algorithms
from the algorithm module.
3. Logic and Data:
 The logic layer manipulates data through the APIs of the data structure
module.
 Data is updated or queried from memory.
4. Processing and Display:
 Results from algorithms and data are returned to the interface for user
display.
 If visualization is enabled, data is passed to the visualization module
before being displayed.
2.2. Main Functions
2.2.1. Circular Linked List Functions
C Sharp (C#) language
1. Insert at Beginning
 Function: InsertAtBeginning(T data)
 Purpose: Adds a new node containing data at the beginning of the circular
linked list.
 Details: If the list is empty, the new node becomes the head and points to itself.
If the list is not empty, the new node points to the current head, and the last node in the
list is updated to point to the new head. A confirmation message is displayed indicating
the successful addition of the node.
2. Insert at End
 Function: InsertAtEnd(T data)
 Purpose: Adds a new node containing data at the end of the circular linked list.
 Details: If the list is empty, the new node becomes the head and points to itself.
Otherwise, the function traverses to the last node, adds the new node after it, and
ensures the new node points back to the head. A success message confirms the addition
of the node.
3. Remove First
 Function: RemoveFirst()
 Purpose: Removes the first node in the circular linked list.
 Details: If the list is empty, a message is displayed indicating that the operation
cannot be performed. If the list contains one node, it becomes empty. Otherwise, the
second node becomes the new head, and the last node is updated to point to the new
head. A confirmation message is displayed upon successful removal.
4. Remove Last
 Function: RemoveLast()
 Purpose: Removes the last node in the circular linked list.
 Details: If the list is empty, an error message is displayed. If the list contains
only one node, the list becomes empty. Otherwise, the function traverses to the second-
to-last node and updates it to point back to the head. A success message confirms the
removal.
5. Search
 Function: Search(T key)
 Purpose: Finds a node in the circular linked list by matching the key value.
 Details: The function traverses the list, comparing each node’s data with the
key. If found, the node is returned; otherwise, it returns null. A message indicates
whether the search was successful or not.
6. Selection Sort
 Function: SelectionSort()
 Purpose: Sorts the nodes of the circular linked list in ascending order using the
selection sort algorithm.
 Details: The function iteratively finds the smallest node in the unsorted portion
and swaps its value with the current node. The process continues until the entire list is
sorted. A success message confirms the completion of the sorting operation.
7. Quick Sort
 Function: Partition(Node<T> start, Node<T> end, out Node<T> newStart, out
Node<T> newEnd)
 Purpose: Partitions the circular linked list into two segments based on a pivot
node, as part of the quick sort algorithm.
 Details: The pivot is chosen as the last node (end). Iterates through the list,
comparing each node's data with the pivot. Nodes with values less than the pivot are
placed before it, while nodes with greater values are placed after it. Adjusts pointers to
ensure correct partitioning while maintaining the circular structure. Returns the pivot
node and updates newStart and newEnd to reflect the new boundaries of the
partitioned segments.
8. Print List
 Function: PrintList()
 Purpose: Prints all the nodes in the circular linked list in order, starting from the
head.
 Details: If the list is empty, it outputs "List is empty." Otherwise, it traverses the
list, displaying each node's data in sequence, followed by an indicator showing the
head node at the end.
C++ Language
1. Add Node at Beginning
 Function: insertAtBeginning(T data)
 Purpose: Adds a new node with the given data at the beginning of the circular
linked list.
 Details: If the list is empty, the new node is set as the head and points to itself.
If the list is not empty, the new node is added before the current head, and the last
node's next pointer is updated to the new head.
2. Add Node at End
 Function: insertAtEnd(T data)
 Purpose: Adds a new node with the given data at the end of the circular linked
list.
 Details: If the list is empty, the new node is set as the head and points to itself.
If the list is not empty, the new node is added after the last node, and its next pointer is
updated to point to head.
3. Remove First Node
 Function: removeFirst()
 Purpose: Removes the first node from the circular linked list.
 Details: If the list is empty, no action is performed. If the list contains only one
node, it is deleted, and the head is set to nullptr. If the list contains multiple nodes, the
head is updated to the second node, and the last node's next pointer is updated to point
to the new head.
4. Remove Last Node
 Function: removeLast()
 Purpose: Removes the last node from the circular linked list.
 Details: If the list is empty, no action is performed. If the list contains only one
node, it is deleted, and the head is set to nullptr. If the list contains multiple nodes, the
second-to-last node is updated to point to head.
5. Print List
 Function: printList()
 Purpose: Displays all the nodes in the circular linked list.
 Details: If the list is empty, a message indicating an empty list is displayed. If
the list contains nodes, their data is displayed in order, ending with a pointer to the
head node.
6. Sort List (Selection Sort)
 Function: selectionSort()
 Purpose: Sorts the nodes in ascending order of their data using the selection sort
algorithm.
 Details: Iterates through the list, finding the smallest value in each pass and
swapping it with the current node's data. If the list is empty or contains only one node,
no action is performed.
7. Merge Two Circular Lists
 Function: merge(CircularLinkedList<T>& otherList)
 Purpose: Merges another circular linked list with the current list.
 Details: If the current list is empty, the head of the other list becomes the head
of the merged list. If the other list is empty, no action is performed. Links the last node
of the current list to the first node of the other list and vice versa.
8. Destructor
 Function: ~CircularLinkedList()
 Purpose: Releases all memory used by the circular linked list.
 Details: Deletes each node in the list, ensuring that no memory leaks occur.
Handles edge cases for an empty or single-node list.
2.2.2. Circular Linked List Functions in Music Playlist Management
1. Add Song
 Function: AddSong(Song song)
 Purpose: Adds a new song to the playlist.
 Details: The song's details include the title, artist, and duration (in seconds).
This function confirms the addition by displaying a success message.
2. Remove Song
 Function: RemoveSong(string title)
 Purpose: Removes a song from the playlist by matching the song title.
 Details: If the song exists, it is removed, and a confirmation message is
displayed. Otherwise, an error message indicates that the song was not found.
3. Display Playlist
 Function: DisplayPlaylist()
 Purpose: Displays all the songs currently in the playlist.
 Details: Each song's title, artist, and duration are listed. If the playlist is empty,
a message indicates this.
4. Play Next Song
 Function: PlayNext()
 Purpose: Simulates playing the next song in the playlist.
 Details: Uses a circular behavior to ensure that after the last song, the playlist
loops back to the first song. Displays the currently playing song's details.
5. Clear Playlist
 Function: ClearPlaylist()
 Purpose: Removes all songs from the playlist.
 Details: Clears the internal song list and confirms the action with a message.
6. Search Song by Title
 Function: SearchSongByTitle(string title)
 Purpose: Finds and displays a song that matches the given title.
 Details: If found, the song's details are displayed. If not, a message indicates
that no match was found.
7. Search Songs by Artist
 Function: SearchSongsByArtist(string artist)
 Purpose: Displays all songs by a specific artist.
 Details: Searches for all songs by the artist. If matches are found, their titles and
durations are displayed. Otherwise, an error message is shown.
8. Display Total Playlist Duration
 Function: DisplayTotalDuration()
 Purpose: Calculates and displays the total duration of all songs in the playlist.
 Details: The duration is displayed in seconds, as well as in minutes and seconds
for user-friendliness.
9. Add Sample Songs
 Function: AddSampleSongs()
 Purpose: Adds a predefined set of songs to the playlist for demonstration
purposes.
 Details: Includes classic songs like Bohemian Rhapsody and Imagine. This
helps users start with a populated playlist for testing.
2.2.3. Main Functions in Tetris Game
The Tetris game is implemented with the following main functionalities:
Block Management:
 Blocks are instantiated with the Block class and derived classes such as IBlock
and JBlock.
 Rotation and move logic ensures that blocks move and rotate according to the
rules of Tetris.
Grid Management:
 The GameGrid class handles the grid structure, checking the validity of
positions and dealing with row clearing when all positions in a row are occupied.
 Other rows above the row to be cleared are moved down to maintain continuity.
Controlling Game Flow:
 GameState class provides a smooth game flow, from controlling the current
block to placing the block and checking for game over conditions.
 Hold allows players to hold a block for later use.
Scoring System: The players receive points according to the number of cleared
rows. The more rows that get cleared at once, the higher the score.
Random Block Queue: The BlockQueue class generates a random order of
blocks, ensuring that the same block does not consecutively appear.
Graphic User Interface:
No GUI Purpose Description
 Title
"TETRIS" in green
 "START
GAME" button:
Begins new game
 "EXIT"
button: Closes
Display the main application
 Game controls
menu screen for
1 panel: Shows key
the Tetris game mappings for
application movement (←→),
rotation (T,Z), hold
(H), and drop actions
(Space)
 Team’s
information: Shows
Group 06 members
 Score display:
Tracks current points
(0)
 Main grid:
Where blocks fall and
stack
 Hold panel:
Active gameplay Stores a piece for
later use
interface where
2  Next panel:
players interact Shows upcoming
with falling blocks piece
 Control guide:
Displays game
control keys
 Active pieces:
Yellow square block
in play
 "Game Over"
message
 Final score
display (Example:
230)
 "Play Again"
button: Restarts game
End game screen  Filled playing
3 showing results field: Shows ending
and restart option block configuration
 Side panels:
Still showing held
and next pieces
 Control guide:
Maintains visibility
of key controls

2.2.4. Main functions in Employee Management System


Add New Employee Form:
Purpose: This feature will be used for administrators to insert and save details of
newly recruited employees in a very easy way.
Features:
 The following input fields will be provided: Employee ID, Full Name, Date of
Birth, Department, Position, and Salary.
 Apply validation wherever necessary for accurate data. For example, numeric
validations for Employee ID and Salary.
 It will check any duplicate Employee IDs and render error messages in that
regards.
 This interface will enable orderly and lucid data insertion.
Edit Employee’s information:
Purpose: This allows the modification of already existing employee records to
keep information updated.
Features:
 The admin can search an employee by ID and edit Full Name, Department, or
Salary.
 It provides real-time validation of all the fields that have to meet the criteria
before saving the changes.
 Provides error handling to avoid storing any invalid data.
Search Employee:
Purpose: To enable the quick retrieval of employee information with specified
criteria.
Features:
 Case-insensitive search functionality enables users to locate employees by
partial or full name.
 Displays search results in a tabular format for better readability and easy
navigation.
 Ensures efficient data retrieval using a Binary Search Tree (BST) backend.
List All Employees:
Purpose: To view a summary of all employees in the system.
Features:
 It displays the employee's data, including Employee ID, Full Name, Date of
Birth, Department, Position, and Salary.
 It allows direct actions such as editing or deleting records from the list
interface.
 A dynamic DataGridView is used to display and interactively manage employee
data.
Delete Employee ():
Purpose: Allows administrators to delete any employee record that is outdated or
wrong.
Features:
 Confirmation prompts prevent accidental deletions.
 Dynamic updating of the Binary Search Tree structure maintains consistency
and integrity.
Validate Input Data:
Purpose: Ensures that data stored in the system is accurate and coherent.
Features:
 Checks numeric fields, date ranges, and required fields.
 Provides friendly error messages when invalid data is input.
 Ensures logical data-for example, checking the age to ensure that an employee
is at least 16 years old.
User Navigation (MainForm):
Purpose: To make the interaction of users with the system easy through properly
structured navigation options.
Features:
 Has buttons for adding, editing, searching, and listing of employees.
 Allows transitions between different forms seamlessly while preserving the
context, which makes the user experience smooth.

Graphic User Interface:
No GUI Purpose Description

This form is a
welcome page
displaying BST
MainForm:
implementation
Introduce system
1 details, key features
features and
list
display our team’s
(Add/Search/Delete,
information
BST operations),
and navigation menu
with four tabs

Data entry form with


fields for Employee
ID, Full Name, Date
FormAddEmploye of Birth
2 e: Create new (DD/MM/YY),
employee records Department,
Position, Salary via
textbox, and Save
button

Edit form with


locked Employee ID
FormEditEmployee
field, input fields for
3 : Modify existing
personal/professiona
employee
l details, and Save
information
button for
confirming changes
Table interface
showing all
FormListEmployee
employee records
4 :Display
with direct
comprehensive
edit/delete
employee database
functionality noted
below

Simple search
FormSearchEmp: interface with
5 Find specific employee ID input
employee field, search button,
information and results display
area

3. IMPLEMENTATION, TEST CASES, AND RESULTS


3.1. Implementation
3.1.1. Circular Linked List Implementation
C Sharp (C#) Language
Insert at public void InsertAtBeginning(T data)
Beginning {
var newNode = new Node<T>(data);
if (IsEmpty())
{
head = newNode;
head.Next = head;
}
else
{
Node<T> temp = head;
while (temp.Next != head)
{
temp = temp.Next;
}
newNode.Next = head;
temp.Next = newNode;
head = newNode;
}
}
Interface code

this.btnInsertAtBegin.Font = new
System.Drawing.Font("Microsoft Sans Serif", 13F,
System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnInsertAtBegin.Location = new System.Drawing.Point(12,
50);
this.btnInsertAtBegin.Name = "btnInsertAtBegin";
this.btnInsertAtBegin.Size = new System.Drawing.Size(177, 39);
this.btnInsertAtBegin.TabIndex = 1;
this.btnInsertAtBegin.Text = "Insert at Begin";
this.btnInsertAtBegin.UseVisualStyleBackColor = true;
this.btnInsertAtBegin.Click += new
System.EventHandler(this.btnInsertAtBegin_Click);

private void btnInsertAtBegin_Click(object sender, EventArgs e)


{
if (int.TryParse(txtInput.Text, out int data))
{
list.InsertAtBeginning(data);
txtInput.Clear();
PrintList();
}
}
Insert at End public void InsertAtEnd(T data)
{
var newNode = new Node<T>(data);
if (IsEmpty())
{
head = newNode;
head.Next = head;
}
else
{
Node<T> temp = head;
while (temp.Next != head)
{
temp = temp.Next;
}
temp.Next = newNode;
newNode.Next = head;
}
}

Interface code
this.btnInsertAtEnd.Font = new System.Drawing.Font("Microsoft
Sans Serif", 13F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnInsertAtEnd.Location = new System.Drawing.Point(12,
95);
this.btnInsertAtEnd.Name = "btnInsertAtEnd";
this.btnInsertAtEnd.Size = new System.Drawing.Size(177, 30);
this.btnInsertAtEnd.TabIndex = 2;
this.btnInsertAtEnd.Text = "Insert at End";
this.btnInsertAtEnd.UseVisualStyleBackColor = true;
this.btnInsertAtEnd.Click += new
System.EventHandler(this.btnInsertAtEnd_Click);

private void btnInsertAtEnd_Click(object sender, EventArgs e)


{
if (int.TryParse(txtInput.Text, out int data))
{
list.InsertAtEnd(data);
txtInput.Clear();
PrintList();
}
}
Remove First public void RemoveFirst()
{
if (IsEmpty()) return;

if (head.Next == head)
{
head = null;
}
else
{
Node<T> temp = head;
while (temp.Next != head)
{
temp = temp.Next;
}
temp.Next = head.Next;
head = head.Next;
}
}

Interface code

this.btnRemoveFirst.Font = new System.Drawing.Font("Microsoft


Sans Serif", 13F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnRemoveFirst.Location = new System.Drawing.Point(12,
131);
this.btnRemoveFirst.Name = "btnRemoveFirst";
this.btnRemoveFirst.Size = new System.Drawing.Size(177, 30);
this.btnRemoveFirst.TabIndex = 3;
this.btnRemoveFirst.Text = "Remove First";
this.btnRemoveFirst.UseVisualStyleBackColor = true;
this.btnRemoveFirst.Click += new
System.EventHandler(this.btnRemoveFirst_Click);

private void btnRemoveFirst_Click(object sender, EventArgs e)


{
list.RemoveFirst();
PrintList();
}
Remove Last public void RemoveLast()
{
if (IsEmpty()) return;

if (head.Next == head)
{
head = null;
}
else {
Node<T> temp = head;
while (temp.Next.Next != head)
{
temp = temp.Next;
}
temp.Next = head;
}
}

Interface code

this.btnRemoveLast.Font = new System.Drawing.Font("Microsoft


Sans Serif", 13F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnRemoveLast.Location = new System.Drawing.Point(12,
167);
this.btnRemoveLast.Name = "btnRemoveLast";
this.btnRemoveLast.Size = new System.Drawing.Size(177, 30);
this.btnRemoveLast.TabIndex = 4;
this.btnRemoveLast.Text = "Remove Last";
this.btnRemoveLast.UseVisualStyleBackColor = true;
this.btnRemoveLast.Click += new
System.EventHandler(this.btnRemoveLast_Click);
private void btnRemoveLast_Click(object sender, EventArgs e)
{
list.RemoveLast();
PrintList();
}
Search public Node<T> Search(T key)
{
if (IsEmpty()) return null;

Node<T> temp = head;


do
{
if (temp.Data.CompareTo(key) == 0)
return temp;
temp = temp.Next;
} while (temp != head);

return null;
}

Interface code

this.btnSearch.Font = new System.Drawing.Font("Microsoft Sans


Serif", 13F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnSearch.Location = new System.Drawing.Point(12, 203);
this.btnSearch.Name = "btnSearch";
this.btnSearch.Size = new System.Drawing.Size(177, 30);
this.btnSearch.TabIndex = 5;
this.btnSearch.Text = "Search";
this.btnSearch.UseVisualStyleBackColor = true;
this.btnSearch.Click += new
System.EventHandler(this.btnSearch_Click);

private void btnSearch_Click(object sender, EventArgs e)


{
if (int.TryParse(txtInput.Text, out int key))
{
var result = list.Search(key);
MessageBox.Show(result != null ? $"Found: {key}" : "Not
Found");
}
}
Print List public void PrintList()
{
if (IsEmpty())
{
Console.WriteLine("List is empty.");
return;
}

Node<T> temp = head;


do
{
Console.Write($"{temp.Data} -> ");
temp = temp.Next;
} while (temp != head);
Console.WriteLine($"(head: {head.Data})");
}

Interface code

this.btnPrintList.Font = new System.Drawing.Font("Microsoft


Sans Serif", 13F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnPrintList.Location = new System.Drawing.Point(12, 239);
this.btnPrintList.Name = "btnPrintList";
this.btnPrintList.Size = new System.Drawing.Size(177, 30);
this.btnPrintList.TabIndex = 6;
this.btnPrintList.Text = "Print List";
this.btnPrintList.UseVisualStyleBackColor = true;
this.btnPrintList.Click += new
System.EventHandler(this.btnPrintList_Click);

private void btnPrintList_Click(object sender, EventArgs e)


{
PrintList();
}
Selection Sort public void SelectionSort()
{
if (IsEmpty() || head.Next == head) return;

Node<T> current = head;


do
{
Node<T> min = current;
Node<T> temp = current.Next;

while (temp != head)


{
if (temp.Data.CompareTo(min.Data) < 0)
{
min = temp;
}
temp = temp.Next;
}

if (!Equals(current.Data, min.Data))
{
T swap = current.Data;
current.Data = min.Data;
min.Data = swap;
}

current = current.Next;
} while (current != head);
}

Interface code

this.btnSort.Font = new System.Drawing.Font("Microsoft Sans


Serif", 13F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnSort.Location = new System.Drawing.Point(12, 275);
this.btnSort.Name = "btnSort";
this.btnSort.Size = new System.Drawing.Size(177, 30);
this.btnSort.TabIndex = 7;
this.btnSort.Text = "Sort";
this.btnSort.UseVisualStyleBackColor = true;
this.btnSort.Click += new
System.EventHandler(this.btnSort_Click);

private void btnSort_Click(object sender, EventArgs e)


{
list.SelectionSort();
PrintList();
}
C++ Language
Insert at void insertAtBeginning(T data)
Beginning {
Node<T>* newNode = new Node<T>(data);
if (isEmpty())
{
head = newNode;
head->next = head;
}
else
{
Node<T>* temp = head;
while (temp->next != head)
{
temp = temp->next;
}
newNode->next = head;
temp->next = newNode;
head = newNode;
}
}
Insert at End void insertAtEnd(T data)
{
Node<T>* newNode = new Node<T>(data);
if (isEmpty())
{
head = newNode;
head->next = head;
}
else
{
Node<T>* temp = head;
while (temp->next != head)
{
temp = temp->next;
}
temp->next = newNode;
newNode->next = head;
}
}
Remove First void removeFirst()
{
if (isEmpty())
return;

if (head->next == head)
{
delete head;
head = nullptr;
}
else
{
Node<T>* temp = head;
while (temp->next != head)
{
temp = temp->next;
}
Node<T>* toDelete = head;
temp->next = head->next;
head = head->next;
delete toDelete;
}
}
Remove Last void removeLast()
{
if (isEmpty())
return;

if (head->next == head)
{
delete head;
head = nullptr;
}
else
{
Node<T>* temp = head;
while (temp->next->next != head)
{
temp = temp->next;
}
Node<T>* toDelete = temp->next;
temp->next = head;
delete toDelete;
}
}
Print List void printList()
{
if (isEmpty())
{
cout << "List is empty.\n";
return;
}

Node<T>* temp = head;


do
{
cout << temp->data << " -> ";
temp = temp->next;
} while (temp != head);
cout << "(head: " << head->data << ")\n";
}
Selection Sort void selectionSort()
{
if (isEmpty() || head->next == head)
return;

Node<T>* current = head;


do
{
Node<T>* min = current;
Node<T>* temp = current->next;

while (temp != head)


{
if (temp->data < min->data)
{
min = temp;
}
temp = temp->next;
}

if (current->data != min->data)
{
std::swap(current->data, min->data);
}

current = current->next;
} while (current != head);
}
Merge void merge(CircularLinkedList<T>& otherList)
{
if (isEmpty())
{
head = otherList.head;
return;
}

if (otherList.isEmpty())
return;

Node<T>* temp1 = head;


while (temp1->next != head)
{
temp1 = temp1->next;
}

Node<T>* temp2 = otherList.head;


while (temp2->next != otherList.head)
{
temp2 = temp2->next;
}

temp1->next = otherList.head;
temp2->next = head;
}
Destruction ~CircularLinkedList()
{
if (!isEmpty())
{
Node<T>* temp = head;
do
{
Node<T>* toDelete = temp;
temp = temp->next;
delete toDelete;
} while (temp != head);
}
}

3.1.2. Music Playlist Management Implementation


Functions code
Add a Song public void AddSong(Song song)
{
songs.Add(song);
Console.WriteLine($"Song '{song.Title}' added to the playlist.");
}
Remove a public void RemoveSong(string title)
Song {
Song song = songs.Find(s => s.Title.Equals(title,
StringComparison.OrdinalIgnoreCase));
if (song != null)
{
songs.Remove(song);
Console.WriteLine($"Song '{title}' removed from the
playlist.");
}
else
{
Console.WriteLine($"Song '{title}' not found in the playlist.");
}
}
Display public void DisplayPlaylist()
Playlist {
if (songs.Count == 0)
{
Console.WriteLine("The playlist is empty.");
return;
}

Console.WriteLine("\nPlaylist:");
foreach (var song in songs)
{
Console.WriteLine($"Title: {song.Title}, Artist: {song.Artist},
Duration: {song.Duration} seconds");
}
}
Play Next public void PlayNext()
Song {
if (songs.Count == 0)
{
Console.WriteLine("The playlist is empty.");
return;
}

currentIndex = (currentIndex + 1) % songs.Count;


Song currentSong = songs[currentIndex];
Console.WriteLine($"\nNow playing: {currentSong.Title} by
{currentSong.Artist} ({currentSong.Duration} seconds)");
}
Clear Playlist public void ClearPlaylist()
{
songs.Clear();
Console.WriteLine("All songs have been removed from the
playlist.");
}
Search Song public void SearchSongByTitle(string title)
by Title {
Song song = songs.Find(s => s.Title.Equals(title,
StringComparison.OrdinalIgnoreCase));
if (song != null)
{
Console.WriteLine($"\nSong Found: Title: {song.Title}, Artist:
{song.Artist}, Duration: {song.Duration} seconds");
}
else
{
Console.WriteLine($"Song '{title}' not found in the playlist.");
}
}
Search Song public void SearchSongsByArtist(string artist)
by Artist {
var foundSongs = songs.FindAll(s => s.Artist.Equals(artist,
StringComparison.OrdinalIgnoreCase));

if (foundSongs.Count > 0)
{
Console.WriteLine($"\nSongs by Artist '{artist}':");
foreach (var song in foundSongs)
{
Console.WriteLine($"Title: {song.Title}, Duration:
{song.Duration} seconds");
}
}
else
{
Console.WriteLine($"No songs by '{artist}' found in the
playlist.");
}
}
Display Total public void DisplayTotalDuration()
Duration {
int totalDuration = 0;

foreach (var song in songs)


{
totalDuration += song.Duration;
}

Console.WriteLine($"\nTotal Playlist Duration: {totalDuration}


seconds ({totalDuration / 60} minutes and {totalDuration % 60}
seconds)");
}
Add Sample public void AddSampleSongs()
Song {
AddSong(new Song("Bohemian Rhapsody", "Queen", 354));
AddSong(new Song("Imagine", "John Lennon", 183));
AddSong(new Song("Hotel California", "Eagles", 390));
AddSong(new Song("Shape of You", "Ed Sheeran", 233));

Console.WriteLine("\nSample songs added to the playlist:");


DisplayPlaylist();
}
Interface code
Initialize Playlist playlist = new Playlist();
playlist.AddSampleSongs();
Menu while (true)
{
Console.WriteLine("\n--- Music Playlist Manager ---");
Console.WriteLine("1. Add a Song");
Console.WriteLine("2. Remove a Song");
Console.WriteLine("3. Display Playlist");
Console.WriteLine("4. Play Next Song");
Console.WriteLine("5. Search Song by Title");
Console.WriteLine("6. Search Songs by Artist");
Console.WriteLine("7. Display Total Playlist Duration");
Console.WriteLine("8. Clear Playlist");
Console.WriteLine("9. Exit");
Console.Write("Enter your choice: ");

if (!int.TryParse(Console.ReadLine(), out int choice) || choice < 1 ||


choice > 9)
{
Console.WriteLine("Invalid choice. Please try again.");
continue;
}

if (choice == 9) break;

switch (choice)
{
case 1:
Console.Write("Enter song title: ");
string title = Console.ReadLine();
Console.Write("Enter artist name: ");
string artist = Console.ReadLine();
Console.Write("Enter song duration (seconds): ");
if (int.TryParse(Console.ReadLine(), out int duration))
{
playlist.AddSong(new Song(title, artist, duration));
}
else
{
Console.WriteLine("Invalid duration entered. Song not
added.");
}
break;

case 2:
Console.Write("Enter the title of the song to remove: ");
string removeTitle = Console.ReadLine();
playlist.RemoveSong(removeTitle);
break;

case 3:
playlist.DisplayPlaylist();
break;

case 4:
playlist.PlayNext();
break;
case 5:
Console.Write("Enter the song title to search: ");
string searchTitle = Console.ReadLine();
playlist.SearchSongByTitle(searchTitle);
break;

case 6:
Console.Write("Enter the artist name to search: ");
string searchArtist = Console.ReadLine();
playlist.SearchSongsByArtist(searchArtist);
break;

case 7:
playlist.DisplayTotalDuration();
break;

case 8:
playlist.ClearPlaylist();
break;
}

Console.WriteLine("\nPress Enter to continue...");


Console.ReadLine();
}

3.1.3. Tetris Game Implementation


The provided code demonstrates the modular implementation of the Tetris
game. Key highlights include:
Block Class:
 Abstract base class defining common properties and methods for all block
types.
 Supports rotation (clockwise and counterclockwise) and movement.
 Properties:
o Tiles: The shapes of the block in different rotations.
o StartOffset: The initial position of the block on the grid.
o Id: A unique identifier for the block type.
 Methods:
o TilePosition(): Returns the current position of each tile in the block.
o RotateCW and RotateCCW: Rotates the block clockwise or
counterclockwise.
o Move: Moves the block by a given number of rows and columns.
o Reset: Resets the block to its initial state.
namespace TetrisGame
{
public abstract class Block
{
protected abstract Position[][] Tiles { get; }
protected abstract Position StartOffset { get; }
public abstract int Id { get; }
private int rotationState;
private Position offset;
public Block() {
offset = new Position(StartOffset.Row, StartOffset.Column);
}

public IEnumerable<Position> TilePosition()


{
foreach (Position p in Tiles[rotationState])
{
yield return new Position(p.Row + offset.Row, p.Column +
offset.Column);
}
}
public void RotateCW()
{
rotationState = (rotationState + 1) % Tiles.Length;
}

public void RotateCCW() {


if (rotationState == 0)
{
rotationState = Tiles.Length - 1;
}
else
{
rotationState--;
}
}
public void Move (int rows, int columns)
{
offset.Row+=rows;
offset.Column += columns;
}
public void Reset()
{
rotationState = 0;
offset.Row = StartOffset.Row;
offset.Column = StartOffset.Column;
}
}
}
BlockQueue Class:
The BlockQueue class manages the sequence of blocks:
 Maintains an array of all block types (IBlock, JBlock, etc.).
 Randomly selects the next block, ensuring no consecutive duplicates.
namespace TetrisGame
{
public class BlockQueue
{
private readonly Block[] blocks = new Block[]
{
new IBlock(),
new JBlock(),
new LBlock(),
new OBlock(),
new SBlock(),
new TBlock(),
new ZBlock()
};
private readonly Random random = new Random();
public Block NextBlock { get; private set; }
public BlockQueue()
{
NextBlock = RandomBlock();
}

private Block RandomBlock()


{
return blocks[random.Next(blocks.Length)];
}

public Block GetAndUpdate()


{
Block block = NextBlock;
do
{
NextBlock = RandomBlock();
}
while (block.Id == NextBlock.Id);
return block;
}

}
}
GameGrid Class: Handles grid boundaries, checks for empty spaces, and clears
full rows
 Properties:
o Rows and Columns: Dimensions of the grid.
o A 2D array to track the state of each cell (occupied or empty).
 Methods:
o IsInside and IsEmpty: Validate cell positions.
o IsRowFull and IsRowEmpty: Check row states.
o ClearFullRows: Clears full rows and shifts above rows down.
namespace TetrisGame
{
public class GameGrid
{
private readonly int[,] grid;
public int Rows { get; }
public int Columns { get; }

public int this[int r, int c] {


get => grid[r, c];
set => grid[r, c] = value;
}
public GameGrid(int rows, int columns) {
Rows = rows;
Columns = columns;
grid = new int[rows, columns];
}

public bool IsInside(int r, int c)


{
return r>=0 && r<Rows && c>=0 && c<Columns;
}
public bool IsEmpty(int r, int c)
{
return IsInside(r, c) && grid[r, c] == 0;
}
public bool IsRowFull(int r)
{
for (int c=0; c<Columns; c++)
{
if (grid[r, c] == 0)
{
return false;
}
}
return true;
}
public bool IsRowEmpty(int r)
{
for (int c = 0; c < Columns; c++)
{
if (grid[r, c] != 0)
{
return false;
}
}
return true;
}
private void ClearRow(int r)
{
for (int c = 0; c < Columns; c++)
{
grid[r, c] = 0;

}
}
//Dời hàng cột giữ nguyên
private void MoveRowDown(int r, int numRows) {
for (int c = 0; c < Columns; c++) {
grid[r + numRows, c] = grid[r, c];
grid[r,c] = 0;
}
}
public int ClearFullRows()
{
int cleared = 0;
for (int r = Rows -1; r >= 0; r--)
{
if (IsRowFull(r))
{
ClearRow(r);
cleared++;
}
else if (cleared > 0)
{
MoveRowDown(r, cleared);
}
}
return cleared;
}
}
}
GameState Class:
The GameState class manages the game logic:
 Handles the current block, score, and held block mechanics.
 Implements block movements (left, right, down, rotate) and collision checks.
 Detects game-over conditions.
namespace TetrisGame
{
public class GameState
{
private Block currentBlock;
public Block CurrentBlock {
get => currentBlock;
private set
{
currentBlock = value;
currentBlock.Reset();

for (int i = 0; i < 2; i++)


{
currentBlock.Move(1, 0);
if (!BlockFits())
{
currentBlock.Move(-1, 0);
}
}
}
}
public GameState()
{
GameGrid = new GameGrid(22, 10);
BlockQueue = new BlockQueue();
CurrentBlock = BlockQueue.GetAndUpdate();
CanHold = true;
}
public GameGrid GameGrid { get; }
public BlockQueue BlockQueue { get; }
public bool GameOver {get; private set;}
public int Score { get; private set;}
public Block HeldBlock { get; private set;}
public bool CanHold { get; private set;}

public void HoldBlock()


{
if (!CanHold)
{
return;
}
if (HeldBlock == null)
{
HeldBlock = CurrentBlock;
CurrentBlock = BlockQueue.GetAndUpdate();
}
else
{
Block tmp = CurrentBlock;
CurrentBlock = HeldBlock;
HeldBlock = tmp;
}
CanHold = false;
}

private bool BlockFits()


{
foreach (Position p in CurrentBlock.TilePosition())
{
if (!GameGrid.IsEmpty(p.Row, p.Column))
{
return false;
}
}
return true;
}

public void RotateBlockCW()


{
CurrentBlock.RotateCW();
if (!BlockFits())
{
CurrentBlock.RotateCCW();
}
}
public void RotateBlockCCW() {
CurrentBlock.RotateCCW();
if (!BlockFits()) {
CurrentBlock.RotateCW();
}
}
public void MoveBlockLeft()
{
CurrentBlock.Move(0, -1);
if (!BlockFits())
{
CurrentBlock.Move(0, 1);
}
}
public void MoveBlockRight()
{
CurrentBlock.Move(0, 1);
if (!BlockFits())
{
CurrentBlock.Move(0, -1);
}
}
private bool IsGameOver()
{
return !(GameGrid.IsRowEmpty(0) && GameGrid.IsRowEmpty(1));
}

private void PlaceBlock()


{
foreach (Position p in CurrentBlock.TilePosition())
{
GameGrid[p.Row, p.Column] = CurrentBlock.Id;
}
Score += GameGrid.ClearFullRows() *10;
if (IsGameOver())
{
GameOver = true;
}
else
{
CurrentBlock = BlockQueue.GetAndUpdate();
CanHold = true;

}
}
public void MoveBlockDown()
{
CurrentBlock.Move(1, 0);
if (!BlockFits())
{
CurrentBlock.Move(-1, 0);
PlaceBlock();
}
}
private int TileDropDistane(Position p)
{
int drop = 0;
while (GameGrid.IsEmpty(p.Row + drop + 1, p.Column))
{
drop++;
}
return drop;
}
public int BlockDropDistance()
{
int drop = GameGrid.Rows;
foreach (Position p in CurrentBlock.TilePosition())
{
drop = System.Math.Min(drop, TileDropDistane(p));
}
return drop;
}

public void DropBlock()


{
CurrentBlock.Move(BlockDropDistance(), 0);
PlaceBlock();
}
}
}

Specific Block Classes


Classes like IBlock, JBlock, LBlock, etc., inherit from Block and define specific
tile configurations for each block type.
Some demostrations:

I-Block Image (Source: Internet)

namespace TetrisGame
{
public class IBlock:Block
{
private readonly Position[][] tiles = new Position[][]
{
new Position[] {new(1,0), new (1,1), new(1,2), new(1,3) },
new Position[] {new(0,2), new (1,2), new(2,2), new(3,2) },
new Position[] {new(2,0), new (2,1), new(2,2), new(2,3) },
new Position[] {new(0,1), new (1,1), new(2,1), new(3,1) }
};
public override int Id => 1;
protected override Position StartOffset => new Position(-1, 3);
protected override Position[][] Tiles => tiles;
}
}

J-Block Image (Source: Internet)

namespace TetrisGame
{
public class JBlock : Block
{
private readonly Position[][] tiles = new Position[][]
{
new Position[] {new(0,0), new (1,0), new(1,1), new(1,2) },
new Position[] {new(0,1), new (0,2), new(1,1), new(2,1) },
new Position[] {new(1,0), new (1,1), new(1,2), new(2,2) },
new Position[] {new(0,1), new (1,1), new(2,0), new(2,1) }

};

public override int Id => 2;


protected override Position StartOffset => new Position(0, 3);
protected override Position[][] Tiles => tiles;
}
3.1.4. Employee Management System Implementation
The Employee Management System is built on the .NET framework, utilizing
key libraries and components to ensure functionality and reliability. This application
implements a data structure Binary Search Tree for efficient management of employee
records. Designed with modularity, usability, and extensibility in mind, each and every
feature is implemented with due deliberation.
The system is composed of several components that interact to provide a
seamless user experience. These components include:
 EmployeeNode Class: Represents individual employee records.
 EmployeeTree Class: It maintains a BST structure of the database and allows
insertions, deletions, search, and traversal on the tree structure.
 Forms: Graphical User Interface (GUI) components for user interaction,
including adding, editing, searching, and displaying employee records.
 MainForm: Provides the main interface for switching between forms.
 Data Structure: Binary Search Tree (BST)
The BST is used to store and manage employee records. Each node in the tree
represents an employee, with attributes such as Employee ID, Full Name, Date of
Birth, Department, Position, and Salary. The EmployeeTree class provides the
following core functionalities:
 Insert: Adds a new employee to the tree while maintaining BST properties.
Duplicate Employee IDs are not allowed.
public void Insert(EmployeeNode newNode)
{
if (root == null)
{
root = newNode;
return;
}
EmployeeNode current = root;
EmployeeNode parent = null;
while (true)
{
parent = current;
if (newNode.EmployeeID < current.EmployeeID)
{
current = current.Left;
if (current == null)
{
parent.Left = newNode;
return;
}
}
else if (newNode.EmployeeID > current.EmployeeID)
{
current = current.Right;
if (current == null)
{
parent.Right = newNode;
return;
}
}
else
{
throw new ArgumentException($"An employee with ID
{newNode.EmployeeID} already exists.");
}
}
}

 Search: Retrieves a specific employee node based on Employee ID.


public EmployeeNode Search(int employeeID)
{
EmployeeNode current = root;
while (current != null)
{
if (current.EmployeeID == employeeID)
return current;
else if (employeeID < current.EmployeeID)
current = current.Left;
else
current = current.Right;
}
return null;
}

 Delete: Removes an employee node and adjusts the tree structure accordingly.
public void Delete(int employeeId)
{
root = DeleteNode(root, employeeId);
}

private EmployeeNode DeleteNode(EmployeeNode node, int employeeId)


{
if (node == null)
return null;

if (employeeId < node.EmployeeID)


node.Left = DeleteNode(node.Left, employeeId);
else if (employeeId > node.EmployeeID)
node.Right = DeleteNode(node.Right, employeeId);
else
{
if (node.Left == null)
return node.Right;
else if (node.Right == null)
return node.Left;

node.EmployeeID = FindMinimum(node.Right).EmployeeID;
node.Right = DeleteNode(node.Right, node.EmployeeID);
}
return node;
}

private EmployeeNode FindMinimum(EmployeeNode node)


{
while (node.Left != null)
node = node.Left;
return node;
}

 In-Order Traversal: Traverses the tree in sorted order (by Employee ID) and
collects employee records.
public void InOrderTraversal(EmployeeNode node, Action<EmployeeNode>
action)
{
if (node == null) return;

InOrderTraversal(node.Left, action);
action(node);
InOrderTraversal(node.Right, action);
}

 Update: Modifies an existing employee's details based on their ID.


public void Update(EmployeeNode updatedNode)
{
EmployeeNode node = Search(updatedNode.EmployeeID);
if (node != null)
{
node.FullName = updatedNode.FullName;
node.DateOfBirth = updatedNode.DateOfBirth;
node.Department = updatedNode.Department;
node.Position = updatedNode.Position;
node.Salary = updatedNode.Salary;
}
else
{
throw new ArgumentException($"Employee with ID
{updatedNode.EmployeeID} not found.");
}
}

 Form Design and Functionality


FormAddEmployee
This form allows users to add new employees. Features include:
 Input validation for Employee ID, name, date of birth, department, position, and
salary.
 Error handling for invalid or duplicate inputs.
 Integration with the EmployeeTree instance for data storage.
private void btnSave_Click(object sender, EventArgs e)
{
if (!int.TryParse(txt_EmployeeID.Text, out int employeeID) ||
!decimal.TryParse(txtSalary.Text, out decimal salary))
{
MessageBox.Show("Invalid input.", "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}

EmployeeNode newEmployee = new EmployeeNode(employeeID,


txtFullName.Text,
new DateTime(int.Parse(txtBirthYear.Text), int.Parse(txtBirthMonth.Text),
int.Parse(txtBirthDay.Text)),
txtDepartment.Text, txtPosition.Text, salary);

try
{
employeeTree.Insert(newEmployee);
MessageBox.Show("Employee added successfully.", "Success",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
FormEditEmployee
This form enables users to update existing employee records. Features include:
 Pre-populated fields with the selected employee’s data.
 Input validation and checks for logical constraints (e.g., valid date of birth).
private void btnSave_Click(object sender, EventArgs e)
{
if (!ValidateInputs())
return;

try
{
DateTime dateOfBirth = new DateTime(
int.Parse(txtBirthYear.Text),
int.Parse(txtBirthMonth.Text),
int.Parse(txtBirthDay.Text)
);

if (dateOfBirth > DateTime.Now.AddYears(-16) || dateOfBirth <


DateTime.Now.AddYears(-100))
{
MessageBox.Show("Invalid date of birth. Employees must be at least 16
years old.",
"Validation Error", MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}

UpdatedEmployee = new EmployeeNode(


int.Parse(txtEmployeeID.Text),
txtFullName.Text,
dateOfBirth,
txtDepartment.Text,
txtPosition.Text,
decimal.Parse(txtSalary.Text)
);

DialogResult = DialogResult.OK;
Close();
}
catch (ArgumentOutOfRangeException)
{
MessageBox.Show("Invalid date. Please check the day, month, and year
fields.",
"Date Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

}
FormListEmployees
This form displays a list of all employees in a DataGridView control. Key
features:
 Edit and Delete buttons for each record.
 Dynamic updates to reflect changes in the tree.
 Employee data retrieval via in-order traversal of the BST.
private void DisplayEmployeeList()
{
dgvEmployeeList.Rows.Clear();
dgvEmployeeList.Columns.Clear();

dgvEmployeeList.Columns.Add("ID", "Employee ID");


dgvEmployeeList.Columns.Add("FullName", "Full Name");
dgvEmployeeList.Columns.Add("DateOfBirth", "Date of Birth");
dgvEmployeeList.Columns.Add("Department", "Department");
dgvEmployeeList.Columns.Add("Position", "Position");
dgvEmployeeList.Columns.Add("Salary", "Salary");
// Add Edit column
DataGridViewButtonColumn editColumn = new
DataGridViewButtonColumn();
editColumn.HeaderText = "Edit";
editColumn.Name = "Edit";
editColumn.Text = "Edit";
editColumn.UseColumnTextForButtonValue = true;
dgvEmployeeList.Columns.Add(editColumn);
// Add Delete column
DataGridViewButtonColumn deleteColumn = new
DataGridViewButtonColumn();
deleteColumn.HeaderText = "Delete";
deleteColumn.Name = "Delete";
deleteColumn.Text = "Delete";
deleteColumn.UseColumnTextForButtonValue = true;
dgvEmployeeList.Columns.Add(deleteColumn);
if (employeeTree != null)
{
var employees = employeeTree.GetAllEmployees();
foreach (var emp in employees)
{
dgvEmployeeList.Rows.Add(
emp.EmployeeID,
emp.FullName,
emp.DateOfBirth.ToShortDateString(),
emp.Department,
emp.Position,
emp.Salary.ToString("C"),
"Edit",
"Delete"
);
}
}
}
private void EditEmployee(int rowIndex)
{
int employeeId =
Convert.ToInt32(dgvEmployeeList.Rows[rowIndex].Cells["ID"].Value);
EmployeeNode employeeToEdit = employeeTree.Search(employeeId);

if (employeeToEdit != null)
{
// Open a new form for editing with the employee's details
FormEditEmployee editForm = new FormEditEmployee(employeeToEdit);
if (editForm.ShowDialog() == DialogResult.OK)
{
// Update the employee details in the tree
employeeTree.Update(editForm.UpdatedEmployee);
DisplayEmployeeList(); // Refresh the list
}
}
}
private void DeleteEmployee(int rowIndex)
{
int employeeId =
Convert.ToInt32(dgvEmployeeList.Rows[rowIndex].Cells["ID"].Value);

DialogResult result = MessageBox.Show("Are you sure you want to delete


this employee?",
"Confirm Delete", MessageBoxButtons.YesNo,
MessageBoxIcon.Warning);

if (result == DialogResult.Yes)
{
// Implement delete method in EmployeeTree
employeeTree.Delete(employeeId);
DisplayEmployeeList();
}
}
FormSearchEmp
This form facilitates searching for employees ID. Features include:
 Case-insensitive search.
 Display of results in a DataGridView control.
private void btnSearch_Click(object sender, EventArgs e)
{
if (!int.TryParse(txtSearch.Text.Trim(), out int searchId))
{
MessageBox.Show("Please enter a valid Employee ID.", "Search Error",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}

EmployeeNode result = employeeTree.Search(searchId);

if (result != null)
{
DisplaySearchResults(new List<EmployeeNode> { result });
}
else
{
MessageBox.Show("No employee found with that ID.", "Search Result",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}

Error Handling and Validation


Robust error handling mechanisms ensure system stability and data integrity. For
example:
 Duplicate Employee IDs trigger an exception with an appropriate error
message.
 Invalid input formats (e.g., non-numeric Employee IDs) are caught and reported
to the user.
Logical validations, such as age constraints for employees, prevent invalid data
entry.
3.1. Test cases and results
3.2.1. Circular Linked List

Test Cases

Test Case ID Description Input Data Expected Outcome

Insert new node at New node added


TC01 A random variable
Beginning successfully
Insert new node at New node added
TC02 A random variable
End successfully
Remove the first The node removed
TC03 A node exists
node successfully
Remove the last The node removed
TC04 A node exists
node successfully
“Found” if the node
Search for a node exists
TC05 A variable input
in the list “Not found” if the node
does not exist
The list displayed
TC06 Print the list The list exists
successfully
The list sorted
TC07 Sort the list The list exists
successfully

Results
Test
Case Screenshots of Actual Output
ID

TC01

TC02
TC03

TC04

TC05
TC06

TC07

3.2.2. Music Playlist Management

Test Cases

Test Case ID Description Input Data Expected Outcome

A new Song added


TC01 Add a new Song Valid data inputs
successfully
The Song removed
TC02 Remove a Song The song exists
successfully
The playlist displayed
TC03 Display Playlist The playlist exists
successfully
The next Song played
TC04 Play the next Song The song exists
successfully

TC05 Search Song by Valid data inputs “Found” if the Song


exists
Title “Not found” if the
Song does not exist
“Found” if the Song
Search Song by exists
TC06 Valid data inputs
Artist “Not found” if the
Song does not exist
Display Total The total duration
TC07 Valid data inputs
Playlist Duration displayed successfully
The playlist cleared
TC08 Clear Playlist The playlist exists
successfully

Results
Test
Case Screenshots of Actual Output
ID

TC01
TC02

TC03
TC04

TC05
TC06

TC07

TC08
3.2.3. Tetris Game

Test cases
Test Case
Description Input Expected Output
ID
Game initializes with
Test Start Game Click "START GAME"
TC01 empty grid, score at 0,
feature button
first piece appears
Test Exit Game Application closes
TC02 Click "EXIT" button
feature properly
Test block
Use arrow keys to move Block moves according to
TC03 movement and
and place a block input and settles at bottom
placement
Current block moves to
Test hold block Press 'H' with active
TC04 hold box, next block
feature block
becomes active
Line disappears, score
Test line clear Complete a horizontal
TC05 increases, blocks above
and scoring line
move down
"Game Over" screen
Stack blocks to top of
TC06 Test game over appears with final score
grid
and "Play Again" option
Click "Play Again"
Test restart Game resets with empty
TC07 button on game over
feature grid and score at 0
screen
Results
Test
Case Screenshots of Actual Output
ID

TC01

TC02
TC03

TC04
TC05

TC06
TC07

3.2.4. Employee Management System

Test Cases
Test Case
Description Input Data Expected Outcome
ID
Add new Employee added
TC01 Valid data inputs
employee successfully
Edit existing
TC02 Valid updates to fields Employee details updated
employee
Search
Employee with
TC03 Partial or full name input Error message displayed
name instead of
ID
Search
List of matching
TC04 employees by Employee ID input
employees
ID
Search with no Employee ID not in the
TC05 No results found message
results nodes
Delete Employee removed
TC06 Employee ID exists
employee successfully
Validate Non-numeric Employee
TC07 Error message displayed
numeric inputs ID
Validate age Date of Birth under 16
TC08 Error message displayed
limits years old

Results
Test
Case Screenshots of Actual Output
ID

TC01
TC02
TC03

TC04

TC05
TC06

TC07
TC08
C. CONCLUSION
1. EVALUATION
1.1. Strengths
Exercise 1: Music Playlist Management
 Clear User Interface: The program provides a simple text-based interface that is
easy to understand and navigate, offering clear instructions to the user.
 Core Features: It implements essential features such as adding and removing
songs, displaying the playlist, searching by title and artist, playing the next song, and
displaying the total playlist duration.
 Playlist Management: The program effectively manages the playlist, keeping
track of the songs and allowing for multiple interactions with the playlist.
 Sample Data: The AddSampleSongs method ensures that there are some initial
songs in the playlist for users to interact with when they first run the program,
enhancing the user experience.
 Modular Design: The program follows a modular design with separate classes
for Song, Playlist, and Program. This makes the code more organized and easier to
maintain or extend.
Exercise 2: Tetris Game
 Modular design: The use of OOP principles ensures high modularity, making
the code easy to maintain and extend.
 Random block generation: Apply the queue in Tetris Game throughout
BlockQueue class ensures diverse gameplay by preventing consecutive identical
blocks.
 Efficient grid management: The GameGrid class efficiently manages cell states
and clearing of rows.
 Game state handling: the GameState class encapsulates game logic, enhancing
code readability.
 Friendly and colorful user interface
 Having the features "ghost pieces" to preview block positions.
Exercise 3: Employee Management System
 Efficient data management: The use of a Binary Search Tree ensures fast and
efficient data operations.
 User-friendly interface: Intuitive forms and navigation simplify the use of the
system.
 Comprehensive validation: Robust input checks enhance data integrity and user
experience.
 Modular design: The system’s architecture allows easy addition of new features
and scalability.
1.2. Limitations
Exercise 1: Music Playlist Management
 No Song Persistence: Currently, the playlist and song data are lost once the
program is closed. There's no saving/loading mechanism to preserve the playlist data.
 Basic Search Functionality: The search functionality for titles and artists only
works with exact matches (case-insensitive), which may not be ideal for users who
want more flexible search options, such as partial matches or fuzzy search.
 Limited Playback Control: The PlayNext method only supports playing the next
song. There is no ability to play, pause, or stop songs, nor is there support for playback
control (such as repeat or shuffle).
 Fixed Song Duration: Song duration is entered manually as an integer
(seconds), but no validation is done to ensure the duration is realistic or positive. It
assumes users enter valid input.
 Lack of Error Handling: There is limited error handling in some parts of the
code, such as when adding or removing songs. It assumes the input is correct and
doesn’t handle edge cases like invalid input more robustly.
 No Playlist Sorting: The playlist is displayed in the order that songs are added,
with no functionality to sort the playlist (by title, artist, or duration).
Exercise 2: Tetris Game
Limited gameplay features: Advanced features like levels, increasing speed, or
sound effects are not implemented.
Exercise 3: Employee Management System
 Lack of data persistence: The current version does not include database or file
storage, causing data loss upon application closure.
 No user roles: All users have the same level of access, which could be a security
concern in a multi-user environment.
2. FUTURE DEVELOPMENT IDEAS
Exercise 1: Music Playlist Management
 Persistent Storage: Implement file handling (e.g., reading and writing to a text
file or using a database) to save and load the playlist data so users can retain their
playlist between sessions.
 Enhanced Search: Improve the search functionality to support partial matches
or fuzzy searches, allowing users to find songs even with small typographical errors.
 Playback Control: Add the ability to play, pause, skip, stop, shuffle, or repeat
songs. This would provide more control over the playback experience.
 Song Editing: Add the ability to edit the properties of an existing song, such as
updating the title, artist, or duration.
 Playlist Sorting: Introduce functionality to sort the playlist by title, artist, or
duration, allowing users to better organize their music.
 Multiple Playlists: Allow users to create and manage multiple playlists, not just
a single one, and provide options to switch between them.
 Graphical User Interface (GUI): Consider adding a GUI using technologies
such as WinForms or WPF for a more user-friendly experience compared to the
command-line interface.
 Track Song Play Count: Implement a feature to track the number of times a
song has been played, allowing users to see which songs are their favorites.
 Error Handling and Validation: Add more robust error handling for invalid
inputs (e.g., when adding a song with a negative duration or when a user tries to
remove a song that doesn’t exist).
 Integration with Music Streaming APIs: For future expansion, integrate the
program with popular music streaming APIs (e.g., Spotify or YouTube) to allow users
to fetch and manage real songs from the web.
Exercise 2: Tetris Game
 Advanced gameplay: Introduce levels with increasing difficulty Multiplayer
mode: Allow competitive or cooperative play between two users.
 Scoring enhancements: Implement bonus points for clearing multiple rows
simultaneously.
Exercise 3: Employee Management System
 Database integration: Implement backup and restore functionality to prevent
data loss by using SQL Server, MySQL, or SQLite.
 Role-based access control: Develop a login system with user roles like
Administrator, Manager, and Employee. Restrict access to sensitive features based on
user roles to enhance security.
REFERENCES
1. Geeks for Geeks – Introduction to C#, last updated in 23 Mar, 2023.
https://www.geeksforgeeks.org/introduction-to-c-sharp/
2. Geeks for Geeks – Introduction to Circular Linked List, last updated in 13 Sep,
2024.
https://www.geeksforgeeks.org/circular-linked-list/
3. Gaddis, T. (2021). Starting out with C#: From control structures through
objects (5th ed.). Pearson Education.
4. McMillan, M. E. (2010). Data structures and algorithms using C#. Cambridge
University Press.
5. Sedgewick, R., & Wayne, K. (2011). Algorithms (4th ed.). Addison-Wesley.
6. Zaharia, M. (2019). Hands-on data structures and algorithms with C#: Level up
your coding skills and solve real-world programming problems with C#. Packt
Publishing.
7. Microsoft. (n.d.). Event-driven programming overview. Microsoft Docs.
Retrieved from https://learn.microsoft.com/en-us/
ROLES AND CONTRIBUTIONS
LIST OF MEMBERS
SEMESTER II ACADEMIC CALENDAR 2024-2025
Group 06 - DASA230179E_02FIE
Student Contribution
Student name Assignment Grade
ID (%)
Implement exercise 1.
23110004 Võ Nguyễn Ngọc Bích 100
Create report of project.

Implement exercise 2, 3.
23110019 Huỳnh Gia Hân 100
Create report of project.

Note:
- (%) = 100%: the percentage of contribution of each member

Lecturer's comments

Ho Chi Minh City, December …. 2024


Lecturer’s signature
(Sign and print name)

You might also like