Tuesday, June 23, 2015

Caesar Cipher Encryption and Decryption

Here's my blog post to end my hiatus. I decided to make a program that encrypts and decrypts text given in the form of a Caesar cipher. So I did just that in 43 lines of Python (the main portion in 27 lines). On Pastebin like usual.

alphabet = "abcdefghijklmnopqrstuvwxyz"
def encrypt(s, shift):
    news = ""
    for i in s:
        if i.lower() in alphabet:
            if i.upper() == i:
                c = alphabet[(alphabet.index(i.lower()) + shift) % len(alphabet)] 
                news = news + c.upper()
            else:
                c = alphabet[(alphabet.index(i) + shift) % len(alphabet)] 
                news = news + c
        else:
            news = news + i
    print(news)
def decrypt(s, shift):
    news = ""
    for i in s:
        if i.lower() in alphabet:
            if i.upper() == i:
                c = alphabet[(alphabet.index(i.lower()) - shift) % len(alphabet)] 
                news = news + c.upper()
            else:
                c = alphabet[(alphabet.index(i) - shift) % len(alphabet)] 
                news = news + c
        else:
            news = news + i
    print(news)
def gettodo():
    a = input("What do you want to do? E for encrypt, D for decrypt: ").lower()
    if a[0] == "e":
        b = input("Enter a plaintext: ")
        c = int(input("Enter a shift: "))
        encrypt(b, c)
        gettodo()
    elif a[0] == "d":
        b = input("Enter a ciphertext: ")
        c = int(input("Enter a shift: "))
        decrypt(b, c)
        gettodo()
    else:
        print("Invalid input.")
        gettodo()
gettodo()

Wednesday, June 17, 2015

Left-Shifting Zeroes in Java

    So I've heard a tricky question that Google apparently likes to ask during interviews:

    You have been given an array of integers that may or may not contain zeroes. Your task is to sort the array in-place such that all the zeroes are at the last digits of the array, and all non-zero integers are at the beginning of the array in the order that they were initially given.
For instance,
sort([0, 0, 0]) //the new array is [0, 0, 0]
sort([1, 0, 1, 0, 0, 1, 1, 0, 1, 0]) //the new array is [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
sort([0, 0, 7]) //the new array is [7, 0, 0], i.e. a much less interesting secret agent
sort([8, 6, 7]) //the new array is [8, 6, 7]
sort([5, 3, 0, 9]) //the new array is [5, 3, 9, 0], you got the wrong number

    My code to solve it is at the bottom or on Pastebin as per usual.
    I thought my method was interesting: I just left-shifted everything over whenever a zero was found, which means that the complexity was O(n^2) if I know my complexity theory (which I very well may not).

    The most confusing part for me to code was the notallzeroes part of it. So I had to hard-code in the notallzeroes variable, which tracks the array to see if we can break: if we've reached the end of the non-zero part of the sorted array, we can break automatically. But it also allows us to see if there are any indices we need to go over again so we can redo those. The issue I ran into without that bit is that if multiple zeroes are in a row, every other zero is skipped.
import java.util.*;
public class Main {
    static int[] array = new int[20];
    public static void sort(int[] a) {
        for (int i = 0; i < a.length; i++) {
            if (a[i] == 0) {
                boolean notallzeroes = false;
                for (int j = i; j < a.length - 1; j++ ){
                    a[j] = a[j+1];
                    if (a[j] != 0) {
                        notallzeroes = true;
                    }
                }
                a[a.length-1] = 0;
                if (notallzeroes) {
                    i--;
                }
                else {
                    break;
                }
            }
        }
    }
    public static void main(String[] args) {
        System.out.println("STARTED!");
        for (int j = 0; j < 20; j++) {
            Random r = new Random();
            for (int i = 0; i < array.length; i++) {
                array[i] = r.nextInt(100);
            }
            for (int i = 0; i < j; i++) {
                array[r.nextInt(20)] = 0;
            }
          System.out.println("BEFORE: " + Arrays.toString(array));
        sort(array);
        System.out.println("AFTER: " + Arrays.toString(array));
        }
    }
}

Monday, June 15, 2015

Project 3: Age in Seconds (and bonus 1 billion seconds and extension)

I've wanted to try out using Python's datetime library for a while. However, as xkcd has joked about, date / time libraries are notoriously complex, so I've been putting it off for a long time.

But here's a simple program I decided to write to test it anyway, since it's Project 3 in the 100 projects list.

from datetime import *
birthday = raw_input("Input your birthday in the form (0001-2015)-(01-12)-(01-31), ex. 2015-06-15:    ")
true_birthday = datetime.strptime(birthday, "%Y-%m-%d")
delta = datetime.now() - true_birthday
print("You're currently " + str(delta.total_seconds()) + " seconds old.")
base = int(raw_input("Enter your favorite number:      "))
i = 1
while base**i < 5000000000:
    tenpowerseconds = true_birthday + timedelta(seconds=base**i)
    strtps = tenpowerseconds.strftime("%a, %Y-%m-%d, %I:%m:%S %p")
    if tenpowerseconds < datetime.now():
        print("You turned {0} (or {1} to the power of {2}) seconds old on: {3}".format(base**i,base,i,strtps))
    else:
        print("You will turn {0} (or {1} to the power of {2}) seconds old on: {3}".format(base**i,base,i,strtps))
    i += 1

