Skip to content

Instantly share code, notes, and snippets.

@hovsater
Created October 2, 2012 12:09
Show Gist options
  • Save hovsater/3818527 to your computer and use it in GitHub Desktop.
Save hovsater/3818527 to your computer and use it in GitHub Desktop.
Problem Solving Challenge #1

Problem Solving Challenge #1

Problem solving challenges are fun. They make use of one's problem solving skills and stimulate the programmer's need to challenge themselves.

Here we go

These 1151159511610110199114 numbers represent a word.

  • The word may only contain a-zA-Z_
  • The word is of size 8.

In this particular case the secret word was s_ecrets.

Write two functionsthat can encrypt an arbitrary string and return a string of numbers such as the one above. The program should also be able to take a string of numbers and return the original word.

Happy hacking!

@Skalman
Copy link

Skalman commented Oct 2, 2012

115 115 95 116 101 101 99 114 converted to ASCII chars is ss_teecr which happens to be an anagram for secrets_.

@hovsater
Copy link
Author

hovsater commented Oct 2, 2012

Impressive. Try solving it by writing a program for it as well. In your submission one of the characters should be replaced.

@Skalman
Copy link

Skalman commented Oct 2, 2012

Alright. Here's an implementation in JavaScript. Not sure which character should be replaced. My program gives the same result.

function solve(input) {
    var i, ch,
        output = "";
    input = input.split("");

    function getchar(number) {
        var char = String.fromCharCode(number);
        if (("A" <= char && char <= "Z") || ("a" <= char && char <= "z") || char === "_") {
            return char;
        }
    }

    for (i = 0; i < input.length; i++) {
        ch = getchar(input[i] + input[i+1]);
        if (ch) {
            output += ch;
            i++;
        } else {
            output += getchar(input[i] + input[i+1] + input[i+2]);
            i += 2;
        }
    }
    return output;
}

console.log(solve("1151159511610110199114")); // gives `ss_teecr`

@hovsater
Copy link
Author

hovsater commented Oct 2, 2012

@Skalman, nice. I was not completely clear about the implementation so I've updated the description above. I've added the solution to my example.

@bil-bas
Copy link

bil-bas commented Oct 2, 2012

Perhaps a little over-engineered, but I think a complete and robust solution:

module Encoder
  class << self 
    # Create a mapping of encoded string back to characters { "115" => "s" }  
    ASCII_TO_CHAR = {}
    chars = ("A".."Z").to_a + ("a".."z").to_a + ["_"]
    chars.each {|c| ASCII_TO_CHAR[c.bytes.to_a[0].to_s] = c }   

    # Encode a string - non-validating.
    def encode(string)
      riffle(string.each_byte.map {|b| b.to_s }).join
    end

    # Decode string - validating.
    def decode(string)
      pos = 0 # Current position in string.
      decoded = []

      # Code is 2 or 3 character strings. Take 2 characters and
      # see if it is valid, otherwise take another char and check that. 
      until pos >= string.length
        if (s = string[pos, 2]) and ASCII_TO_CHAR.has_key? s
          decoded << ASCII_TO_CHAR[s]
          pos += 2
        elsif (s << string[pos + 2]) and ASCII_TO_CHAR.has_key? s
          decoded << ASCII_TO_CHAR[s]
          pos += 3
        else
          raise "bad encoding at string position #{pos}"
        end
      end

      unriffle(decoded).join
    end

    protected
    # Take first and last element from array until array is empty,
    # to build a new array.
    def riffle(array)    
      # Split into two halves.
      first, second = array.each_slice(array.size / 2).to_a
      # Take from the start and end until empty.
      first.zip(second.reverse).inject([]) do |memo, (a, b)|
        memo.push a, b
      end     
    end

    protected
    # Reverse the effect of #riffle
    def unriffle(array)
      first, second = [], []
      array.each_slice(2).each do |a, b| 
        first << a
        second.unshift b
      end
      first + second
    end
  end
end

# Run with "rspec" rather than "ruby" on the command line to run the specs.
if defined? RSpec
  ENCODED = "1151159511610110199114"
  STRING = "s_ecrets" 

  describe Encoder do
    describe "encode" do
      it "should encode a string" do
        Encoder.encode(STRING).should eq ENCODED
      end    
    end

    describe "decode" do
      it "should decode a string" do
        Encoder.decode(ENCODED).should eq STRING
      end
    end

    describe "riffle" do
      it "should riffle an array" do
        Encoder.send(:riffle, [1, 3, 4, 2]).should eq [1, 2, 3, 4]
      end
    end

    describe "unriffle" do
      it "should unriffle an array" do
        Encoder.send(:unriffle, [1, 2, 3, 4]).should eq [1, 3, 4, 2]
      end
    end
  end
end

@bil-bas
Copy link

bil-bas commented Oct 2, 2012

Actually, still bored, so I improved my solution in a separate gist. Might want to delete my previous comment!
https://gist.github.com/3819927

@hovsater
Copy link
Author

hovsater commented Oct 2, 2012

@spooner impressive. Great solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment