I am writing the code in Java as a plugin to a Minecraft server, but the logical principles are general in nature.
public void doReviewMember(CommandSender playerSent) {
if (!reviewsMember.isEmpty()) {
Review doThis = null;
ArrayList<Review> players = new ArrayList<Review>();
ArrayList<Review> playersVIP = new ArrayList<Review>();
ArrayList<Review> playersVIPplus = new ArrayList<Review>();
for (int c1 = 0; c1 < reviewsMember.size(); c1++) {
if (Bukkit.getPlayer(reviewsMember.get(c1).getName()).hasPermission("reviewplugin.vipplus"))
playersVIPplus.add(reviewsMember.get(c1));
else if (Bukkit.getPlayer(reviewsMember.get(c1).getName()).hasPermission("reviewplugin.vip"))
playersVIP.add(reviewsMember.get(c1));
else players.add(reviewsMember.get(c1));
}
if (playersVIPplus.size() > 0)
doThis = playersVIPplus.get(0);
else if (playersVIP.size() > 0)
doThis = playersVIP.get(0);
else doThis = players.get(0);
Bukkit.getPlayer(playerSent.getName()).sendMessage("§4[§6ReviewPlugin§4] §eThis review is for §b" + doThis.getName());
Bukkit.getPlayer(playerSent.getName()).teleport(doThis.getLocation());
reviewsMember.remove(doThis);
if (reviewsMember.size() > 1)
Bukkit.getPlayer(playerSent.getName()).sendMessage("§4[§6ReviewPlugin§4] §eThere are " + reviewsMember.size() + " member reviews left to do.");
else if (reviewsMember.size() == 1)
Bukkit.getPlayer(playerSent.getName()).sendMessage("§4[§6ReviewPlugin§4] §eThere is " + reviewsMember.size() + " member review left to do.");
else
Bukkit.getPlayer(playerSent.getName()).sendMessage("§4[§6ReviewPlugin§4] §eThere are no more Member reviews to do at this time!");
}
else {
Bukkit.getPlayer(playerSent.getName()).sendMessage("§4[§6ReviewPlugin§4] §eThere are no more Member reviews to do at this time!");
}
}
The index out of bounds error was occurring in the for loop, so I have no idea where I am going wrong. This was tested w/o error on a Windows 8 machine but when implemented into a Linux it failed every time with the index out of bounds error.
The above code cannot fail unless some background thread modifies the array in the middle of the loop. Which is most likely the reason for your problem.
Related
I'm trying to program a bug to move around an array attached to a custom Room object, whilst keeping count of how many times each tile has been stepped on.
The Room object is working properly, as are the movement and the counting. However, the bug's coordinates, bugX and bugY, are somehow reverting to 0 after exiting the nextMove method. Their values only revert when exiting the method; even the last line of code in the nextMove method itself uses their new values.
Relevant portion of the method is attached, but other sections can be added upon request.
if (dirNum == 0 && bugY < length-1) //Move up
bugY++;
else if (dirNum == 1 && bugX < width-1) //Move right
bugX++;
else if (dirNum == 2 && bugY > 0) //Move down
bugY--;
else if (dirNum == 3 && bugX > 0) //Move left
bugX--;
else {
System.out.println("Error: Cannot move " + direction + ".");
canMove = false;
dirNum = generator.nextInt(4);
continue;
}
This is the context for the command itself.
while (endSim == false) {
nextMove(bugX, bugY);
System.out.print(room.printRoom() + "\n\nNext move? (y/n) ");
simSentinel = in.next();
if (simSentinel.charAt(0) == 'n')
endSim = true;
}
The declarations where the starting coordinates are assigned aren't inside any loops, let alone where the variable itself is called.
The problem is the one described by #T.J.Crowder in his answer though applied to java.
Variables passed as parameters in java are passed by value. If the value is changed by the method receiving the parameter, the change only affects the value inside that method. The "outside" value doesn't change.
What you can do is to encapsulate the coords in an object and pass the encapsulating object as a parameter.
Then the method will receive the object by value, and change it's state (instead of the value of the object).
For a deeper understanding see this question
EDIT I:
I cleand up the code a bit. Though it is is missing the declaration of room and simSentinel, if you add that you should have a running example.
public class Bug{
public int x=0;
public int y=0;
}
public class SimpleSim {
private int dirNum = 0;
private int length = 20;
private int width = 20;
private boolean canMove = true;
private Random generator = new Random();
private boolean endSim = false;
public static void main(String [] args) {
SimpleSim simpleSim = new SimpleSim();
simpleSim.start();
}
private void start() {
Bug myBug = new Bug();
// Give the bug some initial x, y values.
myBug.x = 0;
myBug.y = 0;
while (endSim == false) {
nextMove(myBug);
System.out.print(room.printRoom() + "\n\nNext move? (y/n) ");
simSentinel = in.next();
if (simSentinel.charAt(0) == 'n')
endSim = true;
}
}
}
public void nextMove(Bug bug){
if (dirNum == 0 && bug.y < length-1) //Move up
bug.y++;
else if (dirNum == 1 && bug.x < width-1) //Move right
bug.x++;
else if (dirNum == 2 && bug.y > 0) //Move down
bug.y--;
else if (dirNum == 3 && bug.x > 0) //Move left
bug.x--;
else {
System.out.println("Error: Cannot move " + "?" + ".");
canMove = false;
dirNum = generator.nextInt(4);
}
}
}
It seems that you are passing your bugX and bugY parameters by value. In this case, changing their value inside the method won't affect their values outside the method.
You may want to make your nextMove method return the new values for bugX and bugY after they are computed so that you can gather them back into your actual bugX and bugY variables
I'm trying to write an AI that never loses at Tic Tac Toe, and I want to use the minimax algorithm to do so. However, when I try to run the program, a stack overflow appears and I can't seem to find what is the error. Could you take a look and tell me what I'm doing wrong? It doesn't go as deep in the recursion I believe, since it should only go through all the possible game outcomes, which go up to 8 moves (since the player is first to play, not the AI). It is probably me doing something wrong, but I can't find anything.
EDIT: Here's the full code, the mechanics function is the main part:
EDIT2: Fixed the constructor
package Packet;
import java.util.*;
import java.util.Scanner;
public class Logic {
public static class TicTacToe{
private int[] currentBoard = new int[9];
private int[] availableSpots = new int [9];
private int emptySpace = 0;
private int playerAI = 1;
private int playerHuman = 2;
void TicTacToe(){
for (int i = 0; i < 9; i++){
this.currentBoard[i] = this.emptySpace;
}
for (int i = 0; i < 9; i++){
this.availableSpots[i] = i;
}
}
private int movesNumber(){
int counter = 0;
for (int i = 0; i < 9; i++){
if (this.currentBoard[i] == this.emptySpace){
counter++;
}
}
return counter;
}
private boolean win(int[] board,int player){
if (
(board[0] == player && board[1] == player && board[2] == player) ||
(board[3] == player && board[4] == player && board[5] == player) ||
(board[6] == player && board[7] == player && board[8] == player) ||
(board[0] == player && board[3] == player && board[6] == player) ||
(board[1] == player && board[4] == player && board[7] == player) ||
(board[2] == player && board[5] == player && board[8] == player) ||
(board[0] == player && board[4] == player && board[8] == player) ||
(board[2] == player && board[4] == player && board[6] == player) ){
return true;
}
else{
return false;
}
}
private int mechanics(int[] newBoard, int player){
if (win(newBoard,this.playerHuman)){
return -10;
}
else if (win(newBoard, this.playerAI)){
return +10;
}
else if (this.movesNumber() == 0){
return 0;
}
ArrayList<Integer> moves = new ArrayList<Integer>();
ArrayList<Integer> scores = new ArrayList<Integer>();
for (int i = 0; i < this.movesNumber(); i++){
int[] possibleBoard = new int[9];
possibleBoard = newBoard;
int availableSpotNumber = i;
int j = i;
while (this.availableSpots[j] == 9){
availableSpotNumber++;
j++;
}
possibleBoard[availableSpotNumber] = player;
if (player == this.playerAI){
scores.add(this.mechanics(possibleBoard, this.playerHuman));
}
else{
scores.add(this.mechanics(possibleBoard, this.playerAI));
}
moves.add(availableSpotNumber);
possibleBoard[availableSpotNumber] = this.emptySpace;
}
int bestMove = 0;
if (player == this.playerAI){
int bestScore = -10000;
for (int i = 0; i < moves.size(); i++){
if (scores.get(i) > bestScore){
bestScore = scores.get(i);
bestMove = i;
}
}
}
else {
int bestScore = 10000;
for (int i = 0; i < moves.size(); i++){
if (scores.get(i) < bestScore){
bestScore = scores.get(i);
bestMove = i;
}
}
}
return moves.get(bestMove);
}
public void printTable(){
System.out.println(this.currentBoard[0] + " | " + this.currentBoard[1] + " | " + this.currentBoard[2]);
System.out.println("- - -");
System.out.println(this.currentBoard[3] + " | " + this.currentBoard[4] + " | " + this.currentBoard[5]);
System.out.println("- - -");
System.out.println(this.currentBoard[6] + " | " + this.currentBoard[7] + " | " + this.currentBoard[8]);
System.out.println();
}
private void fillTable(int position,int player){
this.currentBoard[position] = player;
this.availableSpots[position] = 9;
}
public void startGame(){
while(true){
this.printTable();
Scanner ulaz = new Scanner(System.in);
fillTable(ulaz.nextInt(), this.playerHuman);
this.printTable();
fillTable(this.mechanics(this.currentBoard, this.playerAI), this.playerAI);
ulaz.close();
}
}
public void resetGame(){
for (int i = 0; i < 9; i++){
this.currentBoard[i] = this.emptySpace;
}
for (int i = 0; i < 9; i++){
this.availableSpots[i] = i;
}
}
}
public static void main(String[] args){
TicTacToe game = new TicTacToe();
game.startGame();
}
}
Also, here's the exact errors I get:
Exception in thread "main" java.lang.StackOverflowError
at Packet.Logic$TicTacToe.mechanics(Logic.java:54)
at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
After this part, these parts appear a bunch of times (at least 50)
at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
Line 54:
if (win(newBoard,this.playerHuman)){
Line 84:
scores.add(this.mechanics(possibleBoard, this.playerHuman));
Line 87:
scores.add(this.mechanics(possibleBoard, this.playerAI));
This might or might not be a code issue, as Java is not a fully functional language with it comes to recursion, you might want to see this answer: Does Java 8 have tail call optimization?
Basically, a language that allows for unlimited-depth recursion has to have tail recursion optimization. With tail call optimization, if the return value is the result of exactly the same function with different parameters, the stack will get replaced instead of the new call being added to the stack.
If a language does not have tail call optimization, then you're limited by stack size in how deep your recursion goes, even if the recursive calls have correct termination conditions (note: I haven't analyzed the code in depth, so obviously there might be a problem in the recursive logic itself). If you want to tweak the stack size, use the -Xss Java runtime parameter. Generally, increasing the stack size is a good heuristic (although not a fool-proof method) of checking whether the fault is with the language or with your algorithm.
There's a couple of problems, but here's how you can debug this:
add a StringBuilder debug = new StringBuilder(); field to your class, then change the main loop like this:
int debugLen = debug.length();
debug.append("\nSetting ").append(availableSpotNumber).append(" to ").append(player);
possibleBoard[availableSpotNumber] = player;
try {
if (player == this.playerAI) {
scores.add(this.mechanics(possibleBoard, this.playerHuman));
} else {
scores.add(this.mechanics(possibleBoard, this.playerAI));
}
moves.add(availableSpotNumber);
} catch (StackOverflowError error) {
throw new StackOverflowError(debug.toString());
}
debug.setLength(debugLen);
possibleBoard[availableSpotNumber] = this.emptySpace;
Then you will see what is happening, which will give you a clue what to fix next. For example, the current version is doing this, for initial human move 1:
Setting 0 to 1
Setting 0 to 2
Setting 0 to 1
Setting 0 to 2
etc..
But, if you're too lazy, you can find a fixed version here.
I am writing a chunk of program to play Uno with other classes. My Uno project is almost finished, but I need to be sure that the part which checks to make sure that on moves after a Wild Card is played, I play either a legal card or return a -1. Here is my code:
import java.util.*;
public class AlexaL_UnoPlayer implements UnoPlayer
{
public int play(List<Card> hand, Card upCard, Color calledColor, GameState state)
{
int play = -1;
boolean haveWild = false;
boolean matchesWildCall = false;
int indexOfWild = 0;
//turn number of cards all players are holding into ints for later use
int[] array = state.getNumCardsInHandsOfUpcomingPlayers();
int playerNext = array[0];
int playerTwoNext = array[1];
int playerBefore = array[2];
Color upCardColor = upCard.getColor();
for(int i = 0; i < hand.size(); i++)
{
//see if I have any wilds
if(hand.get(i).getRank().equals(Rank.WILD) || hand.get(i).getRank().equals (Rank.WILD_D4))
{
haveWild = true;
indexOfWild = i;
}
//set upCard color to calledColor if wild or wild_d4 are played
if (upCard.getRank().equals(Rank.WILD) || upCard.getRank().equals(Rank.WILD_D4))
{
upCardColor = calledColor;
}
//always play a card matching rank of upCard, if possible, or play the first in hand which matches color
if(hand.get(i).getColor().equals(upCardColor))
{
if(hand.get(i).getNumber() == upCard.getNumber())
{
play = i;
}
}
//if cornered(no matching number or color), play a wild
else if(haveWild == true)
{
play = indexOfWild;
}
//hold reverse cards until person next after me has less cards than person before me
if(hand.get(i).getRank().equals(Rank.REVERSE) && playerNext < playerBefore)
{
play = i;
}
//play skips when person next to me has less cards than me
if((hand.get(i).getRank().equals(Rank.SKIP) || hand.get(i).getRank().equals(Rank.DRAW_TWO)) && playerNext < hand.size())
{
play = i;
}
}
return play;
}
public Color callColor(List<Card> hand)
{
//strategy: change the color to the one i'm holding the most of
Color changeTo = Color.GREEN;
int numBlues = 0;
int numGreens = 0;
int numReds = 0;
int numYellows = 0;
//find out how many of each color i'm holding
for(int i = 0; i < hand.size(); i++)
{
if(hand.get(i).getColor().equals(Color.BLUE))
{
numBlues++;
}
else if(hand.get(i).getColor().equals(Color.RED))
{
numReds++;
}
else if(hand.get(i).getColor().equals(Color.GREEN))
{
numGreens++;
}
else if(hand.get(i).getColor().equals(Color.YELLOW))
{
numYellows++;
}
}
//find out which i'm holding the most of and call that color
//if no majority, return my favorite color(green)
if(numBlues > numReds && numBlues > numGreens && numBlues > numYellows)
{
changeTo = Color.BLUE;
}
else if(numReds > numBlues && numReds > numGreens && numReds > numYellows)
{
changeTo = Color.RED;
}
else if(numGreens > numBlues && numGreens > numYellows && numGreens > numReds)
{
changeTo = Color.GREEN;
}
else if(numYellows > numBlues && numYellows > numGreens && numYellows > numReds)
{
changeTo = Color.YELLOW;
}
else
{
changeTo = Color.GREEN;
}
return changeTo;
}
}
For some reason, my output is telling me this:
You were given this hand:
0. G7
1. G5
2. G+2
and the up card was: W
and the called color was: YELLOW
and you (wrongly) returned 2.
Valid plays would have included: -1
Can anyone provide some insight on why I am getting this error and how to fix it? Much appreciated!
Based on just this code, it is hard to say what is wrong with your implementation.
Did you try step-by-step debugging of your play function?
Alternately, it would be beneficial to instrument your code with more trace statements to better figure out where the issue might be occurring.
For example:
Every where your play variable gets assigned a value, print its value to console with some context of where you are in code.
if(hand.get(i).getNumber() == upCard.getNumber())
{
play = i;
System.out.println("number match step: play = " + play ); // You can add such a line
}
This should give you an idea as to when play's value is getting mutated to 2 unexpectedly.
Just clutching at straws here, but what are the expected values of getColor and getNumber for wild cards.
In case you have them set to Green or 2 respectively, it might explain the output you are seeing because of the following fragment of code.
//always play a card matching rank of upCard, if possible, or play the first in hand which matches color
if(hand.get(i).getNumber() == upCard.getNumber())
{
play = i;
}
else if(hand.get(i).getColor() == upCardColor)
{
play = i;
}
Is it possible to convert the function go into the non-recursive function? Some hints or a start-up sketch would be very helpful
public static TSPSolution solve(CostMatrix _cm, TSPPoint start, TSPPoint[] points, long seed) {
TSPSolution sol = TSPSolution.randomSolution(start, points, seed, _cm);
double t = initialTemperature(sol, 1000);
int frozen = 0;
System.out.println("-- Simulated annealing started with initial temperature " + t + " --");
return go(_cm, sol, t, frozen);
}
private static TSPSolution go(CostMatrix _cm, TSPSolution solution, double t, int frozen) {
if (frozen >= 3) {
return solution;
}
i++;
TSPSolution bestSol = solution;
System.out.println(i + ": " + solution.fitness() + " " + solution.time() + " "
+ solution.penalty() + " " + t);
ArrayList<TSPSolution> nHood = solution.nHood();
int attempts = 0;
int accepted = 0;
while (!(attempts == 2 * nHood.size() || accepted == nHood.size()) && attempts < 500) {
TSPSolution sol = nHood.get(rand.nextInt(nHood.size()));
attempts++;
double deltaF = sol.fitness() - bestSol.fitness();
if (deltaF < 0 || Math.exp(-deltaF / t) > Math.random()) {
accepted++;
bestSol = sol;
nHood = sol.nHood();
}
}
frozen = accepted == 0 ? frozen + 1 : 0;
double newT = coolingSchedule(t);
return go(_cm, bestSol, newT, frozen);
}
This is an easy one, because it is tail-recursive: there is no code between the recursive call & what the function returns. Thus, you can wrap the body of go in a loop while (frozen<3), and return solution once the loop ends. And replace the recursive call with assignments to the parameters: solution=bestSol; t=newT;.
You need to thinkg about two things:
What changes on each step?
When does the algorithm end?
Ans the answer should be
bestSol (solution), newT (t), frozen (frozen)
When frozen >= 3 is true
So, the easiest way is just to enclose the whole function in something like
while (frozen < 3) {
...
...
...
frozen = accepted == 0 ? frozen + 1 : 0;
//double newT = coolingSchedule(t);
t = coolingSchedule(t);
solution = bestSol;
}
As a rule of thumb, the simplest way to make a recursive function iterative is to load the first element onto a Stack, and instead of calling the recursion, add the result to the Stack.
For instance:
public Item recursive(Item myItem)
{
if(myItem.GetExitCondition().IsMet()
{
return myItem;
}
... do stuff ...
return recursive(myItem);
}
Would become:
public Item iterative(Item myItem)
{
Stack<Item> workStack = new Stack<>();
while (!workStack.isEmpty())
{
Item workItem = workStack.pop()
if(myItem.GetExitCondition().IsMet()
{
return workItem;
}
... do stuff ...
workStack.put(workItem)
}
// No solution was found (!).
return myItem;
}
This code is untested and may (read: does) contain errors. It may not even compile, but should give you a general idea.
OK so I have this HashMap
private Map<String, Player> players = new HashMap<String, Player>();
Here is what I use to remove:
public void destroy() {
players.remove("Red");
os.println(me.getUsername() + "|1|has left|yes|chat");
}
I say Red because it's just a TEST right now. I will get the eventual correct one later. Anyways...
I use THIS to check.
if (e.getKeyCode() == KeyEvent.VK_Q) {
for (Player playert : players.values()) {
c.append("\n < "+playert.getUsername() + " > ");
}
}
When I'm all by myself.. I press Q and I get:
< Dan >
then my friend Red logs in and I Press Q... I get:
< Dan >
< Red >
then he leaves I press Q and I get:
< Dan >
< Red >
So.. how come this isn't working?
Also, here is the code that gets called in init() when a player logs in the game (starts the applet)
public void playerLogin() throws IOException {
Random roll = new Random();
int newNo = roll.nextInt(200);
// me.getUsername() = "Guest #" + roll.nextInt(110);
// String me.getUsername() = getParameter("name");
me = new Player();
me.setUsername(getParameter("name"));
me.setPlayerImage(ImageIO.read(getClass().getResource("me.gif")));
me.setX(256);
me.setY(256);
me.setMap(1);
me.setCommand("move");
players.put(me.getUsername(), me);
repaint();
System.out.println(me.getUsername() + " was added. player: " + me);
os.println(me.getUsername() + "|" + me.getX() + "|" + me.getY() + "|"
+ me.getMap() + "|" + me.getCommand());
attack = 4;
defense = 5;
gold = 542;
level = 1;
exp = 53;
}
In other words, your Applet#destroy() method is not called at the moment you expect it is called? You should use Applet#stop(). The destroy() is only called when the object in question is eligible for GC and/or when the whole browser instance is been closed (and thus not only the current page/tab). JVM may namely keep running as long as the browser instance runs.
When you hit Q... you are checking the contents of players but where is your call to destroy()? Do you explicitly call destroy() anywhere in your code?