Did you know? Programmers convert coffee to code.

If you like my articles, sponsor me a coffee.

At the other end of the link I post some results of my other hobbies, like playing bass. It is worth checking it out ;)

Let’s get started with Crystal

I was thinking about how to start my introduction to the Crystal programming language. There are different paths I could choose from, like introducing the type system, installation, conditionals…

But I thought it is the best to start with a simple example: Guess the Number!

About the game

You already know this game: in our case the application thinks of a number between 1 and 100 (both inclusive) and you have 7 guesses to find out this specific numbers by guessing. If your guess is wrong, the application tells you if your guess was lower or higher than the number to find out.

A bit more difficult (or advanced) version is to find a number between 1 and 1000 (both inclusive) and you have 10 guesses.

This means, this simple example contains the following tasks you have to implement:

  • generate a random number between 1 and 100 (or 1 and 1000)
  • get input from user
  • convert the user input to a number
  • compare the generated number with the user input
  • notify the user if the guess is lower, higher, or same than the secret number (e.g. print something to the console)
  • end the game if the user needs more than 7 (or 10) turns to guess the right number

Implementation

Without much talking, here is my sample solution:

secret_number = rand(1..101)
guesses_left = 7

p "Guess the number between 1 and 100!"

loop do
  while (num = gets) && (!num || !num.to_i? || !(1 <= num.to_i <= 100))
    p "enter a valid number between 1 and 100"
  end
  if !num || !num.to_i?
    break
  end
  num = num.to_i
  if num == secret_number
    p "Congratulations! You've guessed my secret number!"
    break
  elsif num < secret_number
    p "My secret number is greater..."
  else
    p "My secret number is lower..."
  end

  if (guesses_left -= 1) == 0
    p "You couldn't guess my secret number! It was #{secret_number}."
    break
  else
    p "#{guesses_left} guesses left!"
  end
end

As you can see, the code is simple. It is my solution — without very deep knowledge of Crystal — yet.

But this works. Actually, that’s how I design this game every time I sit down to implement it in another programming language. Maybe my design has flaws and that’s why I always end up with a solution like this?

Anyhow, there’s always more which can be tweaked to make the code more compact, readable, easier. Feel free to adjust this solution to your liking.

Walls I’ve faced

Because this is a new language, I faced some walls.

For example, Ruby has a between? method which checks if a given number is between two numbers — inclusive the second number.

4.between?(1, 100) # returns true
1000.between?(1, 100) # returns false

But Crystal doesn’t have this method. I was thinking how I can make the code better. The solution you see above comes from the Community — I asked a question at Stack Overflow to see if my approach was OK with the coding style or not.

struct Number
  def between?(a, b)
    self <=> a >= 0 && self <=> b <= 0
  end
end

As you can see, I use above the powerful option of Crystal: extending objects. Even though Number is a structure of the core language, you can extend it with your custom methods.

The <=> operator is the standard Crystal comparison operator which you may know from Java’s Copmarable.compareTo: it returns 0 if the two objects are equal, a negative number if this object (denoted with self) is less than the other object and a positive number if this object is greater than the other.

I use the standard comparator because I don’t want to mess around writing something custom — all this to maintain compatibility among all the numbers. Maybe someone creates an own version of Number (extends Number) and it doesn’t work as a simple number (perhaps it is in the realm of complex numbers) and my custom comparison won’t fit.

Always keep yourself to the standard comparison implementation to avoid unexpected problems!

GHajba

Conclusion and next steps

That’s it. I’ve shown how to create a simple game easily using Crystal.

We dig into one of the powerful functionalities of this language: extending already available structures if the functionality is not available. This enables you to have a more readable code — and you can hide complicated logic in the depths of the source code structure.

Next up is that we’ll look at how this code is compiled to a binary format on different operating systems, then we’ll create another code which we will use to measure performance improvements.

Stay tuned!

Share the knowledge!
GHajba
 

Senior developer, consultant, author, mentor, apprentice. I love to share my knowledge and insights what I achieve through my daily work which is not trivial -- at least not for me.

Click Here to Leave a Comment Below 0 comments
>
%d bloggers like this: