Flutter & Dart Coding Challenge #2 - Palindrome
Gain a greater understand of Dart and Flutter with this coding challenge.
Dart Palindrome Challenge
Are you ready to challenge yourself once more? We're back with the second edition of our Dart coding challenge, and this one's going to be a little trickier than the first. But don't worry, if you aced the first one, you'll find this a breeze!
This time around there’s a little more fun in the mix. We want you to enter a sequence of letters, numbers, or both, and then programmatically determine if the characters are a palindrome . Sound intriguing? We thought so too!
So what are you waiting for? Get your thinking cap on and let's see if you have what it takes to crack this one!
Below are the application specifications. Read them over and then try to build the application on your own. If you find yourself stuck, several hints are provided below. Two solutions to this problem are available if you are unable to solve it on your own, or have already solved it and want to see my solution!
Project Specifications
Use the Dart Create function to create this project.
Asks the user, through the command-line terminal, to enter a single sequence of numbers or letters. It can be random or a word.
No spaces or special characters are allowed.
There must be more than 6 characters and less than 20.
Then, using any coding method that you see fit, check and see if the characters are a palindrome. As a reminder a palindrome is a word or sequence of characters that is the same backwards and forwards.
Display back to the user whether or not their number is a palindrome.
If the user inputs a number with less than 6 digits prompt them again with a custom message.
If the user inputs a number with less than 50 digits prompt them again with another custom error message.
If the user enters a non valid character alert them and ask for input again.
Use individual functions where appropriate.
Write tests where appropriate!
You’ve got this! Get to work and solve the challenge!
Hints
Only use these if you are completely stuck!
Dart has a library called dart:io. Try importing it and looking at functions called stdin.readLineSync() and stdout.write().
The do - while loop can be a great way to re-execute prompts for input until the proper criteria are met.
The for or forEach loop might be a wonderful way to traverse through a string. Remember, you can access each letter in a string by using brackets, as if were a List or array. Example String[1] would be the second letter (remember the first is zero). There are also other ways to do this as showcased in solution #2 last week.
Bonus fun: Is there a way you could use a while loop to only look at half of the String to conclude whether this is a palindrome or not?
Solution #1
We used “dart create” to initialize this project, so take note of the project structure:
dart create card_coding_challenges_2_palindrome
Name your version however you deem fit.
This creates a file and folder structure that contains folders called /bin, /lib and /test.
In a default Dart project, the /bin
directory is where you can place executable scripts that can be run directly from the command line. The /lib
directory is where you can store the Dart source code files that will be used to build your application or package. The /test
directory is where you can place your test files, which are used to test your code and ensure that it works as expected. These directories are essential for organizing your code and making it more maintainable.
/bin file
import 'package:dart_coding_challenges_2_palindrome/dart_coding_challenges_2_palindrome.dart' as challenge2;
/* Dart Coding Challenge #1
Create an Application that Does the following:
- Use the Dart Create function to create this project for you.
- Asks the user, through the command-line terminal, to enter a sequence of numbers or letters and store it as a string.
- There must be 3 or characters and less than 20 characters. No special characters or spaces are allowed!
- Then, using any coding method that you see fit, your job is to figure out if the string is palindrome or not
- Display back to the user if it is a palindrome or not using a print statement.
*/
void main(List<String> arguments) {
//Get a String that contains integers only from the command line.
String sequence = challenge2.getSequenceFromCommandLine();
//Reverse the order of the letters or numbers in the String.
String reverseSequence = challenge2.reverseOrderOfCharactersInString(sequence);
////Print whether or not it is a Palindrome! Sollution 1!
if (sequence == reverseSequence) {
print("This is a palindrome!");
} else {
print("This is not a palindrome!");
}
}
This is the main executable file. As with the last coding challenge the main function is quite simple. It creates a string called sequence which then calls our getSequenceFromCommandLine()
function, and then creates a second string called reverseSequence, which as you can imagine is the original sequence after being reversed by our reverseOrderOfCharactersInString function.
If the two are equal, we print a message indicating they are a palindrome, otherwise we print that it is not.
/lib file
import 'dart:io';
/* Get a number from the command line. We chose String
so that it is easier to manipulate and reverse! */
String getSequenceFromCommandLine() {
String sequence;
stdout.write("Enter a sequence of between 3-20 numbers or characters: ");
//Loop repeteadly to ask for user intput until our conditions are met.
do {
sequence = stdin.readLineSync()!;
if (sequence.length < 3) {
stdout.write("Error! Please enter 3 or more characters: ");
} else if (sequence.length > 20) {
stdout.write("Error! Please enter less than 20 characters: ");
} else if (!isAlphaNumeric(sequence)) {
stdout.write("Error! Please enter only numbers and letters: ");
}
} while (sequence.isEmpty || (sequence.length < 3 || sequence.length > 20) || !isAlphaNumeric(sequence));
return sequence;
}
//Check for numberic strings only.
bool isAlphaNumeric(String str) {
return RegExp(r'^[a-zA-Z0-9]+$').hasMatch(str);
}
//Let's take our String and reverse the order!
String reverseOrderOfCharactersInString(String str) {
String buffer = "";
//Loop through each character in the String 1 by 1 in reverse order.
for (int i = str.length; i > 0; i--) {
//Write the reversed String to our buffer.
buffer += str[i - 1];
}
return buffer;
}
The file which we find present in the lib folder contains our two primary functions getSequenceFromCommandLine()
and reverseOrderOfCharactersInString
along with a supporting function isAlphaNumeric.
Let’s look at these individually.
getSequenceFromCommandLine()
This function prompts the user to enter a sequence of characters or numbers via the command line and returns it as a string. It enforces certain conditions that the user input must meet: the sequence must contain between 3 to 20 characters or numbers, and cannot contain any special characters or spaces. If the user input fails to meet any of these conditions, the function will display an error message and prompt the user to input a correct sequence again. The function uses a do-while loop to keep asking for user input until all the conditions are met, and then returns the valid sequence as a string.
reverseOrderOfCharactersInString
This function takes a string as input and returns a new string with the characters in reverse order. It uses a for loop that iterates through each character in the original string, starting from the end, and adds them to a new string called buffer
one by one in reverse order. Once all the characters have been added to buffer
, it's returned as the reversed string.
isAlphaNumeric
This function checks whether a given string contains only alphanumeric characters or not. It returns a boolean value of true
if the string contains only letters or numbers, and false
otherwise.
The function uses a regular expression to check if the string matches the pattern ^[a-zA-Z0-9]+$
. Here, the caret ^
matches the start of the string, and the dollar sign $
matches the end of the string. The square brackets []
contain the range of characters allowed, in this case, the alphabets in lowercase a
to z
, uppercase A
to Z
, and numbers 0
to 9
. The +
sign means that the pattern should match one or more characters.
/test file
import 'package:dart_coding_challenges_2_palindrome/dart_coding_challenges_2_palindrome.dart';
import 'package:test/test.dart';
void main() {
test('isNumeric', () {
expect(isAlphaNumeric("asdfsdf"), true);
expect(isAlphaNumeric("12356456"), true);
expect(isAlphaNumeric("this has spaces"), false);
expect(isAlphaNumeric("12389719823~!"), false);
});
test('reverseNumber', () {
expect(reverseOrderOfCharactersInString("123"), "321");
expect(reverseOrderOfCharactersInString("123456789"), "987654321");
});
}
The test file for solution 1 has two simple tests. We are checking our isAlphaNumeric function against a series of expected outputs, as well as reverseNumber. We can use these tests to verify the quality of our application using the dart test
command.
Solution 2
In the video for this challenge I indicated something important: you can think of a palindrome as a sequence of characters folder in half. If we know the first half and the last half are identical, then can we potentially find a way to solve this problem that is more efficient than just comparing the entire string with itself? Of course we can, and that is exactly what solution 2 does.
I have added solution 2 into the same set of files as before so we can see how they work side-by-side.
/bin
import 'package:dart_coding_challenges_2_palindrome/dart_coding_challenges_2_palindrome.dart' as challenge2;
/* Dart Coding Challenge #1
Create an Application that Does the following:
- Use the Dart Create function to create this project for you.
- Asks the user, through the command-line terminal, to enter a sequence of numbers or letters and store it as a string.
- There must be 3 or characters and less than 20 characters. No special characters or spaces are allowed!
- Then, using any coding method that you see fit, your job is to figure out if the string is palindrome or not
- Display back to the user if it is a palindrome or not using a print statement.
*/
void main(List<String> arguments) {
//Get a String that contains integers only from the command line.
String sequence = challenge2.getSequenceFromCommandLine();
//Reverse the order of the letters or numbers in the String.
String reverseSequence = challenge2.reverseOrderOfCharactersInString(sequence);
////Print whether or not it is a Palindrome! Sollution 1!
if (sequence == reverseSequence) {
print("This is a palindrome!");
} else {
print("This is not a palindrome!");
}
//Print whether or not it is a Palindrome! Solution 2!
if (challenge2.isPalindrome(sequence)) {
print("This is a palindrome!");
} else {
print("This is not a palindrome!");
}
}
Not much has changed from solution 1 aside from the last if else control flow. This time notice we don’t compare our sequence with something else, but rather we pass our sequence into a new function called isPalindrome that will be located in our /lib file. Let’s take a look at that!
/lib file
import 'dart:io';
/* Get a number from the command line. We chose String
so that it is easier to manipulate and reverse! */
String getSequenceFromCommandLine() {
String sequence;
stdout.write("Enter a sequence of between 3-20 numbers or characters: ");
//Loop repeteadly to ask for user intput until our conditions are met.
do {
sequence = stdin.readLineSync()!;
if (sequence.length < 3) {
stdout.write("Error! Please enter 3 or more characters: ");
} else if (sequence.length > 20) {
stdout.write("Error! Please enter less than 20 characters: ");
} else if (!isAlphaNumeric(sequence)) {
stdout.write("Error! Please enter only numbers and letters: ");
}
} while (sequence.isEmpty || (sequence.length < 3 || sequence.length > 20) || !isAlphaNumeric(sequence));
return sequence;
}
//Check for numberic strings only.
bool isAlphaNumeric(String str) {
return RegExp(r'^[a-zA-Z0-9]+$').hasMatch(str);
}
//Let's take our String and reverse the order!
String reverseOrderOfCharactersInString(String str) {
String buffer = "";
//Loop through each character in the String 1 by 1 in reverse order.
for (int i = str.length; i > 0; i--) {
//Write the reversed String to our buffer.
buffer += str[i - 1];
}
return buffer;
}
//Solution 2 -- Function to check is Palindrome using only half the list!
bool isPalindrome(String str) {
// define length of string.
int length = str.length;
//Half the length.
int halfLength = (length / 2).floor();
int i = 0;
//Get half the string in reverse!
while (i < halfLength && str[i] == str[length - i - 1]) {
i++;
}
//Return true if each half is the same.
return i == halfLength;
}
The only thing new in this lib file is the final function called isPalindrome.
isPalindrome()
The function takes a string as an argument and first calculates the length of the string using str.length
. It then divides the length of the string by 2 and rounds it down to the nearest integer using the floor()
method to get the half-length of the string.
Next, the function sets an index i
to 0 and starts a while loop that iterates over the string until i
is less than halfLength
and the character at the i
th position is the same as the character at the length - i - 1
th position. This loop checks if the first half of the string is the same as the second half of the string in reverse order.
If the loop completes and all the characters in the first half of the string are the same as the characters in the second half of the string in reverse order, then the function returns true
, indicating that the string is a palindrome. Otherwise, it returns false
.
Then we add a few new tests:
/Tests file
import 'package:dart_coding_challenges_2_palindrome/dart_coding_challenges_2_palindrome.dart';
import 'package:test/test.dart';
void main() {
test('isNumeric', () {
expect(isAlphaNumeric("asdfsdf"), true);
expect(isAlphaNumeric("12356456"), true);
expect(isAlphaNumeric("this has spaces"), false);
expect(isAlphaNumeric("12389719823~!"), false);
});
test('isPalindrome', () {
expect(isPalindrome("1111111"), true);
expect(isPalindrome("poop"), true);
expect(isPalindrome("goop"), false);
});
test('reverseNumber', () {
expect(reverseOrderOfCharactersInString("123"), "321");
expect(reverseOrderOfCharactersInString("123456789"), "987654321");
});
}
Notice the new tests for “isPalindrome.” The tests are self explanatory but necessary so we can test both solutions with Dart test.
Final Thoughts
I hope you had some fun with this problem, and perhaps learned a thing or two. How did you solve the problem? I hope you will let us know in the comments as I am quite curious. Which solution did you prefer, #1 or #2, and why?