Find how many connected groups of nodes in a given adjacency matrix - java

I have a list of lists, each list is a node and contains the edges to other nodes. e.g
[[1, 1, 0], [1, 1, 0], [0, 0, 1]]
The node has a 1 when it refers to its own position, as well as when it has an edge to another node, and a 0 when no edge exists.
This means that node 0 ([1, 1, 0]) is connected to node 1, and node 2 ([0,0,1]) is not connected to any other nodes. Therefore this list of lists can be thought of as an adjacency matrix:
1 1 0 <- node 0
1 1 0 <- node 1
0 0 1 <- node 2
Adding on to this, whether a node is connected with another is transitive, meaning that if node 1 is connected to node 2 and node 2 is connected to node 3, nodes 1 and 3 are also connected (by transitivity).
Taking all this into account, I want to be able to know how many connected groups there are given a matrix. What algorithm should I use, recursive DFS? Can someone provide any hints or pseudocode as to how this problem can be approached?

If the input matrix is guaranteed to describe transitive connectivity, it has a peculiar form that allows for an algorithm probing only a subset of the matrix elements. Here is an example implementation in Python:
def count_connected_groups(adj):
n = len(adj)
nodes_to_check = set([i for i in range(n)]) # [] not needed in python 3
count = 0
while nodes_to_check:
count += 1
node = nodes_to_check.pop()
adjacent = adj[node]
other_group_members = set()
for i in nodes_to_check:
if adjacent[i]:
other_group_members.add(i)
nodes_to_check -= other_group_members
return count
# your example:
adj_0 = [[1, 1, 0], [1, 1, 0], [0, 0, 1]]
# same with tuples and booleans:
adj_1 = ((True, True, False), (True, True, False), (False, False, True))
# another connectivity matrix:
adj_2 = ((1, 1, 1, 0, 0),
(1, 1, 1, 0, 0),
(1, 1, 1, 0, 0),
(0, 0, 0, 1, 1),
(0, 0, 0, 1, 1))
# and yet another:
adj_3 = ((1, 0, 1, 0, 0),
(0, 1, 0, 1, 0),
(1, 0, 1, 0, 0),
(0, 1, 0, 1, 0),
(0, 0, 0, 0, 1))
for a in adj_0, adj_1, adj_2, adj_3:
print(a)
print(count_connected_groups(a))
# [[1, 1, 0], [1, 1, 0], [0, 0, 1]]
# 2
# ((True, True, False), (True, True, False), (False, False, True))
# 2
# ((1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (1, 1, 1, 0, 0), (0, 0, 0, 1, 1), (0, 0, 0, 1, 1))
# 2
# ((1, 0, 1, 0, 0), (0, 1, 0, 1, 0), (1, 0, 1, 0, 0), (0, 1, 0, 1, 0), (0, 0, 0, 0, 1))
# 3
An optimized version of the same algorithm (less readable, but faster and more easily translatable into other languages) is the following:
def count_connected_groups(adj):
n = len(adj)
nodes_to_check = [i for i in range(n)] # [0, 1, ..., n-1]
count = 0
while n:
count += 1
n -= 1; node = nodes_to_check[n]
adjacent = adj[node]
i = 0
while i < n:
other_node = nodes_to_check[i]
if adjacent[other_node]:
n -= 1; nodes_to_check[i] = nodes_to_check[n]
else:
i += 1
return count

There are many approaches to do this. You can use DFS/BFS or disjoint sets to solve this problem. Here are some useful links:
https://www.geeksforgeeks.org/connected-components-in-an-undirected-graph/
https://www.geeksforgeeks.org/find-the-number-of-islands-set-2-using-disjoint-set/

Solution with Java syntax:
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ConnectedGroups {
public static void main(String[] args) {
List<String> adj0 = Arrays.asList("110", "110", "001");
List<String> adj1 = Arrays.asList("10000","01000","00100","00010","00001");
List<String> adj2 = Arrays.asList("11100","11100","11100","00011","00011");
List<String> adj3 = Arrays.asList("10100","01010","10100","01010","00001");
for (List<String> related : Arrays.asList(adj0, adj1, adj2, adj3)) {
System.out.println(related);
System.out.println(count_connected_groups(related));
}
}
private static int count_connected_groups(List<String> adj) {
int count=0;
int n = adj.size();
Stack<Integer> nodesToCheck = new Stack<>();
nodesToCheck.addAll(IntStream.range(0,n).boxed().collect(Collectors.toList()));
while (!nodesToCheck.isEmpty()) {
count++;
Integer node = nodesToCheck.pop();
String adjacent = adj.get(node);
Set<Integer> otherGroupMembers = new HashSet<>();
for (Integer i : nodesToCheck) {
if (adjacent.charAt(i) == '1') otherGroupMembers.add(i);
}
nodesToCheck.removeAll(otherGroupMembers);
}
return count;
}
}

