Allergies in Coffeescript: Complete Solution & Deep Dive Guide

a close up of a computer screen with code on it

From Zero to Hero: Decoding Allergy Scores with CoffeeScript and Bitwise Magic

This guide provides a complete solution to the "Allergies" problem from the kodikra.com curriculum, using CoffeeScript. We'll explore how a single number can efficiently store multiple boolean states by leveraging the power of bitwise operations, a fundamental concept in computer science.

Have you ever looked at a compact piece of data, like a single integer, and wondered how it could possibly represent a complex set of options or flags? It feels like a magic trick. In systems programming, game development, and data transmission, efficiency is king. Sending an array of true/false values is bulky; sending one number is lightning fast. This is the exact challenge presented in the kodikra module: decoding an allergy score. You're given a number, and your task is to unpack it into a full list of allergies. It seems daunting, but the solution is elegant, powerful, and surprisingly simple once you understand the core principle: bitwise operations. This article will not only give you the code to solve the problem but will demystify the "magic" behind bitmasks, turning you into a more efficient and knowledgeable developer.


What is the Allergies Problem in the Kodikra Curriculum?

The premise of this challenge, found in the kodikra CoffeeScript 2 Learning Roadmap, is to model a person's allergies based on a single numerical score. An allergy test returns one integer, and this integer is a composite value that encodes all the substances the person is allergic to from a predefined list.

The system works by assigning a unique, power-of-two value to each potential allergen:

  • eggs: 1
  • peanuts: 2
  • shellfish: 4
  • strawberries: 8
  • tomatoes: 16
  • chocolate: 32
  • pollen: 64
  • cats: 128

The final allergy score is the sum of the values for every item a person is allergic to. For instance, if a person is allergic to peanuts (2) and strawberries (8), their total score would be 10. The goal is to write a CoffeeScript program that can take any score and perform two main functions:

  1. List all allergies: Given a score (e.g., 10), return an array of strings: ['peanuts', 'strawberries'].
  2. Check for a specific allergy: Given a score and a specific allergen (e.g., 'peanuts'), return true or false.

This problem is a classic introduction to the concept of bitmasks or bitfields, where each bit in a number's binary representation acts as a boolean flag (on/off).


Why Bitwise Operations are the Perfect Tool

At first glance, you might think about using division or modulo arithmetic to solve this. While possible, that approach is cumbersome and less intuitive than the method the problem is designed to teach: bitwise operations. This technique treats numbers not as decimal values but as sequences of binary digits (bits).

The key is that each allergen's value is a power of two. Let's look at their binary representations:

  • eggs (1) -> 00000001
  • peanuts (2) -> 00000010
  • shellfish (4) -> 00000100
  • strawberries (8) -> 00001000
  • ...and so on.

Notice a pattern? Each allergen corresponds to a single "on" bit in a unique position. When you sum these values, you are effectively setting multiple bits to "on" in the resulting score. For a score of 10 (peanuts + strawberries):


  00000010  (peanuts, value 2)
+ 00001000  (strawberries, value 8)
------------------
  00001010  (score 10)

The score 10 now has the 2's place bit and the 8's place bit turned on. To check if a person is allergic to a specific item, we can use the bitwise AND operator (&). This operator compares two numbers bit by bit. A bit in the result is set to 1 only if the corresponding bits in both operands are 1.

For example, to check for 'peanuts' (value 2) in a score of 10:


  00001010  (Score 10)
& 00000010  (Peanuts, value 2)
------------------
  00000010  (Result is 2, which is non-zero)

Since the result of the AND operation is the allergen's value itself (and not zero), we know the flag is set. This is incredibly fast and efficient at the hardware level.


How to Implement the Allergies Solution in CoffeeScript

CoffeeScript's clean syntax makes implementing this logic straightforward. We'll create an Allergies class that takes the score in its constructor and provides the required methods.

Step 1: Setting up the Allergen Data

