Avatar of AlKYala

AlKYala's solution

to Rail Fence Cipher in the Java Track

Published at Oct 06 2019 · 0 comments
Instructions
Test suite
Solution

Implement encoding and decoding for the rail fence cipher.

The Rail Fence cipher is a form of transposition cipher that gets its name from the way in which it's encoded. It was already used by the ancient Greeks.

In the Rail Fence cipher, the message is written downwards on successive "rails" of an imaginary fence, then moving up when we get to the bottom (like a zig-zag). Finally the message is then read off in rows.

For example, using three "rails" and the message "WE ARE DISCOVERED FLEE AT ONCE", the cipherer writes out:

W . . . E . . . C . . . R . . . L . . . T . . . E
. E . R . D . S . O . E . E . F . E . A . O . C .
. . A . . . I . . . V . . . D . . . E . . . N . .

Then reads off:

WECRLTEERDSOEEFEAOCAIVDEN

To decrypt a message you take the zig-zag shape and fill the ciphertext along the rows.

? . . . ? . . . ? . . . ? . . . ? . . . ? . . . ?
. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? .
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .

The first row has seven spots that can be filled with "WECRLTE".

W . . . E . . . C . . . R . . . L . . . T . . . E
. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? .
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .

Now the 2nd row takes "ERDSOEEFEAOC".

W . . . E . . . C . . . R . . . L . . . T . . . E
. E . R . D . S . O . E . E . F . E . A . O . C .
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .

Leaving "AIVDEN" for the last row.

W . . . E . . . C . . . R . . . L . . . T . . . E
. E . R . D . S . O . E . E . F . E . A . O . C .
. . A . . . I . . . V . . . D . . . E . . . N . .

If you now read along the zig-zag shape you can read the original message.

Setup

Go through the setup instructions for Java to install the necessary dependencies:

https://exercism.io/tracks/java/installation

Running the tests

You can run all the tests for an exercise by entering the following in your terminal:

$ gradle test

Use gradlew.bat if you're on Windows

In the test suites all tests but the first have been skipped.

Once you get a test passing, you can enable the next one by removing the @Ignore("Remove to run test") annotation.

Source

Wikipedia https://en.wikipedia.org/wiki/Transposition_cipher#Rail_Fence_cipher

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

RailFenceCipherTest.java

import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;

public class RailFenceCipherTest {

    private RailFenceCipher railFenceCipher;

    @Test
    public void encodeWithTwoRails() {
        railFenceCipher = new RailFenceCipher(2);
        Assert.assertEquals("XXXXXXXXXOOOOOOOOO",
            railFenceCipher.getEncryptedData("XOXOXOXOXOXOXOXOXO"));
    }

    @Ignore("Remove to run test")
    @Test
    public void encodeWithThreeRails() {
        railFenceCipher = new RailFenceCipher(3);
        Assert.assertEquals("WECRLTEERDSOEEFEAOCAIVDEN",
            railFenceCipher.getEncryptedData("WEAREDISCOVEREDFLEEATONCE"));
    }

    @Ignore("Remove to run test")
    @Test
    public void encodeWithEndingInTheMiddle() {
        railFenceCipher = new RailFenceCipher(4);
        Assert.assertEquals("ESXIEECSR",
            railFenceCipher.getEncryptedData("EXERCISES"));
    }

    @Ignore("Remove to run test")
    @Test
    public void decodeWithThreeRails() {
        railFenceCipher = new RailFenceCipher(3);
        Assert.assertEquals("THEDEVILISINTHEDETAILS",
            railFenceCipher.getDecryptedData("TEITELHDVLSNHDTISEIIEA"));
    }

    @Ignore("Remove to run test")
    @Test
    public void decodeWithFiveRails() {
        railFenceCipher = new RailFenceCipher(5);
        Assert.assertEquals("EXERCISMISAWESOME",
            railFenceCipher.getDecryptedData("EIEXMSMESAORIWSCE"));
    }

    @Ignore("Remove to run test")
    @Test
    public void decodeWithSixRails() {
        railFenceCipher = new RailFenceCipher(6);
        Assert.assertEquals("112358132134558914423337761098715972584418167651094617711286",
            railFenceCipher.getDecryptedData("133714114238148966225439541018335470986172518171757571896261"));
    }
}
import java.util.ArrayList;
import java.util.Arrays;
/*BIG REMINDER TO SELF: IF YOU KEEP A COOL HEAD, 
*YOU CAN SOLVE EXERCISES IN MUCH LESS THAN 
*IT WOULD TAKE YOU TO SOLVE WHEN STRESSED OUT
*/
public class RailFenceCipher {

	private int rails;
	
	
	public RailFenceCipher(int rails) {
		this.rails = rails;
	}
	