Related

Certain 64bits causing error with my method Java

I have a method which finds the index of all the set bits in a binary string. It works fine except when the bits are set near the end. Here is the code.
public static void main(String[] args) throws InterruptedException {
indexSetBits(1101111100000000000000000000000000000000000000000000000000000000L);
}
public static ArrayList<Integer> indexSetBits(long bitboard) {
ArrayList<Integer> indices = new ArrayList<>();
int count = 0;
while (bitboard > 0L) {
if ((bitboard & 1L) == 1L) {
indices.add(count);
}
bitboard >>= 1;
count++;
}
return indices;
}
For some reason, when I pass in that 64 bit number as seen in my code, it gives the error: " Long number too large." Though i am sure what i am passing in is a 64 bit number. Is there any way to solve this?
Edit: It was pointed out that I was forgetting the "0b". Whoops!
Now that I remembered that, how would i make sure a method that returns a long, returns it in binary format, in other words how would i pass in a long without explicitly saying "0b".
For example I have this method which returns all the attack bits of a king as a long, and the logic with the bit mainuplation is fine within the actual method.
public long[] calculateKingMoves(int square, long ownSideBitboard,long enemySide, long allPieces){
/*
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 2, 3, 0, 0]
[0, 0, 0, 8, x, 4, 0, 0]
[0, 0, 0, 7, 6, 5, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
*/
//8 possible moves for a king from a given position, unless on a border, under check, or attempting to move into a piece that is
// under the watch of another piece.
long kingBitBoard =1L<< square;
long kingAFile = kingBitBoard & Lookups.fileTables[0];
long kingHFile = kingBitBoard & Lookups.fileTables[Lookups.fileTables.length-2];
long move1 = kingAFile <<7;
long move2 = kingBitBoard <<8;
long move3 = kingHFile <<9;
long move4 = kingHFile <<1;
long move5 = kingHFile >> 7;
long move6 = kingBitBoard >>8;
long move7 = kingAFile >>9;
long move8 = kingAFile >>1;
long kingPsuedos = move1 | move2| move3| move4| move5| move6| move7| move8;
long kingMoves = kingPsuedos & ~allPieces;
long kingAttacks = kingPsuedos & enemySide;
return new long[]{kingMoves,kingAttacks};
}
How would i make sure the two longs returned were in binary format? Instead of just normal longs?

Java Linear Regression

I need to find the best fitting regression line for a set of points.
For example for this matrix:
int b [][] = { { 3, 1, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 2, 3, 1, 0, 1, 0, 0, 0 },
{ 0, 1, 2, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 3, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 3, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 2, 3, 1 },
{ 0, 0, 0, 0, 0, 1, 1, 1, 2 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1 } };
Every number represents the amount of data points (weight I suppose) at that location (where rows are the X axis and Columns are for the Y).
I have attempted to use the SimpleRegression class from the apache mathematics library and am having some issues.
First, it doesn't appear to support weights. Second I believe that I'm doing something wrong, even for a matrix that is nothing but 1's on the main diagonal the slope/intercept results make no sense.
public static void main(String[] args) {
double a[][] = new double[9][9];
for (int i = 0; i < 9; i++)
a[i][i] = 1;
SimpleRegression r = new SimpleRegression(true);
r.addData(a);
System.out.println("Slope = " + r.getSlope());
System.out.println("Intercept = " + r.getIntercept());
}
This gives me results that are incorrect. I would assume that this matrix represents the function f(x) = x yet the slope I'm getting is -0.12499..
Could anyone point me at what I'm doing wrong?
I have a feeling I'm not only misusing the code but also the mathematics.
As the comments say, addData() expects a 2xN matrix of x y positions or individual x y positions. The following example returns a slope of 1 for a diagonal matrix as expected:
public static void main(String[] args) {
double a[][] = new double[9][9];
for (int i = 0; i < 9; i++)
a[i][i] = 1;
SimpleRegression r = new SimpleRegression(true);
addData(r, a);
System.out.println("Slope = " + r.getSlope());
System.out.println("Intercept = " + r.getIntercept());
}
public static void addData(SimpleRegression r, double[][] data) {
for(int x=0; x<data.length; x++) {
for(int y=0; y<data[0].length; y++) {
for(int i=0; i<data[x][y]; i++) {
r.addData(x, y);
}
}
}
}
The example assumes that index 0 corresponds to a position of 0, index 1 corresponds to a position of 1 and so on. If this is not the case you need to add a function to transform index to position.