First, we need a way to map the allergen names to their bitwise values. A constant object is perfect for this. We define it outside the class so it's a shared, immutable reference.


# Define the mapping of allergens to their bitmask values.
# This object is a constant reference for our class.
ALLERGENS =
  eggs: 1
  peanuts: 2
  shellfish: 4
  strawberries: 8
  tomatoes: 16
  chocolate: 32
  pollen: 64
  cats: 128

Step 2: Creating the Allergies Class

The class will store the score and contain the logic. The constructor simply accepts the score and assigns it to an instance variable @score.


class Allergies
  # The constructor is called when a new instance is created.
  # e.g., new Allergies(34)
  # It stores the allergy score for later use.
  constructor: (@score) ->

Step 3: The `list()` Method Logic

To get the list of all allergies, we need to iterate through our ALLERGENS object. For each allergen, we perform the bitwise AND operation between the person's score and the allergen's value. If the result is not zero, it means the person has that allergy, and we add it to our results array.

Here is an ASCII art diagram illustrating the flow of the list() method:

    ● Start with score
    │
    ▼
  ┌───────────────────┐
  │ Create empty list │
  │ `allergiesFound`  │
  └─────────┬─────────┘
            │
            ▼
  ┌───────────────────┐
  │ Loop each allergen│
  │ in `ALLERGENS`    │
  └─────────┬─────────┘
            │
            ▼
    ◆ Is (score & allergenValue) > 0 ?
   ╱           ╲
  Yes           No
  │              │
  ▼              ▼
┌──────────────┐  (Continue loop)
│ Add allergen │
│ to list      │
└──────────────┘
  │
  └──────────────┬───────────────┘
                 │
                 ▼
           (End of loop)
                 │
                 ▼
           ┌────────────┐
           │ Return the │
           │ list       │
           └────────────┘
                 │
                 ▼
               ● End

CoffeeScript's list comprehensions make this incredibly concise and readable.

Step 4: The `allergicTo()` Method Logic

This method is even simpler. It takes a single allergen string as an argument. It finds the corresponding value from our ALLERGENS map and performs the same bitwise AND check. The key difference is that it returns a boolean (true or false) directly.

This ASCII diagram shows how the bitwise AND operation works at a binary level to confirm an allergy:

  Check for 'chocolate' (32) in score 34:

    Score: 34  ⟶   00100010 (binary)
    Item:  32  ⟶   00100000 (binary)
                   │
                   ▼
  ┌──────────────────────────────────┐
  │ Perform Bitwise AND (&) Operation│
  └──────────────────────────────────┘
    00100010  (Score)
  & 00100000  (Chocolate)
  ──────────
    00100000  (Result is 32)
                   │
                   ▼
    ◆ Is Result > 0 ?
   ╱           ╲
  Yes           No
  │              │
  ▼              ▼
[ Allergic ]   [ Not Allergic ]
  (Return true)  (Return false)

The Complete CoffeeScript Solution

Putting it all together, here is the final, well-commented code. This solution is clean, efficient, and demonstrates idiomatic CoffeeScript.


# kodikra.com CoffeeScript Module: Allergies Solution
# This code uses bitwise operations to efficiently determine allergies from a score.

# Define the mapping of allergens to their bitmask values.
# Each value is a power of 2, representing a single bit.
ALLERGENS =
  eggs: 1
  peanuts: 2
  shellfish: 4
  strawberries: 8
  tomatoes: 16
  chocolate: 32
  pollen: 64
  cats: 128

