This program takes integers from user input and puts them in a collection. It then prints the positive values first, then the negative values, and doesn't print repeated numbers. It stops asking for input once the user enters 0. Here is the code:
public class Intcoll2
{
private int[] c;
private int[] d;
private int howmany = 0;
public Intcoll2()
{
c = new int[500];
}
public Intcoll2(int i)
{
c = new int[i]
}
public void insert(int i)
{
if (i > 0)
{
int j = 0;
while ((j <= howmany) && (c[j] != i)) j++;
if (j == howmany)
{
if (j == c.length - 1)
{
d = new int[2*c.length];
for (int k = 0; k<c.length; i++){
d[k] = c[k];
}
c = d;
}
c[j] = i; c[j + 1] = 0;
}
howmany++;
}
}
public int get_howmany()
{
int j=0, howmany=0;
while (c[j]!=0) {howmany++; j++;}
return howmany;
}
Now my current print method looks like this:
public void print()
{
int j = 0;
System.out.println();
while (j <= howmany)
{
System.out.println(c[j]); j++;
}
}
But when I try to use that in my client, it only prints out zeros. Any help with what I'm doing wrong would be greatly appreciated.
An answer that you were probably not looking for, but still on the only real answer you should care about.
Your problem is not that somewhere in that code a bug is hiding. The problem is that your code is confusing beyond limits:
Dont use single-character variable names.
The constructor that takes an int ... creates an empty array!
Dont say "collection" when you are using arrays.
Dont give fields and local variables the same name.
Seriously: understanding this mess is mainly complicated and hard because you wrote code that is hard to read.
Now you are asking other people to debug such complicated code that you (the author who created it!) do not understand in the first place.
Instead, you might throw this whole thing away. And slowly write it again; but in a way that isn't at all confusing to the reader.
I took a look at your class and rewrote it in a more legible manner. I didn't test it but I'm confident it works. You can check it out and hopefully understand what's happening. Hope this helps!
public class IntCollection2 {
private int[] collection; // A large allocation, not neccessarily filled up.
private int currentSize; // The number of spots currently filled in the collection.
public IntCollection2() {
collection = new int[500];
currentSize = 0;
}
public IntCollection2(int size) {
collection = new int[size];
currentSize = 0;
}
/**
* Inserts a new element into the internal array. If the current array is filled up,
* a new array double the size of the current one is allocated.
* #param element An int to insert into the collection. Must not be '0'.
* #return True if the element was successfully inserted, false if the element was
* equal to '0' and was ignored.
*/
public boolean insert(int element) {
if (element != 0) {
if (currentSize < collection.length - 1) {
collection[currentSize] = element;
} else {
int[] newCollection = new int[collection.length * 2];
for (int i = 0; i < currentSize; i++) {
newCollection[i] = collection[i];
}
newCollection[currentSize] = element;
collection = newCollection;
}
currentSize++;
return true;
} else {
return false;
}
}
/**
* Not actually necessary because the class automatically updates its currentSize
* every time a new element is inserted.
* #return The current number of filled spots in the internal array.
*/
public int getCurrentSize() {
int size = 0;
for (int i = 0; i < collection.length && collection[i] != 0; i++) {
size++;
}
return size;
}
/**
* Prints out all the elements currently in the collection, one on each line.
*/
public void print() {
System.out.println();
for (int i = 0; i < currentSize; i++) {
System.out.println(collection[i]);
}
}
}
FYI: this class just prints out every element in the collection, in order. You mentioned something about printing positive then negative values, but I leave that to you.
EDIT: I'm guessing you're brand new to programming, so I just want to clarify exactly what a collection is. An array is an ordered list of elements. When you create an array, the computer sets aside a bit of memory to hold exactly the number of elements you told it to. You cannot change the size of an existing array. A collection is basically a wrapper around an array. It makes a bigger array than it needs to hold its elements, and when its array becomes full, it allocates a new, bigger one that can hold more elements.
Related
In this homework problem we’ll finish implementing the SimpleList interface shown above in a class called SimpleArrayList. We have provided starter code for you including a constructor that takes an initial array of Object references. We are also providing code for the get, set, and size methods—which you completed yesterday—and for remove, to give you an idea of how to approach add. Note that at this point we are testing the entire interface shown above. Your job is to complete add. Like set, you can ignore invalid indices. We will test them.
my code makes sense logically but won't compile
public class SimpleArrayList {
/** Internal array for storing values. */
private Object[] array;
/**
* Create a list from an array of Objects.
*
* Copies references from the passed array so that
* modifications to this list will not affect the original array.
* We'll need to make copies of the array later to support add and remove,
* so this is the right thing to do now.
*
* #param originalArray original array of Objects used to create the list
*/
SimpleArrayList(Object[] originalArray) {
// Would normally need to defend against originalArray being null,
// but we'll defer that until later.
if (originalArray != null) {
array = new Object[originalArray.length];
for (int i = 0; i < originalArray.length; i++) {
array[i] = originalArray[i];
}
}
}
public Object get(int index) {
if (index < 0 || index >= array.length) {
return null;
}
return array[index];
}
public void set(int index, Object element) {
if (index < 0 || index >= array.length) {
return;
}
array[index] = element;
}
public int size() {
return array.length;
}
public Object remove(int removeIndex) {
if (removeIndex < 0 || removeIndex >= array.length) {
return null;
}
// remove returns the item being removed
Object toReturn = array[removeIndex];
// Create and populate our new smaller array. We use for loop syntax
// maintaining two indices.
Object[] newArray = new Object[array.length - 1];
int originalIndex = 0;
for (int newIndex = 0; newIndex < newArray.length; newIndex++) {
// Skip the spot that we are removing
if (newIndex == removeIndex) {
originalIndex++;
}
newArray[newIndex] = array[originalIndex];
originalIndex++;
}
array = newArray;
return toReturn;
}
public void add(int index, Object element)
{
Object[] newArray = new Object[array.length + 1];
int orIndex = 0;
for(int i =0; i< index; i++)
{
newArray[i] = array[orIndex];
orIndex++;
}
newArray[index] = element;
for(int i = index+1; i< newArray.length; i++)
{
newArray[i] = array[orIndex];
orIndex++;
}
array = newArray;
}
}
all of this was given except for my add method which I wrote. I get different errors right now it says incompatible types for the instantiation of simplearraylist as a list which I didn't even write.
my code makes sense logically but won't compile. all I've written is the add method, everything else was given. I based it off the remove method
It has to implement the interface SimpleList
I am supposed to implement a method in Java that returns an array of integers with no duplicates. I have managed to do it, but my solution seems rather long. I would like to know of ways to improve it.
I added comments so it is easier for your guys to understand what the code does.
public class IntArrayProcessor {
private int[] a;
public IntArrayProcessor(int[] a) {
this.a = a;
}
/**
*
* #return Array with no repeated integers.
*/
public int[] getSet() {
/* creates an array with the same entries and length as this.a */
int[] duplicateA = new int[this.a.length];
/* stores the number of repeated entries in array this.a */
int numberOfDuplicates = 0;
/* is the integer a duplicate or not? */
boolean isDuplicate;
/**
* Counts the number of duplicates in array this.a
*/
for (int i = 0; i < this.a.length; i++) {
duplicateA[i] = this.a[i];
}
for (int i = 0; i < duplicateA.length; i++) {
isDuplicate = false;
for (int j = i + 1; j < this.a.length; j++) {
if (duplicateA[i] == this.a[j]) {
isDuplicate = true;
}
}
if (isDuplicate) {
numberOfDuplicates++;
}
}
/*
* the noDuplicate array has the lenght of the this.a array minus the
* number of repeated entries
*/
int[] noDuplicate = new int[this.a.length - numberOfDuplicates];
/* to keep track of the noDuplicate indexes */
numberOfDuplicates = 0;
/**
* An array with no repeated numbers
*/
for (int i = 0; i < duplicateA.length; i++) {
isDuplicate = false;
for (int j = i + 1; j < this.a.length; j++) {
if (duplicateA[i] == this.a[j]) {
isDuplicate = true;
}
}
if (!(isDuplicate)) {
noDuplicate[numberOfDuplicates] = duplicateA[i];
numberOfDuplicates++;
}
}
return noDuplicate;
}
}
An easy solution is to use the Stream API:
int[] distinctArray = IntStream.of(a).distinct().toArray();
If you don't want to use Stream API you can use a HashSet (or other collections that implement the Set interface).
Set<Integer> set = new HashSet<Integer>(Arrays.asList(array));
That is some rather long code! It seems like you are looking for a more homemade solution than the one that Max put up! Here is some psuedo-code for what I would do:
1. Create a dictionary that takes an int and returns a boolean.
2. For every element in your starting array add it to the dictionary with the boolean value of true (even though the value won't actually matter).
3. Find the number of keys in your dictionary (this will be the number of unique values found in the first array, which is also the length of your new array)
4. Create a new array given the length found in the previous step.
5. Run through each of the keys in the dictionary and add it to the new array!
Shortcut: Instead of step 4 & 5 typically getting the keys from the dictionary will return an array, which would be your end solution.
I'd be happy to write up a more formal solution if that is more helpful.
Note: If you are only familiar with Java, Dictionaries are almost synonymous to HashMaps and can be used interchangeably in this situation. Java's default implementation of a dictionary is called a HashMap
Note 2: Accessing the number of keys/getting all of the keys in a Dictionary/HashMap should be a function built-in, not one you have to write!
I want to check if an array is at 75% filled with objects and if it's true i have to resize it. In the variable size i have my objects (!=null) and i have an array of integers ints
public class PQ {
private int[] pq;
private int size;
public PQ(int capacity) {
if (capacity < 1) {
throw new IllegalArgumentException();
}
this.pq = new int[capacity + 1];
this.size = 0;
}
public void insert(int number) {
//Code
}
private int[] resize() {
int[] newPQ = new int[this.pq.length * 2];
for (int i = 0; i < this.pq.length; i++) {
newPQ[i] = this.pq[i];
}
return newPQ;
}
}
Try this:
Whenever you add an element, we increment size (this will track the number of non-empty spaces so that you don't need to continually recount your array). Then we compare this number to the total length of your array. If count is at least 75% of the size of the array, we call your resize method and set pq to the new array it returns. I assume that you wish to add to the end of the array, and that you don't want empty indexs between numbers. If you want gaps you will need to use a loop which I am trying to avoid for efficiency's sake, if it isn't necessary. Assuming you don't, you can just add to your array at index size since this will be the first non-empty element.
//O(1) efficiency if you don't need to resize, O(n) if you do
public void insert(int number) {
if(size / pq.length >= 75) {
pq = resize();
}
pq[size] = number; //Since this will be the first non-empty index
size++;
return; //Doing it this way, if you can, is much more efficient than looping
}
If you call remove and take out from anything but the end you are going to have to shift everything down so that you don't have empty space.
If you are going to have empty indexes, try something like this (to insert at the first empty index encountered by the loop)...Let's use an Integer[] instead so that you can check for null and don't have to worry about any 0's in the array being counted as empty (int[] initiates everything to 0).
That way we can check for empty space and 0's are not counted as empty space in case you use any in your int[].
//O(n) efficiency if you don't need to resize, O(n^2) if you do
public void insert(int number) {
if(size / pq.length >= 75) {
pq = resize();
//You would have to make resize return an Integer[] and
//implement this throughout the code
}
for(int i = 0; i < pq.length; i++) {
if(pq[i] == null) {
pq[size] = number;
size++;
return;
}
}
}
Regardless:
Remember when you call remove() to decrement size.
What you could do is have an integer instance variable called count, that keeps track of the number of elements in the pq array. And whenever you insert an element into the array through the insert method, you can increment the count variable. Whenever you remove an element from the array through a remove method, you can decrement the count variable. Then, you can use this to check if the array is 75% filled at least,
if(pq.length * .75 <= size){
//do what you need to do here
}
And the class would look like this,
public class PQ {
private int[] pq;
private int size;
public PQ(int capacity) {
if (capacity < 1) {
throw new IllegalArgumentException();
}
this.pq = new int[capacity + 1];
this.size = 0;
}
public void insert(int number) {
size++;
//Code
}
public void remove(int number) {
size--;
//Code
}
private int[] resize() {
int[] newPQ = new int[this.pq.length * 2];
for (int i = 0; i < this.pq.length; i++) {
newPQ[i] = this.pq[i];
}
return newPQ;
}
}
You are explicitly storing the size as a variable. You also know the backing array's size. Compare them at the point when you need to check size: if(this.size > 3*this.pq/4).
Use ArrayList do everything automatically for you in more efficient way.
Edited:
it is the initialization, all put -1
this.pq = new int[capacity + 1];
Arrays.fill(pq, -1);
then when you check you do like this:
if(pq[pq.length*.75] != -1) {
// then is means that is has already filled up 75%
} else {
// not filled 75% yet
}
I am trying to implement a minmax algorithm to create an AI for connect four. I'm having quite a bit of trouble with it though as I feel like I have overcomplicated things (and it doesn't work properly), perhaps someone here can help. I'm going to post my code first and then the issue I'm having with it below.
This is the initial call to the minmax algorithm
public int getColumnForMove(ConnectFour game)
{
game.minimax(2, game.getCurrentPlayer(), game);
int column = game.getBestMove();
return column;
}
This is the initial minimax method (it is inside the ConnectFour class which is not where the initial method is called from that is in a separate AI class) that is called and a subclass that holds each column the user moves into as well as the min/max'ed score if it moves into that column.
class ColumnsAndScores
{
int column;
int score;
ColumnsAndScores(int column, int score)
{
this.column = column;
this.score = score;
}
}
List<ColumnsAndScores> cas = new ArrayList<>();
public void minimax(int depth, int turn, ConnectFour game)
{
cas = new ArrayList<>();
minimaxHelper(depth, depth, turn, game);
}
The following are methods that get the min or max score from each set of possible moves:
public int getMax(List<Integer> list)
{
int max = Integer.MIN_VALUE;
int index = -1;
for (int i = 0; i < list.size(); i++)
{
if (list.get(i) > max)
{
max = list.get(i);
index = i;
}
}
return list.get(index);
}
public int getMin(List<Integer> list)
{
int min = Integer.MAX_VALUE;
int index = -1;
for (int i = 0; i < list.size(); i++)
{
if (list.get(i) < min)
{
min = list.get(i);
index = i;
}
}
return list.get(index);
}
This is the actual minimax method (it has a bunch of commented out code that shows it should return a range of values depending on how good the board is if its not a clear cut win or loss but right now I'm just trying to have it make decisions based on a win or loss (if none of that happens in the requested depth it makes a random move)).
public int minimaxHelper(int originalDepth, int depth, int turn, ConnectFour game)
{
//holds future game states
ConnectFour futureGameState;
//holds the current scores
List<Integer> scores = new ArrayList<>();
//if (not at the lowest depth)
if (depth !=0)
{
if (checkForWin(turn))
{
//return Integer.MAX_VALUE or Integer.MIN_VALUE respectively based on who's turn it is
return (turn % 2 == 0) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
//recursively call getColumnForMove(depth--, otherTurn) for each column if the column isnt full
for (int i = 1; i <= ConnectFour.NUM_OF_COLUMNS; i++)
{
futureGameState = new ConnectFour();
futureGameState.setCurrentGameState(game.getCurrentGameState());
futureGameState.setCurrentPlayer(game.getCurrentPlayer());
if (futureGameState.isValidMove(i))
{
futureGameState.makeMove(i);
futureGameState.switchPlayer();
scores.add(minimaxHelper(originalDepth, depth - 1, futureGameState.getCurrentPlayer(), futureGameState));
}
else //if move isnt valid return the worst possible value so this column doesnt get chosen
{
return (turn % 2 == 0) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
if (depth == originalDepth)
{
ColumnsAndScores newScore;
if (turn % 2 == 0)
newScore = new ColumnsAndScores(i, getMax(scores));
else
newScore = new ColumnsAndScores(i, getMin(scores));
cas.add(newScore);
}
}
if (turn % 2 == 0)
return getMax(scores);
else
return getMin(scores);
}
else
{
if (checkForWin(turn))
{
//return Integer.MAX_VALUE or Integer.MIN_VALUE respectively based on who's turn it is
return (turn % 2 == 0) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
else
{
return 0;
}
//else
//if 3 in a row with 2 open spaces that have pieces under those spaces
//return 100
//else if 3 in a row with 1 open space that has a piece under that space
//return 80;
//else if 3 in a row
//return 60;
//else if 2 in a row
//return 40
//else
//return 0
}
}
and finally this is a method that is called by the AI to get the best move from the list that minimax added the ColumnAndScores too.
public int getBestMove()
{
int highestScore = Integer.MIN_VALUE;
int best = -1;
for (int i = 0; i < cas.size(); ++i) {
if (highestScore < cas.get(i).score) {
highestScore = cas.get(i).score;
best = i;
}
}
if (highestScore == 0)
return 1 + ((int) (Math.random() * 7));
else
return best;
}
While I believe there are a couple of logic errors the thing I am having the most difficulty with at the moment is that when I dofutureGameState = new ConnectFour();
futureGameState.setCurrentGameState(game.getCurrentGameState());
This should put it into a separate instance so that when I then make a move it should only last for that branch of the tree and not corrupt the actual game being played but that isn't the case. It is changing the actual state of the game being passed in.
The issue is most probably caused by the implementation of ConnectFour, something like
private int[][] state;
public void setCurrentGameState(int[][] newState) {
this.state = newState;
}
That's okay, but causes your "copy" of the game state to actually reference the same int[][] state, thus any modifications to it will apply to both states. What you want is
public class ConnectFour implements Cloneable<ConnectFour> {
private static final int NUM_ROWS = 6;
private static final int NUM_COLS = 7;
private int[][] state = new int[NUM_ROWS][NUM_COLS];
// ...
public ConnectFour clone() {
int[][] stateCopy = new int[NUM_ROWS][NUM_COLS];
for (int i = 0; i < NUM_ROWS; i++)
for (int j = 0; j < NUM_COLS; j++)
stateCopy[i][j] = this.state[i][j];
ConnectFour cloned = new ConnectFour();
cloned.setCurrentGameState(stateCopy);
// copy other fields over to cloned
return cloned;
}
}
I'm just going to address one issue. You should try not to have too many per question, and include the code relevant to your question, such as your ConnectFour class here.
If you want to make a copy of the board you can modify without changing the original, you need to make a deep copy, not a copy of the reference. To make a shallow copy of your house, you make a copy of your house key. If you give it to someone, you shouldn't be surprised to see changes when you get home. To make a deep copy of your house, you get a second lot and build a new house from blueprints and photos of your house. If you give a key to the new house to someone, he/she might not notice the difference immediately, but any changes shouldn't affect you directly, and changes you make won't affect the recipient.
"Deep copy" is actually ambiguous because your object may contain object members that have object members. When you make a deep copy, you have to decide whether to make deep copies or shallow copies of any member objects. If your ConnectFour class contains an ArrayList of Move objects, each of which is a wrapper for an int representing a column, you have 3 choices:
You can copy a reference to the ArrayList.
You can make a new ArrayList with references to the same set of moves.
You can make a new ArrayList with references to copies of the moves.
Anyway, my guess is that you don't yet have nested member objects, so your deep copy method can look something like the following:
public class ConnectFour{
private int[][] board = new int[6][7];
public setCurrentGameState(int[][] state){
for(int i = 0; i<6; i++)
for(int j=0; j<7; j++)
board[i][j] = state[i][j];
}
...
I have a random set S of integers and the cardinality (n) of this set may vary from 10 to 1000. I need to store all sums of the nCr combinations of size r generated from this set. Usually r range from 3 to 10.
E.g. if S={102,233,344,442,544,613,71289,836,97657,12} and r=4, Then The sums generated will be {0,1,2,3}=102+233+344+442, {0,1,2,4}=102+233+344+544,....so on.
I implemented a findCombi function (below) in Java which gave me all nCr combinations in terms of r sized sets of indices and then I sifted through these sets in another function to generate the sum of corresponding elements.
But the program is giving heapspace error, probably because of exponential nature and I have 100-5000 of such sets, S. Or may be there is a memory leak?
Is there a faster and lesser-memory consuming way to do it?
Note: dsize=n, combiSize=r
List <List<Integer>> findCombi(int dsize,int combiSize) {
if( (combiSize==0) || (dsize==0) ){
return null;
}
long n=dsize;
int r=combiSize;
for(int i=1;i<combiSize;i++) {
n=n*(dsize-i);
r=r*i;
}
int totalcombi=(int) n/r;
List <List<Integer>> combiData=new ArrayList<>(totalcombi);
int pos;
List <Integer> combi=new ArrayList<>(combiSize);
for(int i=0;i<combiSize;i++) {
combi.add(i,i);
}
combiData.add(new ArrayList<>(combi));
pos=combiSize-1;
while(true) {
if(combi.get(pos)<(dsize-combiSize+pos)) {
combi.set(pos,combi.get(pos)+1);
if(pos==(combiSize-1)) {
combiData.add(new ArrayList<>(combi));
}
else {
combi.set(pos+1,combi.get(pos));
pos++;
}
}
else {
pos--;
}
if(pos==-1) {
break;
}
}
return combiData;
}
I needed something like that earlier, so here is some code adapted from the project I made back then. The method allSums builds a list of indices of size r, which is used to represent all the possible combinations. At each step, the current sum is added to the result set, then the next combination is generated. Since the results are put in a set, there is no way a result could appear twice. I included a main method so you can see it work. I hope this is clear, feel free to ask questions.
import java.util.*;
public class Program {
static private Set<Integer> allSums(List<Integer> values, int r) {
HashSet<Integer> res = new HashSet<>();
if ((values.isEmpty()) || r > values.size()) {
return res;
}
// build the list of indices
List<Integer> li = new ArrayList<>();
for (int i = 0; i < r; i++) {
li.add(i);
}
li.add(values.size()); // artificial last index : number of elements in set
while (true) {
// add the current sum to the result
int sum = 0;
for (int i = 0; i < r; i++) {
sum += values.get(li.get(i));
}
res.add(sum);
// move to the next combination
// first, find the last index that can be incremented
int i = r-1;
while ((i >= 0) && (li.get(i) == li.get(i+1)-1)) {
i--;
}
// was such an index found ?
if (i == -1) {
break; // if not, it's over
}
// increment the last index and set all the next indices to their initial value
li.set(i,li.get(i)+1);
for (int j = i+1; j < r; j++) {
li.set(j, li.get(j-1)+1);
}
}
return res;
}
public static void main(String[] args) {
List<Integer> values = new ArrayList<>();
values.add(10);
values.add(100);
values.add(1000);
values.add(10000);
values.add(100000);
Set<Integer> s = allSums(values, 3);
for (int i : s) {
System.out.println(i);
}
}
}