MultipleSelectionModel: which list change events to expect from selectedIndices?

... in particular when modifying the underlying items?
Below is a quick example that selects a range and adds an item above the selection for TableView and ListView. The selectedIndices before/after adding:
indices before modification: [2, 3]
indices after modification: [3, 4]
Expected options:
a single wasReplaced for the whole range
a wasRemoved for the "2" and a wasAdded for the "4"
??
Actual:
table's selection fires two events, each with a single wasAdded
list's selection fires a wasPermutated (that's nuts, or what am I missing?)
Output (jdk8u40b12):
Change #0 on TableView indices
list = [3]
Change event data:
class javafx.scene.control.MultipleSelectionModelBase$3
javafx.scene.control.MultipleSelectionModelBase$3#4ececa
cursor = 0
Kind of change: added
Affected range: [0, 1]
Added size: 1
Added sublist: [3]
Change #1 on TableView indices
list = [3, 4]
Change event data:
class javafx.scene.control.MultipleSelectionModelBase$3
javafx.scene.control.MultipleSelectionModelBase$3#b0161d
cursor = 0
Kind of change: added
Affected range: [1, 2]
Added size: 1
Added sublist: [4]
Change #0 on ListView indices
list = [3, 4]
Change event data:
class com.sun.javafx.collections.NonIterableChange$SimplePermutationChange
{ permutated by [4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0] }
cursor = 0
Kind of change: permutated
Affected range: [0, 2]
Permutation: [0->4, 1->3]
The producing code:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.ListChangeListener.Change;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class SelectedIndicesOnItemsModified extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Integer> items = FXCollections.observableArrayList(1, 2, 3, 4);
TableView<Integer> table = new TableView<>(items);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
table.getSelectionModel().selectRange(2, 4);
System.out.println("indices before modification: " +
table.getSelectionModel().getSelectedIndices());
ListView<Integer> list = new ListView<>(items);
list.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
list.getSelectionModel().selectRange(2, 4);
new PrintingListChangeListener("TableView indices ",
table.getSelectionModel().getSelectedIndices());
new PrintingListChangeListener("ListView indices ",
list.getSelectionModel().getSelectedIndices());
items.add(0, 111);
}
public static void main(String[] args) {
launch(args);
}
public static <T> void prettyPrint(Change<? extends T> change) {
StringBuilder sb = new StringBuilder("\tChange event data:\n");
sb.append("\n " + change.getClass() + "\n " + change);
int i = 0;
change.reset();
while (change.next()) {
sb.append("\n\tcursor = ").append(i++).append("\n");
final String kind = change.wasPermutated() ? "permutated" : change
.wasReplaced() ? "replaced"
: change.wasRemoved() ? "removed"
: change.wasAdded() ? "added"
: change.wasUpdated() ? "updated" : "none";
sb.append("\t\tKind of change: ").append(kind).append("\n");
sb.append("\t\tAffected range: [").append(change.getFrom())
.append(", ").append(change.getTo()).append("]\n");
if (kind.equals("added") || kind.equals("replaced")) {
sb.append("\t\tAdded size: ").append(change.getAddedSize())
.append("\n");
sb.append("\t\tAdded sublist: ")
.append(change.getAddedSubList()).append("\n");
}
if (kind.equals("removed") || kind.equals("replaced")) {
sb.append("\t\tRemoved size: ").append(change.getRemovedSize())
.append("\n");
sb.append("\t\tRemoved: ").append(change.getRemoved())
.append("\n");
}
if (kind.equals("permutated")) {
StringBuilder permutationStringBuilder = new StringBuilder("[");
for (int k = change.getFrom(); k < change.getTo(); k++) {
permutationStringBuilder.append(k).append("->")
.append(change.getPermutation(k));
if (k < change.getTo() - 1) {
permutationStringBuilder.append(", ");
}
}
permutationStringBuilder.append("]");
String permutation = permutationStringBuilder.toString();
sb.append("\t\tPermutation: ").append(permutation).append("\n");
}
}
System.out.println(sb.toString());
};
public static class PrintingListChangeListener implements ListChangeListener {
String source;
int counter;
public PrintingListChangeListener() {
}
public PrintingListChangeListener(String message, ObservableList<?> list) {
list.addListener(this);
source = message;
}
#Override
public void onChanged(Change change) {
System.out.println("Change #" + counter++ + " on " +source +
"\nlist = " + change.getList());
prettyPrint(change);
}
}
}
Filed two issues, RT-39393 for ListView, RT-39394 for TableView
A tentative partly answer to my own question
Notification count
Number of notification (aka: calls to changed(Change c)) should be the same as number in underlying data, in pseudo-code
itemsChanges = 0;
itemsListener = c -> itemsChanges++;
getItems().addListener(itemsListener);
selectedChanges = 0;
selectedListener = c -> selectedChanges++;
getSelectedIndices().addListener(selectedListener);
getItems().modifySomehow(...);
assertEquals(itemsChanges, selectedChanges);
Change Types
Thinking about it, most changes in the underlying items seem to map to a replaced in the selectedIndices ("value" below denotes the elements in the selectedIndices):
"real" wasAdded: all values greater than the insertion location must be increased by addedSize
// selectedIndices before
[2, 4]
items.add(0, something);
// selectedIndices after
[3, 5]
-> net effect: two values are set (== replaced by) to a new value
"real" wasRemoved: all values pointing to removed items must be removed as well, values greater than the remove location must be decreased by removedSize
// selectedIndices before
[2, 4, 5, 8]
items.removeAll(items.get(3), items.get(5))
// selectedIndices after
[2, 3, 6]
-> net effect: replace [4, 5, 8] at pos 1 by [3, 6]
wasUpdated: indices are unchanged, though the underlying items did change somehow. Depending on context, it might be a good idea to pass those updates through to its listener or not.
Still open: replaced/permutation in items
To get those expected (at least by my paper coding :-) notifications correct, isn't quite trivial - and went wrong in MultipleSelectionModelBase and subclasses. Currently playing with moving all the nasty details into a dedicated IndicesList (which is-a TransformList with items as sourceList)