# The main class to handle allergy calculations.
class Allergies
  # The constructor is called when a new instance is created.
  # e.g., `new Allergies(34)`
  # It stores the allergy score for later use by other methods.
  # The `@` symbol is CoffeeScript shorthand for `this.`.
  constructor: (@score) ->

  # `list()` returns an array of strings for all allergies the person has.
  list: ->
    # We use a list comprehension, a powerful CoffeeScript feature.
    # It iterates through each `allergen` and `value` in the ALLERGENS object.
    allergen for allergen, value of ALLERGENS when @allergicTo(allergen)

  # `allergicTo(item)` checks if the person is allergic to a specific item.
  # It returns true or false.
  allergicTo: (item) ->
    # Get the bitwise value for the given item (e.g., 'peanuts' -> 2)
    itemValue = ALLERGENS[item]

    # The core logic: perform a bitwise AND operation.
    # `&` is the bitwise AND operator.
    # If the bit corresponding to `itemValue` is set in `@score`,
    # the result will be `itemValue` itself (a non-zero number).
    # In JavaScript/CoffeeScript, non-zero numbers are "truthy".
    # We use `!!` to explicitly cast the result to a true boolean.
    !!(@score & itemValue)

# To make this class available for use in other files (e.g., in Node.js),
# we export it.
export default Allergies

Running the Code

To test this code, you would typically use a test runner. However, you can also run it manually. Assuming you have Node.js and the CoffeeScript compiler installed (npm install -g coffeescript), you could save the code as allergies.coffee and interact with it like this:

Create a test file, e.g., test.coffee:


import Allergies from './allergies.coffee'

# Example 1: Score of 34 (chocolate + peanuts)
allergies1 = new Allergies(34)
console.log "Score 34 list:", allergies1.list() # Should be ['peanuts', 'chocolate']
console.log "Score 34 allergic to peanuts?", allergies1.allergicTo('peanuts') # Should be true
console.log "Score 34 allergic to eggs?", allergies1.allergicTo('eggs') # Should be false

# Example 2: Score of 0 (no allergies)
allergies2 = new Allergies(0)
console.log "Score 0 list:", allergies2.list() # Should be []

# Example 3: Score of 255 (allergic to everything listed)
allergies3 = new Allergies(255)
console.log "Score 255 list:", allergies3.list() # Should be all 8 allergens

Then, run it from your terminal:


# Compile and run the test file
coffee test.coffee

Where are Bitwise Operations Used in the Real World?

The concept of bitmasks is not just an academic exercise; it's a cornerstone of high-performance computing. Understanding it opens doors to optimizing code in various domains.

  • File Permissions in Unix/Linux: The classic rwx (read, write, execute) permissions are a bitmask. Read is 4 (100), Write is 2 (010), and Execute is 1 (001). A permission of 7 (111) means you have all three. A permission of 5 (101) means read and execute.
  • Feature Flags: A single integer can control dozens of features in an application. A server can send one number to a client, and the client-side code uses bitwise checks to see which features should be enabled, saving bandwidth.
  • Graphics Programming: Colors are often represented as a single 32-bit integer, with 8 bits each for Alpha, Red, Green, and Blue (ARGB). Bitwise shifts and masks are used to extract or modify individual color channels.
  • Database Enums/Sets: Some database systems, like MySQL, have a SET data type that stores a selection of predefined string values as a bitmask internally for highly efficient storage and querying.

By mastering this technique, you are learning a language that computers speak at a much lower, more efficient level. Dive deeper into our CoffeeScript language guides to explore more advanced concepts.


Alternative Approaches and Trade-offs

While bitwise operations are the most efficient solution, it's useful to consider other ways to solve the problem to understand the trade-offs.

The Mathematical (Modulo/Division) Approach

You could solve this by repeatedly subtracting the largest possible allergen value from the score. 1. Start with the largest allergen value (128 for 'cats'). 2. If the score is greater than or equal to 128, the person is allergic to cats. Subtract 128 from the score. 3. Move to the next largest value (64 for 'pollen') and repeat. 4. Continue until the score is 0 or you've checked all allergens.

This works, but it involves more complex conditional logic and arithmetic operations, which are generally slower than a single bitwise AND. It's also less expressive of the underlying "flags" concept.

Pros and Cons of the Bitwise Approach