	public String getEncryptedData(String s) {
		/*ArrayList<String> StringRails = new ArrayList<String>(); //repräsentieren die Rails
		ArrayList<char []> charRails = new ArrayList<char []>();
		char[] sc = s.toCharArray();
		
		int rowLength = s.length() / rails;
		int index = 0;*/
		
		/*for(int i = 0; i < rails; i++) { //Reihen
			String row = "";
			for(int j = 0; j < rowLength; j++) { //einzelne Reihe
				row += sc[index];
				index++;
			}
			System.out.println(row); //Debug
			charRails.add(row.toCharArray());
		}*/
		
		/*if(index < s.length() - 1) {
			String row = "";
			while(index < s.length()) {
				index++;
				row += sc[index];
			}
			System.out.println(row); //Debug
			charRails.add(row.toCharArray());
		}*/
		
		/*ArrayList<char []> charRails = new ArrayList<char []>();
		
		char[][] table = new char[rails][];
		
		for(int i = 0; i < this.rails; i++) {
			char[] sc = s.toCharArray();
			System.out.printf("%s\n", Arrays.toString(sc));
			charRails.add(sc);
			table[i] = sc;
		}
		
		int spare = 0;
		
		for(int i = 0; i < s.length(); i++) {
			
			if(spare > rails) {
				spare = 0;
			}
			
			for(int j = 0; j < rails; j++) {
				if(j == spare && j % 2 == 0) {
					continue;
				}
				else if(j % 2 != 0 && i % 2 != 0) {
					continue;
				}
				charRails.get(j)[i] = '_';
			}
			
			spare++;
		}
		
		for(int i = 0; i < this.rails; i++) {
			System.out.println(charRails.get(i));
		}
		
		return null;*/
		
		char[][] table = new char[rails][s.length()];
		char[] sc = s.toCharArray();
		int j = 0;
		boolean increase = true;
		boolean decrease = false;
		
		
		for(int i = 0; i < s.length(); i++) {
			if(j >= rails) {
				j-=2;
				decrease = true;
				increase = false;
				i--;
				continue;
			}
			else if(j < 0) {
				increase = true;
				decrease = false;
				j+=2;
				i--;
				continue;
			}
			table[j][i] = sc[i];
			if(increase) {
				j++;
			}
			else if(decrease) {
				j--;
			}
		}
		
		String ret = "";
		for(int i = 0; i < table.length; i++) {
			System.out.printf("%s\n", Arrays.toString(table[i]));
			ret += normalizeCharArray(table[i]);
		}
		ret = ret.replaceAll(" ", "");
		//System.out.println(ret);
		return ret;
	}
	
	
	public char[][] buildTable(String s) { //WHO THE FUCK WOULD HAVE THOUGHT THIS TAKES SO MUCH FUCKING TIME WHEN IT WAS SO OBVIOUS TO BEGIN WITH
		char[][] table = new char[rails][s.length()];
		int j = 0;
		boolean increase = true;
		boolean decrease = false;
		
		
		for(int i = 0; i < s.length(); i++) {
			if(j >= rails) {
				j-=2;
				decrease = true;
				increase = false;
				i--;
				continue;
			}
			else if(j < 0) {
				increase = true;
				decrease = false;
				j+=2;
				i--;
				continue;
			}
			table[j][i] = '?';
			if(increase) {
				j++;
			}
			else if(decrease) {
				j--;
			}
		}
		
		for(int i = 0; i < table.length; i++) {
			//System.out.printf("%s\n", Arrays.toString(table[i]));
		}
		
		return table;
	}
	
	public char[][] buildDecryptionTable(String s) {
		char[][] table = this.buildTable(s);
		char[] sc = s.toCharArray();
		//entering chars into table
		
		int scIndex = 0; //for the words themselves
		
		for(int i = 0; i < table.length; i++) {
			for(int j = 0; j < table[i].length; j++) {
				if(table[i][j] == '?') {
					table[i][j] = sc[scIndex];
					scIndex++;
				}
			}
		}
		
		for(int i = 0; i < table.length; i++) {
			//System.out.printf("%s\n", Arrays.toString(table[i]));
		}
		
		return table;
		
	}
	
	public String getDecryptedData(String s) {
		char[][] table = this.buildDecryptionTable(s);
		
		int j = 0;
		boolean increase = true;
		boolean decrease = false;
		
		StringBuilder ret = new StringBuilder();
		
		/*for(int i = 0; i < table.length; i++) { //DEBUG LIKE ANYTHING ELSE THAT PRINTS
			System.out.printf("%s\n", Arrays.toString(table[i]));
		}*/
	
		for(int i = 0; i < s.length(); i++) {
			//System.out.println(i); //Debug
			if(j >= this.rails) {
				j-=2;
				decrease = true;
				increase = false;
				i--;
				continue;
			}
			else if(j < 0) {
				increase = true;
				decrease = false;
				j+=2;
				i--;
				continue;
			}
			ret.append(table[j][i]);
			if(increase) {
				j++;
			}
			else if(decrease) {
				j--;
			}
		}
		//System.out.println(ret);
		return ret.toString();
	}
	
	public String normalizeCharArray(char[] x) {
		String s = "";
		for(int i = 0; i < x.length; i++) {
			if(x[i] > 91 || x[i] < 64) {
				continue;
			}
			//System.out.println(x[i]);
			s += x[i];
		}
		return s;
	}
	
	
	/*public static void main(String[] args) {
		RailFenceCipher a = new RailFenceCipher(4);
		//a.getEncryptedData("EXERCISES");
		RailFenceCipher b = new RailFenceCipher(3);
		b.getDecryptedData("TEITELHDVLSNHDTISEIIEA");
	}*/
	
	/*AGAIN NOTE TO SELF: ALWAYS KEEP A CALM HEAD WHEN PROGRAMMING. 
	 * ELSE ITLL TAKE TO LONG OR YOU MAY END UP GOING IN CIRCLES. 
	 * DONT STRESS YOURSELF
	 */ 
	
}

Community comments

Find this solution interesting? Ask the author a question to learn more.

AlKYala's Reflection

Took me way too long. Basically because I was stressing out because of other things. Im glad it worked out.