I am making a small class for a little project. It's a text based RPG game and I am trying to create a drop class for when NPC's die. I have create a couple Math.random methods (which are exactly the same, just differently named for my convenience.) to drop random amounts for an item id (name) and to get the rarity of the item dropped. It all works fine, but it only randomizes one time (on startup or run) and it won't randomize the amounts after that. I am also randomizing it between 2 numbers, for example, 25 and 50, the random not going lower then 25 or higher then 50.
My question is: How can I randomize a integer in a 2D Array or a general array after each time a NPC dies, so the random number that is first obtained changes and doesn't stay the same. Because right now, it stays at the number choose. if the number is 25, then the next npc I kill, the amount would still be 25.. and 25.. and 25.. and so on. I need it to randomize or change.
Please help, thank you.
public class DropConfig {
private static final int
ALWAYS = 0,
VERY_COMMON = rate(1, 9),
COMMON = rate(10, 20),
UNCOMMON = rate(30, 40),
RARE = rate(50, 60),
VERY_RARE = rate(70, 80),
SUPER_RARE = rate(90, 100);
public static final int[][] NPC_DROPS = {
// Normal NPC's
{1, 526, 1, ALWAYS},
{2, 526, 1, ALWAYS},
{3, 526, 1, ALWAYS},
{1, 995, drop(1, 50), ALWAYS},
{2, 995, drop(1, 50), ALWAYS},
{3, 995, drop(1, 50), ALWAYS},
// Moderate NPC's
{9, 526, 1, ALWAYS},
{9, 995, drop(250, 500), UNCOMMON},
{9, 555, drop(2, 7), VERY_COMMON},
{9, 995, drop(5, 50), VERY_COMMON},
{9, 1050, 1, RARE},
};
public static int rate(int min, int max) {
return 1 + (int)(Math.random() * ((max - min) + 1));
}
//Same as rate, different name for looks.
public static int drop(int min, int max) {
return 1 + (int)(Math.random() * ((max - min) + 1));
}
Heres where I call the drops method
public void npcDeath() {
int npc = 0;
if (npc == null)
return;
for(npc = 0; npc < DropConfig.NPC_DROPS.length; npc++) {
if(npc == DropConfig.NPC_DROPS[npc][0]) {
if(Misc.random(DropConfig.NPC_DROPS[npc][3]) == 0) { //Drops ALWAYS item
Item(DropConfig.NPC_DROPS[npc][1], DropConfig.NPC_DROPS[npc][2]);
}
}
}
}
If I understand correctly, you would like the elements of the NPC_DROPS array initialized with a call to drop() to be reinitialized each time this NPC_DROPS array is used.
Well, NPC_DROPS is a constant, so it can't change. Generate it each time it's accessed, using a method:
public static int[][] generateNpcDrops(){
return new int[][] {
// Normal NPC's
{1, 526, 1, ALWAYS},
{2, 526, 1, ALWAYS},
{3, 526, 1, ALWAYS},
{1, 995, drop(1, 50), ALWAYS},
{2, 995, drop(1, 50), ALWAYS},
{3, 995, drop(1, 50), ALWAYS},
// Moderate NPC's
{9, 526, 1, ALWAYS},
{9, 995, drop(250, 500), UNCOMMON},
{9, 555, drop(2, 7), VERY_COMMON},
{9, 995, drop(5, 50), VERY_COMMON},
{9, 1050, 1, RARE},
}
}
...
public void npcDeath() {
int npc = 0;
if (npc == null)
return;
int[][] npcDrops = DropConfig.generateNpcDrops();
for(npc = 0; npc < npcDrops.length; npc++) {
if(npc == npcDrops[npc][0]) {
if(Misc.random(npcDrops[npc][3]) == 0) { //Drops ALWAYS item
Item(c, npcDrops[npc][1], npcDrops[npc][2]);
}
}
}
}
You want to place functions as constants. You can do this in a language like Scala naturally, but in Java you have to work a little harder.
In every case, you need to call a function to get the actual value.
You can use enum and anonymous methods, but the simplest way/hack is to encode your ranges.
public static int rate(int min, int max) { // same for drop.
int range = max - min;
return (range << 16) | (min & 0xFFFF);
}
public static int eval(int minMax) {
int min = (short) minMax;
int range = (short) (minMax >> 16);
if (range == 0)
return min; // plain number.
else
return min + (int) (Math.random() * (range + 1));
}
You need to call eval() to turn your encoded range into a random number.
Creating an instance of Random with the same seed you will get the same 'random' number. Have you considered using SecureRandom? The difference between SecureRandom and Random is that SecureRandom produces non-deterministic output on each call.
Related
i am writing a program that will read the element in a convolute and the program will then multiple each element in the convolute with the kernel given. I will need to take the convolute array from other class as well as kernel.
But i am getting this Error message: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
The error will be specified in the comment section with capitalised sentence, which is in my second for loop
The classes (kernel and the convolute) will be provided down after my code.
Thank You!
public static void main(String[] args)
{
Kernel kernel = new Kernel();
Convolute convolute = new Convolute();
int[][] matrixA = convolute.MATRIX_A;
int[][] kernelVertical = kernel.VERTICAL;
int[][] resultArray = new int[4][4];
int tempMatrix = 0, sumMatrix = 0; // declare temporary matrix and sumMatrix to take all the sum of each product array
int matrixRowA = 0, matrixColumnA = 0; // declare variable for matrix row and column
int convoluteRowControl = 2, convoluteColumnControl = 2; // this variable is to control moving of the kernel through the convolute
while(convoluteRowControl < matrixA.length) // while loop stops when convoluteRowControl points to 6
{
for(int kernelRow = 0; kernelRow < kernelVertical.length; kernelRow++) // this loop will stop when kernelRow is 3
{
for(int kernelColumn = 0; kernelColumn < kernelVertical[kernelRow].length; kernelColumn++) // this loop will stop when kernelColumn is 3
{
tempMatrix = matrixA[matrixRowA][matrixColumnA] * kernelVertical[kernelRow][kernelColumn]; // ERROR IS HERE!!
sumMatrix += tempMatrix; // sum all of the matrix calculated
matrixColumnA++; // re-initialize matrixColumnA to move to the next column element in matrixA
}
matrixRowA++; // re-initialize matrixRowA to move to the next row element in matrixA
matrixColumnA = convoluteColumnControl - 2; // re-initialize matrixColumnA back to the original specified range
}
for(int row = 0; row < resultArray.length; row++) // this loop is used to store sumMatrix calculated in the above loop to each element of the array
{ // loop stops at 5
for(int column = 0; column < resultArray[row].length; column++)
{
resultArray[row][column] = sumMatrix; // store sumMatrix into each element of the array
}
}
++convoluteColumnControl; // re-initialize convoluteColumnControl so that the kernel can move to the next column
if(matrixColumnA < 5) // if kernel get to the last column of its size, reset the row and move to the next column again
{ // this will stop when kernel get to the final column of the convolute
matrixRowA = convoluteRowControl - 2; // reset row back to the the top kernel
matrixColumnA = convoluteColumnControl - 2; // set new starting limit for the column in the kernel
}
if(matrixColumnA == 5) // when matrixColumnA is 5 (which means the final column of the convolute) this IF is executed
{ // to set the new row for the kernel
++convoluteRowControl; // convolteRowControl increase by 1 to set a new row limit for the kernel in convolution
matrixRowA = convoluteRowControl - 2; // reset matrixRowA equivalent to the starting of the new kernel
}
}
}
public class Convolute
{
/*
* ARRAY_A contains a 6x6 matrix
*/
public static final int[][] MATRIX_A =
{
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0}
};
}
public class Kernel
{
/*
* HORIZONTAL - A kernel that detects horizontal lines.
*/
public static final int[][] HORIZONTAL =
{
{ 1, 1, 1},
{ 0, 0, 0},
{-1, -1, -1}
};
/*
* VERTICAL - A kernel that detects vertical lines.
*/
public static final int[][] VERTICAL =
{
{ 1, 0, -1},
{ 1, 0, -1},
{ 1, 0, -1}
};
}
I am trying to implement a machine learning algorithm (k-nn for example).As it stands my Main class, which essentially builds 8×8-pixel matrices into an array to be manipulated later. (See the data description and sample dataset.) As it stands my arrays are printing as a like so:
, Class Code: 7 DataSet:[0, 0, 3, 9, 15, 8, 0, 0, 0, 1, 15, 16, 16, 7, 0, 0, 0, 0, 5, 16, 16, 10, 4, 0, 0, 0, 3, 16, 16, 16, 9, 0, 0, 0, 0, 15, 14, 4, 0, 0, 0, 0, 0, 13, 5, 0, 0, 0, 0, 0, 1, 15, 3, 0, 0, 0, 0, 0, 4, 13, 0, 0, 0, 0, 7]
Now for my starting point I'm looking to try to implement a very basic kNN algorithm as something to build from but I am having trouble manipulating the datasets that are being outputted. I have been reading up on Foundations of Machine Learning by M. Mohri but it hasn't been of any help. My Main class for building my data:
import java.util.*;
import java.io.*;
public class Main {
static class Data {
int[] dataSet;
int classCode;
public Data(int[] dataSet, int label) {
this.dataSet = dataSet;
this.classCode = label;
}
#Override
public String toString() {
return "Class Code: " + classCode + " DataSet:" + Arrays.toString(dataSet) + "\n";
}
}
ArrayList<Data> dataSetList;
int[][] dataArray = new int[2810][65];
private void readFile(String csvFile) {
int instances = 0;
dataSetList = new ArrayList<>();
try {
Scanner scan = new Scanner(new BufferedReader(new FileReader(csvFile)));
while (scan.hasNext()) {
String line = scan.next();
String[] extractedDataFromFile = line.split(",");
for (int i = 0; i < extractedDataFromFile.length; i++) {
dataArray[instances][i] = Integer.parseInt(extractedDataFromFile[i]);
}
dataSetList.add(new Data(dataArray[instances], dataArray[instances][extractedDataFromFile.length - 1]));
instances++;
}
System.out.println(dataSetList.toString());
} catch (FileNotFoundException ex) {
System.out.println(ex.getMessage());
}
}
public static void main(String[] args) {
Main main = new Main();
main.readFile("dataset1.csv");
}
}
This is my first time experimenting with machine learning so any feedback or approach to this would be hugely appreciated.
EDIT//
I'm looking at a basic kNN implementation as a starting point whether someone can redirect me to material on implementing on a similar data set or an example using my current provided code. I apologize if my initial post was a little vague
I've been trying to implement an A* algorithm in a tower defense style game and after hours of trying I thought I'd ask for some insight in my logic flaws.
I've been trying to create it via http://web.mit.edu/eranki/www/tutorials/search/ & https://stackoverflow.com/a/5602061/1550619
But and infinite problem occurs when trying to generate the successors/neighbors to an AStarNode(I think) - First time implementing A* and still learning.
private ArrayList<AStarNode> aStaring(Object o, AStarNode start, AStarNode goal) {
ArrayList<AStarNode> closed = new ArrayList();
ArrayList<AStarNode> open = new ArrayList();
start.g = 0;
start.h = estimateDistance(start, goal);
start.f = 0;
open.add(start);
while(!open.isEmpty()){
AStarNode q = null;
for(AStarNode asn : open){
if(q == null || asn.f < q.f){
q = asn;
}
}
open.remove(q);
closed.add(q);
for(AStarNode succesor : q.generateSuccesors()){
if(closed.contains(succesor)){
System.out.println("Closed contained succesor");
//TODO Check if walkable
}else{
if(!open.contains(succesor)){
succesor.g = q.g+1;
succesor.h = estimateDistance(succesor, goal);
succesor.f = succesor.g + succesor.h;
succesor.parent = q;
open.add(succesor);
}else{
float nextG = q.g + succesor.cost;
if(nextG < succesor.g){
open.remove(succesor);
closed.add(succesor);
}
}
if(succesor.x == goal.x && succesor.y == goal.y){ //path found
System.out.println("hurray");
return reconstructPath(succesor);
}
}
}
}
return null;
}
public class AStarNode {
private MapDimension md = new MapDimension();
public AStarNode parent;
public int x,y;
public int f,g,h;
public int cost = 1;
public AStarNode(int x, int y){
this.x = x;
this.y = y;
}
//Looking up 4 neighbors and adding to node;
public ArrayList<AStarNode> generateSuccesors(){
ArrayList<AStarNode> neighbors = new ArrayList<>();
if(x+1 < md.getWidth()){
AStarNode temp = new AStarNode(x+1,y);
temp.parent = this;
neighbors.add(temp);
}
if(x-1 > 0){
AStarNode temp = new AStarNode(x-1,y);
temp.parent = this;
neighbors.add(temp);
}
if(y+1 < md.getHeight()){
AStarNode temp = new AStarNode(x,y+1);
temp.parent = this;
neighbors.add(temp);
}
if(y-1 > 0){
AStarNode temp = new AStarNode(x,y-1);
temp.parent = this;
neighbors.add(temp);
}
return neighbors;
}
}
Map:
public static final int[][] MAP = {
{1, 1, 1, 1, 2, 2},
{1, 1, 1, 0, 0, 2},
{2, 0, 1, 0, 0, 0},
{2, 0, 1, 0, 1, 1},
{2, 2, 1, 1, 1, 1},
{2, 2, 0, 0, 0, 1},
{2, 1, 1, 1, 1, 1},
{0, 1, 0, 0, 2, 2},
{2, 1, 0, 2, 2, 2},
{0, 1, 0, 0, 2, 2},
};
Any pointers towards the right direction would be fantastic :]
Everytime you run generateSuccessors, you create 4 (or less) NEW instances of AStarNode objects. This is not a problem per se, but AStarNode does not define hashCode and equals. So two nodes with the same coordinates are not considered equals, so closed.contains(successor) will NEVER return true.
Implement hashCode and equals on AStarNode (or get your IDE to do it for you). Something as simple as:
public int hashCode(){
return x*y;
}
public boolean equals(Object o){
if (o instanceof AStarNode){
return x==((AStarNode)o).x && y==((AStarNode)o).y;
}
return false;
}
I'm stitching a bitmap from a layout array, that puts the a larger bitmap together as a guide. Using multiple bitmaps into one bitmap. What I rotate the whole bitmap, my solution is to restitch it but have the array account for this rotation. The making of the bitmap is determined by the order of the array. The stitching assumes that the array starts from zero and that is the first index or the left top most corner and then goes to the right to the end and goes to beginning of the next row. I would like to have a 90, 180, 270, and 360 functions to call on. I'm thinking 360 is easy I iterate backwards. I'm using 11 by 11 which is constant.
For example
0, 1, 3, 4
5, 6, 7, 8,
9, 10, 11, 12
13, 14, 15, 16
when I rotate 90
4, 8, 12, 16
3, 7, 11, 15
1, 6, 10, 14
0, 5, 9, 13
Try this. This may have performance impact but its a simple solution.
import java.util.Arrays;
public class RotateMatrix {
public static void main(String[] args) {
int original[][] = { { 0, 1, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 },
{ 13, 14, 15, 16 } };
printArray(original);
System.out.println("After 90 Degree");
printArray(rotate(original, 90));
System.out.println("After 180 Degree");
printArray(rotate(original, 180));
System.out.println("After 270 Degree");
printArray(rotate(original, 270));
System.out.println("After 360 Degree");
printArray(rotate(original, 360));
}
private static int[][] rotate(int[][] original, int angle) {
int[][] output = original;
int times = 4 - angle/90;
for(int i=0; i<times; i++){
output = rotate(output);
}
return output;
}
private static int[][] rotate(int[][] original) {
int n = original.length;
int m = original[0].length;
int[][] output = new int[m][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
output[j][n - 1 - i] = original[i][j];
return output;
}
private static void printArray(int[][] array) {
for (int i = 0; i < array.length; i++) {
System.out.println(Arrays.toString(array[i]));
}
}
}
This rotates the array anti-clockwise direction just as in your example. However if you want to change this to clockwise just change int times = 4 - angle/90; to int times = angle/90; in rotate(int[][] original, int angle) method.
How long does it last to solve the knights tour problem with backtracking on an 8x8 board? Because my algorithm already computes somehow too long and it seems, like it wont finish. But when I try a 6x6, or 5x5 board, it finishes successfully.
the code:
class KnightsTour{
private boolean[][] board;
private int count, places;
private static final Point[] moves = new Point[]{
new Point(-2, -1),
new Point(-2, 1),
new Point(2, -1),
new Point(2, 1),
new Point(-1, -2),
new Point(-1, 2),
new Point(1, -2),
new Point(1, 2)
};
public KnightsTour(int n) {
board = new boolean[n][n];
places = n*n;
count = 0;
}
public boolean ride(int x, int y) {
board[x][y] = true;
count++;
if (count == places) {
return true;
}
for (Point p : moves) {
int nextX = x + p.x;
int nextY = y + p.y;
if (nextX < 0 || nextX >= board.length || nextY < 0 || nextY >= board.length || board[nextX][nextY]) {
continue;
}
if (ride(nextX, nextY)) {
return true;
}
}
board[x][y] = false;
count--;
return false;
}
}
I came across the same problem. Everything runs smoothly till n=7 and suddenly it takes forever to calculate for n=8. I hope this helps someone :)
The problem lies with the order in which you are checking for the moves. You are using :
xMove[8] = { -2, -2, 2, 2, -1, -1, 1, 1}
yMove[8] = { -1, 1, -1, 1, -2, 2, -2, 2}
If you plot these vectors in the 2D plane, they are haphazardly placed. In other words, they are not ordered in either a clockwise or an anti-clockwise manner. Consider this instead :
xMove[8] = { 2, 1, -1, -2, -2, -1, 1, 2 }
yMove[8] = { 1, 2, 2, 1, -1, -2, -2, -1 }
If you plot these vectors, they are neatly arranged in an anticlockwise circle.
Somehow this causes the recursion to run much quickly for large values of n. Mind you, it still takes forever to calculate for n=9 onwards.