It's pretty straightforward, you put in a date as follows:
Input your birthday in the form (0001-2015)-(01-12)-(01-31), ex. 2015-06-15:    1997-06-02
You're currently 569181542.709 seconds old.
Enter your favorite number:      21       
You turned 21 (or 21 to the power of 1) seconds old on: Mon, 1997-06-02, 12:06:21 AM      
You turned 441 (or 21 to the power of 2) seconds old on: Mon, 1997-06-02, 12:06:21 AM    
You turned 9261 (or 21 to the power of 3) seconds old on: Mon, 1997-06-02, 02:06:21 AM  
You turned 194481 (or 21 to the power of 4) seconds old on: Wed, 1997-06-04, 06:06:21 AM
You turned 4084101 (or 21 to the power of 5) seconds old on: Sat, 1997-07-19, 06:07:21 AM
You turned 85766121 (or 21 to the power of 6) seconds old on: Sat, 2000-02-19, 03:02:21 PM
You will turn 1801088541 (or 21 to the power of 7) seconds old on: Sun, 2054-06-28, 10:06:21 PM

Pretty fun thing to do just for fun. It's on Pastebin as per usual for easier viewing.

Saturday, June 13, 2015

Project 2 Part 2: Higher / Lower Bot

So I was wondering if I misunderstood the purpose of the project - was it supposed to be an interface for the game or a bot for the game? Well, I decided I'd just do a bot to play the game. And here it is.


import random
def getmax():
    try:
        return int(input("What's the highest number to play? "))
    except SyntaxError:
        print("Enter a integer.")
        return getmax()
min = 1
max = getmax()
truemax = max
turns = 0
toguess = random.randint(min, max)
done = False
while not done:
    turns += 1
    guess = (min + max) / 2
    range = max - min
    print("Guessed " + str(guess))
    if guess == toguess:
        print("I did it!")
        print("Guessed a number from 0 to " + str(truemax) + " in " + str(turns) + " turns.")
        done = True
    elif guess < toguess:
        print("Too low.")
        min += range / 2
    else:
        print("Too high.")
        max -= range / 2
A pastebin of the code is here.
The coolest part to me is how fast it is. It was able to guess with a range from 1 to 10 billion (10 to the power of 10) in 32 turns and with a range from 1 to 10 septillion in 83 turns. This makes sense, since my implementation is essentially a binary tree with 34 levels (since log2 of 10 billion is 33.2.)

This got me curious just how many iterations my solution would take to guess a number, on average. Some numbers are guessed faster than others. Instead of wasting a bunch of my CPU on Cloud9, though, I decided to calculate it by hand.

From guessing a number between one and ten, here's a tree representation of what my solution would do:

                     5
       3                      8
   2      4               7      9
1                     6             10

So, in the case where we're guessing a number between 1 and 10, if a number is picked at random, it'll take (on average) (1(1) + 2(2) + 3(4) + 4(3)) / 10 = 2.9 turns to be guessed.

Using some modified code to loop from 1 to 100, I got an average of 5.9 turns for a number to be guessed.

Going from 1 to 1000, it took 9.1 turns,

In general, it seems like the average number of iterations to guess a number from 1 to n is less than or equal to:

0.92 * log (base 2) (n) A pastebin of the code is here.
The coolest part to me is how fast it is. It was able to guess with a range from 1 to 10 billion (10 to the power of 10) in 32 turns and with a range from 1 to 10 septillion in 83 turns. This makes sense, since my implementation is essentially a binary tree with 34 levels (since log2 of 10 billion is 33.2.)

This got me curious just how many iterations my solution would take to guess a number, on average. Some numbers are guessed faster than others. Instead of wasting a bunch of my CPU on Cloud9, though, I decided to calculate it by hand.

From guessing a number between one and ten, here's a tree representation of what my solution would do:

                     5
       3                      8
   2      4               7      9
1                     6             10

So, in the case where we're guessing a number between 1 and 10, if a number is picked at random, it'll take (on average) (1(1) + 2(2) + 3(4) + 4(3)) / 10 = 2.9 turns to be guessed.

Using some modified code to loop from 1 to 100, I got an average of 5.9 turns for a number to be guessed.

Going from 1 to 1000, it took 9.1 turns,

In general, it seems like the average number of iterations to guess a number from 1 to n is less than or equal to:

0.92 * log (base 2) (n)

Thursday, June 11, 2015

Project 2 of the 100 Projects: Higher or Lower (in Python)

I was inspired by a post on Liquidthink.net about what the author terms the 100 projects challenge, and I decided that I'll try to do as many as I can too, also in Python.

So without further ado, a quick and (hopefully) clean implementation of Higher or Lower in Python. It's only 29 lines, which is an amount I'm rather pleased with.



import random
toguess = 0
def getmax():
    return int(input("Enter the maximum number to guess: "))
def setnum():
    return random.randint(1, getmax())
def guessnum():
    try:
        guess = int(input("Enter a guess: "))
    except SyntaxError:
         print("That's not a number. Try again.")
          return guessnum()
    return guess
def mainloop():
     toguess = setnum()
     currguess = guessnum()
     count = 1
     while currguess != toguess:
          count += 1
          if currguess < toguess:
               print("Too low.")
          else:
               print("Too high.")
          currguess = guessnum()
     toprint = "You won in {0} turns! Try again? ".format(count)
     print(toprint)
     x = raw_input("")[0]
     if x == "y" or x == "Y":
          mainloop()
mainloop()
It's on Pastebin for easier reading here and I put it on a Gist a couple minutes ago.
I'm rather proud of the way in which I handled the main loop (aptly titled mainloop()) without being excessively verbose and making use of return statements in a pretty efficient manner.