Add a node in a gridpane using mouse - java

I'm trying to do a quite easy boardgame (Carcassonne) but I'm having a lot of troubles with the graphic interface. The problem is that I don't see the way to make a relation between the mouse clicks and the gridpane row and columns.
The first tile is given and it's always added to the 100, 100 gridpanes position. You won't see it in the code, but for each tile added if the adjacents are empty it's added a white tile, so it looks like this:
Then, the player is expected to do a legal move ( we're not controlling cheaters, so yeah, it will be a weak game ) in the positions x = 99 y = 100, x = 101 y = 100, x = 100 y = 99, x = 100 y = 101.
But when i click there using the method play() the e.getSceneX(); method returns me the pixel position, and I need a way to convert it to a valid row index. So this is happening:
This is the console output:
tile XCCCC added at 100 100 // this is always given by the program, it's always the same
tile MFFCF added at 391 380
In this case, I clicked to the x = 100 y = 101 gridpane but the mouse returned me the pixel 391, 380.
Any idea?
This is the structure of my code:
public final class GUI extends Application {
private Game _game;
private GridPane _visualBoard;
#Override
public void start(final Stage primaryStage) {
// some stuff setting the gridpane, which will be inside a scrollpane and the scrollpane will be inside a borderpane which will alse have 2 additional VBoxes with the current turn information
play();
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
public void play() {
_visualBoard.setOnMousePressed((MouseEvent e) -> {
double x = e.getSceneX();
double y = e.getSceneY();
_game.doMove(x, y);
});
}
public void insertTile(myTile r, int x, int y) {
myVisualTile rV = new myVisualTile(r);
_visualBoard.add(rV, x, y);
}
And this is the class game:
public class Game {
private GUI _gui;
private List<Player> _players; // An arraylist of players
private int _currentPlayer; // The index of the current player in the ArrayList
private Board _board; // The logical board, totally separeted from the gridpane
private tileStack _stack;
public void doMove(double x, double y) {
int ax = (int) x;
int ay = (int) y;
if (_stack.isEmpty()) {
System.out.println("Game finnished");
//stuff
}
else {
myTile r = _stack.poll(); // takes the first tile of the stack
_gui.insertTile(r, ax, ay);
}
}

public void play() {
_visualBoard.setOnMousePressed((MouseEvent e) -> {
Node source = (Node)e.getTarget() ;
Integer x = GridPane.getColumnIndex(source);
Integer y = GridPane.getRowIndex(source);
_game.doMove(x, y);
});
}
That actualy worked. Thanks everybody!

Related

How can I edit JPanel Graphics in one class?

So I'm trying to program snake on a JFrame and doing all graphical stuff (moving the 'snake', random food generation, etc.) on a JPanel. I'm in the beginning stages so all I'm trying to do right now is move a black square around on my frame using arrow keys. My while loop in the Panel class won't get interrupted by a key press in the Snake class, so is there a way to edit JPanel graphics from the same class with all my other code?
Here's all the code. My Panel class at the bottom follows the template I found here.
public class Snake {
// panel width and height
static int pW;
static int pH;
static int x = 10;
static int y = 10;
static int k;
static JFrame frame = new JFrame("SNAKE");
// getters for panel class
public int getPW() { return pW; }
public int getPH() { return pH; }
public int getX() { return x; }
public int getY() { return y; }
public static void main(String[] args) {
// get screen dimensions
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int sH = (int) screenSize.getHeight();
int sW = (int) screenSize.getWidth();
pW = (int) sW/2;
pH = (int) sH/2;
// initialize frame
frame.setSize (pW/1,pH/1);
frame.setLocation(pW/2,pH/2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addKeyListener( new KeyAdapter() {
public void keyPressed(KeyEvent e) {
k = e.getKeyCode();
switch(k) {
case 38: /* y -= square size */ break; // up
case 40: /* y += square size */ break; // down
case 37: /* x -= square size */ break; // left
case 39: /* x += square size */ break; // right
case 27: System.exit(0);
}
}
});
Panel panel = new Panel();
frame.add(panel);
frame.setVisible(true);
}
}
class Panel extends JPanel {
Snake snake = new Snake();
//square size and separation between squares
int sep = 0;
int size = 50;
// initial location of square on the panel/frame
int x = sep + size;
int y = sep + size;
// holding values to check if x or y have changed
int xH = x;
int yH = x;
public void paint(Graphics g) {
int pW = snake.getPW();
int pH = snake.getPH();
int i; int o;
Color on = Color.BLACK;
Color off = Color.GRAY;
// gray background
g.setColor(Color.GRAY);
g.fillRect(0,0,pW,pH);
// black square initialization
g.setColor(Color.BLACK);
g.fillRect(x, y, size, size);
/* this loop is supposed to check if the black
* rectangle has moved by repeatedly grabbing x & y
* values from the Snake class. When a key is pressed
* and the values change, a gray rectangle is placed at the old location
* and a black one is placed at the new location.
*
* When I run the program, I get stuck in this while loop.
* If I had the while loop in the same class I check for keys,
* I don't think I would have this problem
*/
while(true) {
x = snake.getX();
y = snake.getY();
if(x != xH || y != yH) {
g.setColor(off);
g.fillRect(xH, yH, size, size);
g.setColor(on);
g.fillRect(snake.getX(), snake.getY(), size, size);
xH = x;
yH = y;
}}
}
}
You should never have a while(true) loop in a painting method. This will just cause an infinite loop and your GUI will not be able to respond to events.
Instead you need to add methods to your snake class to move the snake. So when one of the arrow keys is pressed you update the starting position of the snake. Then the method will invoke repaint() and the snake will repaint itself when the paintComponent() method is invoked by Swing.
So your painting code should override paintComponent() not paint() and you should invoke super.paintComponent(g) as the first statement in the method.
Don't call your custom class "Panel", there is an AWT class with that name. Make your class name more descriptive.

Drag nodes like in a patience/Klondike card game

I'm doing a Klondike game. The logic is all working. I'm just having trouble with the UI in javafx.
I've been trying to move/drag the cards from the 'tableau pile' arround without the expected result.
My card is a ImageView with an Image inside. The cards are inside a Pane:
Pane tableau = new Pane();
for (int i = 0; i < n; i++) {
Image img = new Image("resources/images/" + (i + 1) + ".png");
ImageView imgView = new ImageView(img);
imgView.setY(i * 20);
//imgView Mouse Events here
tableau.getChildren().add(imgView);
}
I tried:
imgView.setOnMousePressed((MouseEvent mouseEvent) -> {
dragDelta.x = imgView.getLayoutX() - mouseEvent.getSceneX();
dragDelta.y = imgView.getLayoutY() - mouseEvent.getSceneY();
});
imgView.setOnMouseDragged((MouseEvent mouseEvent) -> {
imgView.setLayoutX(mouseEvent.getSceneX() + dragDelta.x);
imgView.setLayoutY(mouseEvent.getSceneY() + dragDelta.y);
});
This solution dont work because I'm setting the positions so when release the card wont return to where it was, and because the card is colliding with other UI objects.
Another attempt:
imgView.setOnDragDetected((MouseEvent event) -> {
ClipboardContent content = new ClipboardContent();
content.putImage(img);
Dragboard db = imgView.startDragAndDrop(TransferMode.ANY);
db.setDragView(img, 35, 50);
db.setContent(content);
event.consume();
});
In this solution the problems are: the card comes semitransparent, like moving a file, the cursor becames no/forbidden but other than that it works well: no collisions and the card goes to his original place if I release the mouse.
Another problem is that I dont know if I can move more than 1 card with this solution?
My final question is, How can I move a node (in this case an ImageView) or a group of nodes, from one pile to another, like in a Solitaire Card Game?
For knowing the original card position you should use the setTranslateX (and Y) instead of setLayoutX in your mouse handler. So when the user releases the card, you can simply invoke a Transition and let the card fly back to the layout position. If the user releases the card on a valid place, you set the translate coordinates to 0 and change the layout position or use relocate.
If you want to make the cards semitransparent, you could e. g. change the opacity or apply CSS.
By the way, I wouldn't use Clipboardcontent, it seems inappropriate for your needs.
You can move multiple objects with your mouse handling code. You simple have to apply the translation to multiple objects simultaneously. When you drag a pile, you determine the cards on top of the selected card and apply the transition to all of them.
Here's a quick example to show you how it could look like.
Card.java, you'll use an ImageView.
public class Card extends Rectangle {
static Random rand = new Random();
public Card() {
setWidth(100);
setHeight(200);
Color color = createRandomColor();
setStroke(color);
setFill( color.deriveColor(1, 1, 1, 0.4));
}
public static Color createRandomColor() {
int max = 200;
Color color = Color.rgb( (int) (rand.nextDouble() * max), (int) (rand.nextDouble() * max), (int) (rand.nextDouble() * max));
return color;
}
}
Game.java, the application.
public class Game extends Application {
static List<Card> cardList = new ArrayList<>();
#Override
public void start(Stage primaryStage) {
MouseGestures mg = new MouseGestures();
Group root = new Group();
for( int i=0; i < 10; i++) {
Card card = new Card();
card.relocate( i * 20, i * 10);
mg.makeDraggable(card);
cardList.add( card);
}
root.getChildren().addAll( cardList);
Scene scene = new Scene( root, 1600, 900);
primaryStage.setScene( scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
// TODO: don't use a static method, I only added for the example
public static List<Card> getSelectedCards( Card currentCard) {
List<Card> selectedCards = new ArrayList<>();
int i = cardList.indexOf(currentCard);
for( int j=i + 1; j < cardList.size(); j++) {
selectedCards.add( cardList.get( j));
}
return selectedCards;
}
}
MouseGestures.java, the mouse handling mechanism.
public class MouseGestures {
final DragContext dragContext = new DragContext();
public void makeDraggable(final Node node) {
node.setOnMousePressed(onMousePressedEventHandler);
node.setOnMouseDragged(onMouseDraggedEventHandler);
node.setOnMouseReleased(onMouseReleasedEventHandler);
}
EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
dragContext.x = event.getSceneX();
dragContext.y = event.getSceneY();
}
};
EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
Node node = (Node) event.getSource();
double offsetX = event.getSceneX() - dragContext.x;
double offsetY = event.getSceneY() - dragContext.y;
node.setTranslateX(offsetX);
node.setTranslateY(offsetY);
// same for the other cards
List<Card> list = Game.getSelectedCards( (Card) node);
for( Card card: list) {
card.setTranslateX(offsetX);
card.setTranslateY(offsetY);
}
}
};
EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
Node node = (Node) event.getSource();
moveToSource(node);
// same for the other cards
List<Card> list = Game.getSelectedCards( (Card) node);
for( Card card: list) {
moveToSource(card);
}
// if you find out that the cards are on a valid position, you need to fix it, ie invoke relocate and set the translation to 0
// fixPosition( node);
}
};
private void moveToSource( Node node) {
double sourceX = node.getLayoutX() + node.getTranslateX();
double sourceY = node.getLayoutY() + node.getTranslateY();
double targetX = node.getLayoutX();
double targetY = node.getLayoutY();
Path path = new Path();
path.getElements().add(new MoveToAbs( node, sourceX, sourceY));
path.getElements().add(new LineToAbs( node, targetX, targetY));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(1000));
pathTransition.setNode(node);
pathTransition.setPath(path);
pathTransition.setCycleCount(1);
pathTransition.setAutoReverse(true);
pathTransition.play();
}
/**
* Relocate card to current position and set translate to 0.
* #param node
*/
private void fixPosition( Node node) {
double x = node.getTranslateX();
double y = node.getTranslateY();
node.relocate(node.getLayoutX() + x, node.getLayoutY() + y);
node.setTranslateX(0);
node.setTranslateY(0);
}
class DragContext {
double x;
double y;
}
// pathtransition works with the center of the node => we need to consider that
public static class MoveToAbs extends MoveTo {
public MoveToAbs( Node node, double x, double y) {
super( x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
}
}
// pathtransition works with the center of the node => we need to consider that
public static class LineToAbs extends LineTo {
public LineToAbs( Node node, double x, double y) {
super( x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
}
}
}
When you pick a card or a multiple of cards, they'll transition back to their origin.
Here's a screenshot where I dragged the 3rd card from top.
When you check if a card is on a valid destination, you should invoke the fixPosition method. It simply relocates the card, i. e. calculates the position using the translation values, repositions the node and sets its translation to 0.
The tricky part was the PathTransition. It's working from the center of a node, not from the x/y coordinates. Here's a thread regarding that issue to which I replied in case you wish to know more about it.

Finding solution to maze in java

I have a project to have a red dot inside the first box of a maze i randomly generated and the dot is supposed to follow its way through the boxes and find the end of the maze. Now if it hits a dead end, its supposed to go back to where its path started and not go back down that path, that leads to a dead end. i made it so each box represents the #1, this way when the red dot travels over the box, it increments by 1, so it can realize where its been. its always supposed to go to the lowest number possible so it can never go back to the dead ends its already been to. i am able to reach the end of the maze but i come into 2 problems.
the method i wrote that does all this work is the solve() function. I cant understand why 2 things happen...
1st thing is that when the red dot comes to a branch of dead ends, sometimes itll just go to one dead end, to a different dead end , back to the same dead end.. traveling to the same 'numbers' when im trying to have it only go towards the boxes that have 1's or just the lower numbers.
2nd thing is that once it inevitably reaches the end of the maze.. the red dot goes into the green area, where i specifically say in the while loop, it can not be in a green box.
if M[y][x] = 0, its a green box and if its = 1 its a black box. anything higher than 1 will also be inside the box.
your help is highly appreciated as ive been stuck on this problem for hours and cant seem to find out the problem.
the problem persists in the solve() method
import java.awt.*;
import java.awt.event.*;
import java.awt.Graphics;
import javax.swing.*;
public class mazedfs extends JFrame implements KeyListener
{
/* default values: */
private static int bh = 16; // height of a graphical block
private static int bw = 16; // width of a graphical block
private int mh = 41; // height and width of maze
private int mw = 51;
private int ah, aw; // height and width of graphical maze
private int yoff = 40; // init y-cord of maze
private Graphics g;
private int dtime = 40; // 40 ms delay time
byte[][] M; // the array for the maze
public static final int SOUTH = 0;
public static final int EAST = 1;
public static final int NORTH = 2;
public static final int WEST = 3;
public static boolean showvalue = true; // affects drawblock
// args determine block size, maze height, and maze width
public mazedfs(int bh0, int mh0, int mw0)
{
bh = bw = bh0; mh = mh0; mw = mw0;
ah = bh*mh;
aw = bw*mw;
M = new byte[mh][mw]; // initialize maze (all 0's - walls).
this.setBounds(0,0,aw+10,10+ah+yoff);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try{Thread.sleep(500);} catch(Exception e) {} // Synch with system
this.addKeyListener(this);
g = getGraphics(); //g.setColor(Color.red);
setup();
}
public void paint(Graphics g) {} // override automatic repaint
public void setup()
{
g.setColor(Color.green);
g.fill3DRect(0,yoff,aw,ah,true); // fill raised rectangle
g.setColor(Color.black);
// showStatus("Generating maze...");
digout(mh-2,mw-2); // start digging!
// digout exit
M[mh-1][mw-2] = M[mh-2][mw-1] = 1;
drawblock(mh-2,mw-1);
solve(); // this is the function you will write for parts 1 and 2
play(); // for part 3
}
public static void main(String[] args)
{
int blocksize = bh, mheight = 41, mwidth = 41; // need to be odd
if (args.length==3)
{
mheight=Integer.parseInt(args[0]);
mwidth=Integer.parseInt(args[1]);
blocksize=Integer.parseInt(args[2]);
}
mazedfs W = new mazedfs(blocksize,mheight,mwidth);
}
public void drawblock(int y, int x)
{
g.setColor(Color.black);
g.fillRect(x*bw,yoff+(y*bh),bw,bh);
g.setColor(Color.yellow);
// following line displays value of M[y][x] in the graphical maze:
if (showvalue)
g.drawString(""+M[y][x],(x*bw)+(bw/2-4),yoff+(y*bh)+(bh/2+6));
}
void drawdot(int y, int x)
{
g.setColor(Color.red);
g.fillOval(x*bw,yoff+(y*bh),bw,bh);
try{Thread.sleep(dtime);} catch(Exception e) {}
}
/////////////////////////////////////////////////////////////////////
/* function to generate random maze */
public void digout(int y, int x)
{
M[y][x] = 1; // digout maze at coordinate y,x
drawblock(y,x); // change graphical display to reflect space dug out
int dir = (int)(Math.random()*4);
for (int i=0;i<4;i++){
int [] DX = {0,0,2,-2};
int [] DY = {-2,2,0,0};
int newx = x + DX[dir];
int newy = y + DY[dir];
if(newx>=0 && newx<mw && newy>=0 && newy<mh && M[newy][newx]==0)
{
M[y+DY[dir]/2][x+DX[dir]/2] = 1;
drawblock(y+DY[dir]/2,x+DX[dir]/2);
digout(newy,newx);
}
dir = (dir + 1)%4;}
} // digout
public void solve() // This is the method i need help with.
{
int x=1, y=1;
drawdot(y,x);
while(y!=mh-1 || x!=mw-1 && M[y][x]!=0){
int min = 0x7fffffff;
int DX = 0;
int DY = 0;
if (y-1>0 && min>M[y-1][x] && M[y-1][x]!=0){
min = M[y-1][x];
DX = 0;
DY = -1;
}//ifNORTH
if (y+1>0 && min>M[y+1][x] && M[y+1][x]!=0){
min = M[y+1][x];
DY = 1;
DX = 0;
}//ifSOUTH
if (x-1>0 && min>M[y][x-1] && M[y][x-1]!=0){
min = M[y][x-1];
DX = -1;
DY = 0;
}//ifWEST
if (x+1>0 && min>M[y][x+1] && M[y][x+1]!=0){
min = M[y][x+1];
DX = 1;
DY = 0;
}//ifEAST
M[y][x]++;
drawblock(y,x);
x = x+DX;
y = y+DY;
drawdot(y,x);
}//while
// modify this function to move the dot to the end of the maze. That
// is, when the dot reaches y==mh-2, x==mw-2
} // solve
///////////////////////////////////////////////////////////////
/// For part three (save a copy of part 2 version first!), you
// need to implement the KeyListener interface.
public void play() // for part 3
{
// code to setup game
}
// for part 3 you may also define some other instance vars outside of
// the play function.
// for KeyListener interface
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) // change this one
{
int key = e.getKeyCode(); // code for key pressed
System.out.println("YOU JUST PRESSED KEY "+key);
}
} // mazedfs
////////////
// define additional classes (stack) you may need here.
The issue causing the second problem you are facing (dot moving to green box) lies in the while loop conditiony!=mh-1 || x!=mw-1 && M[y][x]!=0 . The condition evaluates to y!=mh-1 ||(x!=mw-1 && M[y][x]!=0) since && has higher precedence over the || and || just needs one of its operand to be true. In your case, y!=mh-1 is still ture at the end of maze. Hence the loop continues and the dot moves into green area. To fix the issue modify the condition as (y!=mh-1 || x!=mw-1) && M[y][x]!=0. Hope this helps.

Moving Rectangle Shapes in JavaFX with a thread

I have a strange problem that I need help with.
This is a very simple application. I have a Rectangle Shape saved in a Car object.
public class Car {
private Rectangle rect;
private TheFourCarDeadlock.direction direction;
public Car(Rectangle r, TheFourCarDeadlock.direction d) {
this.rect = r;
this.direction = d;
}
public void move() {
double xPos;
double yPos;
switch (direction) {
case left:
// make sure x is a positive nr between 0 and 600
xPos = (rect.getX() - 1) % 600;
if (xPos < 0) {
xPos = 600;
}
rect.setX(xPos);
System.out.println(String.format("move left, x: %1.0f", xPos));
break;
case right:
xPos = (rect.getX() + 1) % 600;
rect.setX(xPos);
System.out.println(String.format("move right, x: %1.0f", xPos));
break;
case up:
yPos = (rect.getY() - 1) % 600;
rect.setY(yPos);
break;
case down:
yPos = (rect.getY() + 1) % 600;
rect.setY(yPos);
break;
default:
throw new AssertionError(direction.name());
}
}
}
The class Car move a car object to the left or right depending on the direction that is set.
public class TheFourCarDeadlock extends Application {
int maxWidth = 600;
int maxHeight = 600;
Car carFromLeft;
Car carFromRight;
public static enum direction {
left, right, up, down
};
#Override
public void start(Stage primaryStage) {
// setup
Group root = new Group();
Scene scene = new Scene(root, maxWidth, maxHeight);
// cars
// cars on left side going right
Rectangle leftSide = new Rectangle(0, 350 - 10, 20, 20);
leftSide.setFill(Color.BLUE);
root.getChildren().add(leftSide);
carFromLeft = new Car(leftSide, direction.right);
// cars on right side going left
Rectangle rightSide = new Rectangle(600, 250 + 10, -20, -20);
rightSide.setFill(Color.BLUE);
root.getChildren().add(rightSide);
carFromRight = new Car(rightSide, direction.left);
primaryStage.setTitle("The Four Car Deadlock");
primaryStage.setScene(scene);
primaryStage.show();
Thread t = new Thread(new DrawRunnable());
t.start();
}
public void moveCars() {
carFromLeft.move();
carFromRight.move();
}
private class DrawRunnable implements Runnable {
#Override
public void run() {
try {
while (true) {
Thread.sleep(30);
Platform.runLater(new Runnable() {
#Override
public void run() {
moveCars();
}
});
}
} catch (InterruptedException ex) {
System.out.println("Interrupted");
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
In the main application I create two cars, one going right and one going left. I move each car every 30 ms with a Thread t.
Now, the weird thing that I don't understand is that the carFromLeft works fine and is displayed in the form and then moved to the right as I planned. The carFromRight, that have exactly the same code and made the same way. Just stands still... Even though in the output it prints that the position x of the rectangle is changing like it's supposed to.
In the output I get this:
move left, x: 436
move right, x: 165
move left, x: 435
move right, x: 166
move left, x: 434
move right, x: 167
move left, x: 433
move right, x: 168
move left, x: 432
move right, x: 169
move left, x: 431
move right, x: 170
move left, x: 430
So the rectangles change their x position. One going left and one going right. But only the one moving to the right is updated and drawn in the form... What is going on?
You gave the rect an negative height and width - if you give it a postive one it shows up and moves for me from left to right.
BTW - In JavaFX you should not use threads to implement this feature because you are spamming the system with Platform.runLater calls. You should use an Animation e.g. a TranslateTransition

Position and orientation of robot in a grid

I want to make a 10x10 grid and put the robot in position (10,1) (bottom left). I want this robot to be able to move forward, turn left/right and to pick up/put objects in a grid. When put in any position, there should be number in a grid which shows how many objects is put in this position, just like this:
..........
...1......
..2.......
....3.....
..........
..........
......9...
.....4....
.........1
..........
We will not see the robot in a grid. I have two classes. Class Robot:
public class Robot {
private Area area;
private Robot rob;
public Robot(Area area){
this.area = area;
rob = new Robot(area);
}
public void Right(){
}
public void Left(){
}
public void Forward(){
}
public void Put(){
}
public void PickUp(){
}
public (?) getPosition(){ // should return robot's position
}
}
Class Area:
private int numberOfObjects;
private Robot robot;
private static final int X = 10;
private static final int Y = 10;
private Object [][] area; // grid
public Area(){ // defines a grid and robot
area = new Area[X][Y];
for(int a=0;a<X;a++){
for(int b=0;b<Y;b++)
area[a][b]=".";
}
numberOfObjects = 0; // grid is initially empty
Area ar = new Area();
robot = new Robot(ar);
}
public void Put(int x,int y){ // put the object to position (x,y)
area[x][y]=numberOfObjects++;
}
public void PickUp(int x,int y){ // pick up the object in position (x,y)
if(area[x][y]!=null){
area[x][y]=numberOfObjects--;
}
}
public void PrintAGrid(){
for(int r=0;r<X;r++){
for(int c=0;c<Y;c++)
System.out.print(area[r][c]+" ");
System.out.println();
}
System.out.println();
}
}
How can I put the robot in position (10,1)? How can I declare and set its orientation (i.e. on the right)? I guess it will be easy to write other methods, so I do not focus on it.
There are several issues with your code.
Why do you have an instance of Robot inside the class Robot? You have not used that instance at all!
private Object [][] area; should be int[][] area. You always save int in this, right?
If I understand your requirements correctly, Your implementation of pick and put is not correct.
Here is a help how you can solve the problems. I had to think several times if Robot should be in Grid or it should be the other way. I ended up with Grid in Robot.
May be Grid could be a singleton.
Here is our Grid
public class Grid {
private int[][] numberOfObjects = new int[10][10];
public void put(int x, int y) {
numberOfObjects[y][x]++;
}
public void pick(int x, int y) {
numberOfObjects[y][x]--;
}
}
You can replace parameters int x, int y with a Point.
And here is the robot
public class Robot {
private static final int NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3;
private int direction;
private int x, y;
private Grid grid;
public Robot(Grid grid) {
this.x = 0;
this.y = 0;
this.grid = grid;
direction = NORTH;
}
public void right() {
direction++;
if (direction == 4) {
direction = 0;
}
}
public void left() {
direction--;
if (direction == -1) {
direction = 3;
}
}
public void forward() {
if (direction == NORTH) {
y--;
} else if (direction == SOUTH) {
y++;
} else if (direction == EAST) {
x++;
} else if (direction == WEST) {
x--;
}
}
public void put() {
grid.put(x, y);
}
public void pick() {
grid.pick(x, y);
}
}
You need to represent the curent location with a variable and initialize it to the 10 1 postion, though your array goes 0-9 and 0-9 so this may be 9,0. to store this position maybe try a Point object that contains a Point x,y.
If someone is interested in a JavaScript version, you can have a look at this repo right here. In general:
The robot must have a facing direction (left, up, right, down).
The are three possible commands: left, right, move.
With that being said, the algorithm is quite straightforward:
totalScore = 0
Foreach i in input
computeCurrentDirection()
if input != MOVE: continue
totalScore += i
return totalScore
There are several sweet-tricks that someone might do to optimize the functions. Take a look at switchDirection.
const directionArray = [Directions.RIGHT, Directions.DOWN, Directions.LEFT, Directions.UP];
const switchDirection = (currDirection, command) => {
if (command === Commands.MOVE) {
return currDirection
}
const currDirectionIndex = directionArray.indexOf(currDirection);
if (command === Commands.RIGHT) {
return directionArray[(currDirectionIndex + 1) % 4];
}
return directionArray[((currDirectionIndex - 1) + 4) % 4];
}
Instead of an exhaustive approach, someone might use an array to help compute the upcoming direction of the robot. This significantly reduces the amount of needed code.
Note this implementation can be easily expanded to accommodate any new requirements needed for project expansion. When faced with such questions, try to architect your codebase in a testable and expandable way, because it's usually the case where reviewers are interested in your coding organizational skills, rather than whether you are able to solve the problem or not.

Categories