Calculate average top third of the population

Could you guys help me which apache-commons-math classes can I use to calculate the average of the top third of the population.
To calculate the average I know can use org.apache.commons.math3.stat.descriptive.DescriptiveStatistics.
How to get the top third of the population?
Example
Population: 0, 0, 0, 0, 0, 1, 2, 2, 3, 5,14
Top third: 2, 3, 5, 14
Average = 24/4= 6.0
First of all what do you call top third of population?
If set is divides by 3 and remainder is 0, then its is simple, but in your case 11%3 = 2.
So You should know how to get top third when remainder is not equal 0.
I would suggest You to use Arrays procedures, to get Top third of set. If You still want to use DescriptiveStatistics you can invoke it.
double[] set = {0, 0, 0, 0, 0, 1, 2, 2, 3,4,5};
Arrays.sort(set);
int from = 0;
if (set.length % 3==0){
from = set.length/3*2 ;
}
if (set.length % 3 != 0){
from = Math.round(set.length/3*2) + 1;
}
double [] topThirdSet = Arrays.copyOfRange(set,from , set.length);
DescriptiveStatistics ds = new DescriptiveStatistics(topThirdSet);
System.out.println(ds.getMean());

Steganography program giving weird results

I am developing a steganography program for a computer programming class. It appears to gives random ascii symbols. The output is supposed to be BINARY. The encode message method was given to us by my teacher. We just have to program the decode part.
import java.awt.*;
class HideMessage {
public void encodeMessage(Picture stegoObject, int[] binaryArray) {
Pixel pixelTarget = new Pixel(stegoObject, 0, 0);
Pixel[] pixelArray = stegoObject.getPixels();
Color pixelColor = null;
int redValue = 0;
for (int x = 0; x < binaryArray.length; x++) {
redValue = binaryArray[x];
pixelTarget = pixelArray[x];
pixelTarget.setRed(redValue);
}
pixelTarget = pixelArray[binaryArray.length];
pixelTarget.setRed(255);
System.out.println("FinishedPic");
stegoObject.write("SecretMessage.bmp");
stegoObject.explore();
}
public void decodeMessage(Picture decodepic) {
int redValue = 0;
Pixel targetPixel = null;
Color pixelColor = null;
int sum = 0;
for (int x = 0; redValue < 2; x++) {
//inside nested loop to traverse the image from left to right
for (int count = 1; count < 9; count++) {
targetPixel =
decodepic.getPixel(count + (8 * x), 0);
//gets the x,y coordinate of the target pixel
pixelColor = targetPixel.getColor();
//gets the color of the target pixel
redValue = pixelColor.getRed();
if (redValue == 1) {
if (count == 1) {
sum = sum + 128;
}
if (count == 2) {
sum = sum + 64;
}
if (count == 3) {
sum = sum + 32;
}
if (count == 4) {
sum = sum + 16;
}
if (count == 5) {
sum = sum + 8;
}
if (count == 6) {
sum = sum + 4;
}
if (count == 7) {
sum = sum + 2;
}
if (count == 8) {
sum = sum + 1;
}
}
System.out.println(sum);
}
System.out.println((char)sum);
sum = 0;
} //end of the inner for loop
}
}
public class HideMessageTester {
public static void main(String[] args) {
int[] bitArray =
{ 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0,
1, 1, 1, 1, 0, 0, 1 };
//int[] bitArray =
{ 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1,
0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1,
0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1,
1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1};
Picture stegoObject = new Picture("Earth.bmp");
HideMessage stego = new HideMessage();
stego.encodeMessage(stegoObject, bitArray);
Picture decodeObject = new Picture("SecretMessage.bmp");
System.out.println("Now Decoding");
stego.decodeMessage(decodeObject);
}
}
First, some general pieces of advice: I think your program is overly complicated because the functions are commingling their responsibilities:
Picture stegoObject = new Picture("Earth.bmp");
HideMessage stego = new HideMessage();
stego.encodeMessage(stegoObject, bitArray);
Picture decodeObject = new Picture("SecretMessage.bmp");
System.out.println("Now Decoding");
stego.decodeMessage(decodeObject);
I was very surprised to see SecretMessage.bmp; it wasn't at all obvious that were trying to decode the object you had just created. Sure, upon reading the encodeMessage() method it was easy enough to determine where it came from, but I think this flow would have been easier:
/* encode */
Picture pic_to_steg = new Picture("foo.bmp");
HideMessage stego = new HideMessage();
Picture secret = stego.encodeMessage(pic_to_steg, bitArray);
secret.write("SecretMessage.bmp");
/* decode */
Picture pic_with_message = new Picture("SecretMessage.bmp");
int[] hidden = stego.decodeMessage(pic_with_message);
/* output `hidden` and compare against `bitArray` */
In other words: leave the file IO entirely up to the main flow of the program. Perhaps your routines will be called from a network server in the future, and the pictures will never be saved to disk. That modification will be far easier if the routines operate on Pictures and return amended Pictures and int[].
Can you test your encodeMessage() method in isolation? Perhaps look at the differences in what it does between an input file and an output file. This section looks troublesome:
public void encodeMessage(Picture stegoObject, int[] binaryArray) {
Pixel pixelTarget = new Pixel(stegoObject, 0, 0);
Pixel[] pixelArray = stegoObject.getPixels();
Color pixelColor = null;
int redValue = 0;
for (int x = 0; x < binaryArray.length; x++) {
redValue = binaryArray[x];
pixelTarget = pixelArray[x];
pixelTarget.setRed(redValue);
}
pixelTarget = pixelArray[binaryArray.length];
pixelTarget.setRed(255);
Is the pixelArray really a reference into the image that can be updated through simple assignment? I'd really expect the design to look more like this pseudo-code:
pixel p = image.getPixel(x, y);
p.setred(binaryArray[i]);
image.setPixel(x, y, p);
The decoding has some strange loops:
for (int x = 0; redValue < 2; x++) {
//inside nested loop to traverse the image from left to right
for (int count = 1; count < 9; count++) {
This loop might work exactly as you designed it, but upon a first reading, it feels very wrong: You start with x=0, you increment x each time through the loop, but you use redValue < 2 as your loop termination rule.
I would so much rather see the loop written like this:
int x = 0;
while (redValue < 2) {
/* stuff */
x++;
}
(It isn't identical; x is still valid outside the loop, which can be dangerous. However, I think this is much more clear.)
There are cases where the termination clause of a for loop isn't related to the setup or increment clauses -- in my experience, they are very rare.
In this case though, it feels like a mistake; the condition redValue < 2 a loop invariant, but the inner loop assumes it will only happen on pixels that are multiples of 8, which is an assumption that is not enforced in the encodeMessage() method.
Trying to compute an integer value from your redValues as you read them is needlessly complicating your decode routine. I suggest removing the inner loop and return an array exactly like the array passed into the encodeMessage() routine. This will be (a) easier (b) easier to debug (c) easier to test (d) a thousand times easier to handle writing bit arrays that aren't evenly divisible by 8.
Then write a second method that turns the bit array output into the sum, or ASCII characters, or EBCDIC characters, or RSA key parameters, or whatever it is that's being encoded. Don't try to do too much at once. Writing a separate method to decode the array of bits will be (a) easier (b) easier to debug (c) easier to test (d) thousand time easier to handle arbitrary output modifications.
I hope these hints help.

Categories

Resources