Pros Cons
Extreme Performance: Bitwise operations are single CPU instructions, making them incredibly fast. Limited Readability: For developers unfamiliar with them, code like score & 32 can be cryptic without context.
Memory Efficiency: A single integer can store up to 32 or 64 boolean flags (depending on the integer size), which is far more compact than an array or object. Fixed Set of Options: This approach is best for a known, fixed set of flags. Adding new options dynamically is difficult without changing the bit values.
Atomic Operations: Updating multiple flags can often be done in a single, atomic operation, which is useful in concurrent programming. Limited Number of Flags: You are limited by the number of bits in your integer type (usually 32 or 64). For hundreds of flags, this method is not suitable.

For the Allergies problem, the bitwise approach is unequivocally the superior choice as it aligns perfectly with the problem's constraints: a fixed set of boolean states that need to be stored and checked efficiently.


Frequently Asked Questions (FAQ)

What exactly is a bitmask or bitfield?
A bitmask is an integer used to store multiple boolean (on/off) states. Each bit in the integer's binary representation corresponds to a single state. By using bitwise operations like AND, OR, XOR, and NOT, you can set, clear, or query these individual states efficiently.
Why are the allergy values powers of two?
Using powers of two (1, 2, 4, 8, ...) ensures that each value corresponds to a single, unique bit being set to '1' in its binary representation (001, 010, 100, etc.). This isolation is crucial for the bitwise AND operation to work correctly, as it allows you to check one flag without interfering with others.
Is it possible to solve this without bitwise operations?
Yes, as discussed in the "Alternative Approaches" section, you could use a mathematical approach with subtraction and comparison. However, this is less efficient and doesn't teach the powerful bitmasking technique, which is the pedagogical goal of this exercise from the kodikra.com curriculum.
How does CoffeeScript's `&` operator differ from the `&&` operator?
This is a critical distinction. The single ampersand & is the Bitwise AND operator, which works on the binary representation of numbers. The double ampersand && is the Logical AND operator, which works with boolean (true/false) values and is used for control flow (e.g., if user.isLoggedIn && user.hasPermission).
Is CoffeeScript still a relevant language to learn?
CoffeeScript's popularity has waned since its peak, primarily because many of its best ideas (like arrow functions, classes, and destructuring) were officially adopted into the JavaScript (ES6/ES2015) standard. However, learning it provides excellent historical context for modern JS and it's still used in some legacy codebases and by developers who prefer its extremely concise syntax. The concepts learned, like bitwise operations, are language-agnostic and universally applicable.
What happens if the score is greater than the sum of all known allergens?
Our current implementation gracefully handles this. The extra bits in the score simply don't correspond to any known allergen in our ALLERGENS map. The code will only identify the allergies that match the bits we've defined, effectively ignoring any unknown flags.
How would I add a new allergen, like "dust mites"?
It's simple. You just add a new entry to the ALLERGENS object with the next power of two. Since the last item ('cats') is 128, the next would be 256. You would add dust_mites: 256 to the object. The rest of the code would work without any changes, which demonstrates the scalability of this design.

Conclusion

The Allergies problem is a fantastic vehicle for understanding and implementing bitwise operations, a fundamental technique for any serious programmer. By treating an integer as a collection of flags, we've created a solution in CoffeeScript that is not only correct but also exceptionally performant and memory-efficient. You've learned how to define a bitmask, use the bitwise AND operator (&) to query flags, and structure the logic within a clean, reusable class.

This pattern of using bitmasks for state management appears across all domains of software engineering. The next time you need to manage a fixed set of configuration options or states, remember the elegance of this approach. It's a powerful tool to have in your developer toolkit.

Disclaimer: The code and concepts in this article are based on the latest stable versions as of this writing, including CoffeeScript 2.x which compiles to modern ES6+ JavaScript. The principles of bitwise operations are timeless and apply across programming languages.

Ready to tackle the next challenge? Explore our comprehensive CoffeeScript 2 Learning Roadmap to continue building your skills.


Published by Kodikra — Your trusted Coffeescript learning resource.