Pacman Collisions in Java - java

I am making a pacman arcade game on Java but my collisions have problems.
If you see my image
here my pacman sprite stands still (no x or y movement) when visiting a corner or when trying to turn back the direction it came (ie goes left but does not go right again). I understand this is because I set my xMovement to 0 and yMovement to 0 if a collision is detected (see second code block under collide()).
How would I allow the pacman sprite to move the other way (ie it comes from the left and I want it to go right) or traverse a corner if my collision() does not allow this?
Below is my draw method in the App.java class which draws the player based on the user's input. The keys wasd correspond with up, left, down, right respectively. this.direction is only used so the player does not waste a move nor go through a wall when a collision happens. *Note, I put (this.player.x_ord + 2) % 16 == 0 because my pacman image is not a 16x16 image unlike my walls which are.
public void draw() { // This is an infinite loop
mapDraw(); // this draws my map constantly so I do not have multiple pacman sprites drawn
this.player.tick(); // see second code below for details
if (keyPressed){ // Used wasd rather than arrow keys
if (key == 's' && this.direction != 's' && (this.player.x_ord + 2) % 16 == 0 &&
(this.player.y_ord + 4) % 16 == 0){ // We dont want Player to turn ever on a non 16 divisible area
this.player.p = this.loadImage("src/main/resources/playerDown.png");
this.player.yMovement = this.player.speed;
this.player.xMovement = 0;
this.direction = 's';
}
else if (key == 'w' && this.direction != 'w' && (this.player.x_ord + 2) % 16 == 0 &&
(this.player.y_ord + 4) % 16 == 0){
this.player.p = this.loadImage("src/main/resources/playerUp.png");
this.player.yMovement = -this.player.speed;
this.player.xMovement = 0; // I do not want my pacman to move diagonally so thats why
this.direction = 'w';
}
else if (key == 'd' && this.direction != 'd' && (this.player.x_ord + 2) % 16 == 0 &&
(this.player.y_ord + 4) % 16 == 0){
this.player.p = this.loadImage("src/main/resources/playerRight.png");
this.player.xMovement = this.player.speed;
this.player.yMovement = 0;
this.direction = 'd';
}
else if (key == 'a' && this.direction != 'a' && (this.player.x_ord + 2) % 16 == 0 &&
(this.player.y_ord + 4) % 16 == 0){
this.player.p = this.loadImage("src/main/resources/playerLeft.png");
this.player.xMovement = -this.player.speed;
this.player.yMovement = 0;
this.direction = 'a';
}
}
this.player.draw(this); //see second code below for details
}
Below is my player.java class
*Note again that this.x_ord + 2 == w.x_pos + 16 && this.y_ord + 4 == w.y_pos is offset because of my pacman sprite is larger than my 16x16 walls.
public void tick(){
// //logic
this.detectCollision();
if (this.isLiving){
this.y_ord += this.yMovement;
this.x_ord += this.xMovement;
}
}
public void draw(PApplet a){ //just draw the sprite
if (this.isLiving){
a.image(this.p, this.x_ord, this.y_ord);
}
}
public void collide(boolean isX){ // Is it an x or y collision
if (isX == true){ // If it moves left or right into a wall
this.xMovement = 0;
}
else if (isX == false){ // If it moves up or down into a wall
this.xMovement = 0;
}
}
public void detectCollision(){
for (Walls w: this.wallLocations){ // A list of wall locations from a .txt file
if (this.x_ord + 2 == w.x_pos + 16 && this.y_ord + 4 == w.y_pos){ // Detect left movement into right wall piece
collide(true);
}
if (this.x_ord + 2 + 16 == w.x_pos && this.y_ord + 4 == w.y_pos){ // Detect right movement into left wall piece
collide(true);
}
if (this.y_ord + 4 == w.y_pos + 16 && this.x_ord + 2 == w.x_pos){ // Detect up movement into bottom wall piece
collide(false);
}
if (this.y_ord + 4 + 16 == w.y_pos && this.x_ord + 2 == w.x_pos){ // Detect down movement into top wall piece
collide(false);
}
}
Any help to my problem is much appreciated.

I didn't analyze your code deeply but it seems to me that your main problem is that collide method considers only 2 cases, vertical movement or horizontal movement. If you want to have movement in 4 different directions that method need to have 4 different states.
To achieve that you could create an enum representing direction. Then in detectCollision pass appropriate Direction into collide. Finally, in the collide consider 4 different directions. For example, if there is barrier on the right, xMovement need to be non-positive. The collide method could look like so:
public void collide(Direction direction){
if (direction == Direction.RIGHT){
this.xMovement = Math.min(0, this.xMovement);
}
if (direction == Direction.LEFT){
this.xMovement = Math.max(0, this.xMovement);
}
if (direction == Direction.UP){
this.yMovement = Math.min(0, this.yMovement);
}
if (direction == Direction.DOWN){
this.yMovement = Math.max(0, this.yMovement);
}
}

Related

Value of Variable Keeps Resetting Every Time The Loop Runs (Java)

I'm currently working on a homework assignment for my Java OOP class. The assignment is that a mouse is trapped midway in a 30ft long pipe. The mouse needs to move randomly with a 50% chance of going left or right. The mouse can only move a random distance between a min of 3ft and a max distance of 8ft for each move made. The program should keep track of the distance that the mouse is from the left and right ends of the pipe after each move and once it has reached one end of the pipe, the loop should end and it should print out that the mouse has reached whatever end it reached. I'm using the variable fromendL to keep track of the mouse's distance from the left end and fromendR for the other end. The problem i'm encountering is that every time the loop runs it's resetting the values of each variable so and it's never giving me the distance over the course of multiple loops. Everything I believe I have working fine, although it might not be the most efficient way (i'm still fairly new to programming).
I'll attach the code below:
class Main {
public static void main(String[] args)
{
int fromendL;
int fromendR;
int tMin = 3;
int tMax = 8;
int direction;
int travel;
int travelR = 15;
int travelL = 15;
boolean escaped = false;
while (!escaped)
{
direction = (int)(Math.random()* 2 + 1);
travel = (int)(Math.random() * (tMax - tMin) + 3);
if (direction == 1)
{
fromendL = 15 - travel;
fromendR = 30 - 15 + travel;
travelL = travelL - travel;
System.out.println("The mouse has moved: " + travel + " ft to the left" );
System.out.println("The mouse is " + fromendL +" ft from The Left End");
System.out.println("The mouse is " + fromendR +" ft from The Right End\n");
if(travelL == 0 || travelL < 0)
{
escaped = true;
System.out.println("The Mouse has escaped the Left end of the Pipe!");
}
else if (travelR == 30 || travelR > 30)
{
escaped = true;
System.out.println("The Mouse has escaped the Right end of the Pipe!");
}
}
else if (direction == 2)
{
fromendL = 15 + travel;
fromendR = 30 - 15 - travel;
travelR = travelR + travel;
System.out.println("The mouse has moved: " + travel + " ft to the right");
System.out.println("The mouse is " + fromendL +" ft from The Left End");
System.out.println("The mouse is " + fromendR +" ft from The Right End\n");
if(travelR == 30 || travelR > 30)
{
escaped = true;
System.out.println("The Mouse has escaped the Right end of the Pipe!");
}
else if (travelL == 0 || travelL < 0)
{
escaped = true;
System.out.println("The Mouse has escaped the Left end of the Pipe!");
}
}
}
}
}
The following piece of code should solve the original problem. Please analyze it to find some of the improvements compared to your code.
Instead of using two variables to keep the position (fromendLand fromendR), I use a single one (pos). If I know the length of the pipe (which doesn't change) and the position starting from the left side of the pipe, the distance to the right end can be calculated.
Constructs like if (a == 0 || a < 0) are better written like if (a <= 0) in my opinion.
I use the direction as +1 or -1. Just like in mathematics, the negative direction is like going to the left, the positive direction is like going to the right.
The reason that your variables are reset every time lies in
fromendL = 15 - travel;
fromendR = 30 - 15 + travel;
travelL = travelL - travel;
You start from 15 resp 30 over and over again instead of using the last position of the mouse.
My code looks like
(I use tabs for indentation; my eyes are too old to see the subtle 2-character indentations ;) :
class Main {
public static void main(String[] args)
{
static final int tMin = 3;
static final int tMax = 8;
static final int pLength = 30;
int direction;
int travel;
int pos = pLength / 2;
boolean escaped = false;
while (!escaped) {
direction = (int)(Math.random() * 2);
if (direction == 0) direction = -1;
travel = ((int)(Math.random() * (tMax - tMin)) + tMin) * direction;
pos += travel;
System.out.println("The mouse has moved: " + Math.abs(travel) + " ft to the " + (travel > 0 ? "right" : "left"));
System.out.println("The mouse is " + pos +" ft from The Left End");
System.out.println("The mouse is " + (pLength - pos) + " ft from The Right End\n");
if (pos >= pLength || pos <= 0) {
System.out.println("The Mouse has escaped the " + (pos <= 0 ? "Left" : "Right") + " end of the Pipe!");
escaped = true;
}
}
}
}
The ? is a ternary operator. It tests the condition and if true, the expression evaluates to the value directly following the question mark. If false the expression evaluates to the value following the colon. Use it with care, many people don't like it and think it's confusing. And for that reason I've put it between parenthesis so it's clear where the construct starts and ends.
Since pos is either less or equal zero (escaped to the left) or greater or equal 30 (escaped to the right), I only have to test which of both it is. If I know the mouse didn't escape to the left it must have escaped to the right. (The condition of the if already guarantees that the mouse has escaped).

tic tac toe horizontal/vertical and diagonal check not wokring - java

I am writing a tic tac toe game and everything seems to work except the checks (horizontal/vertical and diagonal). I am using an array (int [3][3]) to make the board.
These are my checks:
private boolean wonStraightLines( int player)
{
boolean answer = false;
if (
((board[0][0] & board[0][1] & board[0][2]) == (player * 3)) ||
((board[1][0] & board[1][1] & board[1][2]) == (player * 3)) ||
((board[2][0] & board[2][1] & board[2][2]) == (player * 3)) ||
((board[0][0] & board[1][0] & board[2][0]) == (player * 3)) ||
((board[0][1] & board[1][1] & board[2][1]) == (player * 3)) ||
((board[0][2] & board[1][2] & board[2][2]) == (player * 3))
)
{
answer = true;
}
else {
answer = false;
}
return answer;
}
and for the diagonal:
private boolean wonDiagonal( int player)
{
boolean answer = false;
if (
((board[0][0] & board[1][1] & board[2][2]) == (player * 3)) || ((board[0][2] & board[1][1] & board[2][0]) == (player * 3))
)
{
answer = true;
}
else {
answer = false;
}
return answer;
}
when I run the program whenever X or O get 3 from any direction the game keeps running rather than throwing out a "you win" message. Any help would be appreciated. Not sure if any other parts of the code are needed or not.
EDIT: I also tried using the + instead of the & between the board array values but did not work as well.
I'm assuming there are 3 unique values for the states of each element such as for example:
board[row][col] = 0 // no entry
board[row][col] = 1 // player 1
board[row][col] = 2 // player 2
Without being clever a horizontal check for player (using row-major structure) would look like:
(board[0][0] == player && board[0][1] == player && board[0][2] == player)
and repeat for each row.
And similar for vertical, repeating for each column:
(board[0][0] == player && board[1][0] == player && board[2][0] == player)
And one diagonal:
(board[0][0] == player && board[1][1] == player && board[2][2] == player)
If you were determined to use an arithmetic operation then you'd have to change the "player" values to avoid overlap, as in player 1 == 1 and player 2 == 4, such as:
board[row][col] = 0 // no entry
board[row][col] = 1 // player 1
board[row][col] = 4 // player 2
Then you could do something like for a horizontal row:
((board[0][0] + board[0][1] + board[0][2]) == (player * 3))
Note in Java 8 and later adding an int array (a row or column in your case) can be slightly more succinct:
// sum the first row
(IntStream.of(board[0]).sum() == (player * 3))
Now if you really wanted to use the bit-wise "and" operation then this is your check assuming the initial element values (0,1,2) as stated at top:
// check if the player's "bit" is set in all elements of first row.
(board[0][0] & board[0][1] & board[0][2]) == player

While loop not checking both conditions?

I am fairly new to programming and have decided to take on a project where I create a game in the console. The user has the options to move up, down, left, or right from the center of an area that is a 3x3 grid. One of the x,y locations is marked a 'bad' square and the game ends when the user's x and y are equal to that of the bad square's. The bad squares location is x = 1 and y = 3.
The problem I have is that when the user enters Up or Left (hence the users y becomes 3 or the users x becomes 1) and the game ends even though one of the other axis values does not match the bad squares.
Here is my code:
public static void main (String[]args){
//scanner
Scanner userIn = new Scanner(System.in);
//string that will get users value
String movement;
//strings that are compared to users to determine direction
String up = "Up";
String down = "Down";
String left = "Left";
String right = "Right";
//starting coordinates of user
int x = 2;
int y = 2;
//coordinates of bad square
int badx = 1;
int bady = 3;
//message telling user options to move (not very specific yet)
System.out.println("Up, Down, Left, Right");
//do while loop that continues until
do {
movement = userIn.nextLine();
//checking user input and moving them accordingly
if (movement.equals(up)) {
y++;
} else if (movement.equals(down)) {
y--;
} else if (movement.equals(left)) {
x--;
} else if (movement.equals(right)) {
x++;
} else {
System.out.println("Unacceptable value");
}
//checking if user is out of bounds, if user tries to leave area, x or y is increased or decreased accordingly
if (x < 0 || y < 0 || x > 3 || y > 3) {
System.out.println("Out of bounds");
if (x < 0) {
x++;
} else if (y < 0) {
y++;
} else if (x > 3) {
x--;
} else if (y > 3) {
y--;
}
}
//message showing user x and y coordinates
System.out.println("x =" + x + " y =" + y);
} while (y != bady && x != badx); //what checks to see if user has come across the bad square
//ending message (game ends)
System.out.println("Bad Square. Game over.");
}
Your while(y != bady && x != badx) test tests y isn't bad AND x isn't bad therefore it only takes one of these to be false for your loop to cease.
An easy fix might be to swap your logic around a little.
while(!(y == bady && x == badx))
If you think about how your conditional statement is phrased while(y != bady && x != badx) you will see that when either x = 1 or y = 3, one of the sides in the AND statement evaluates to false and causes the whole condition to be false. You could handle it by instead writing:
while(y != bady || x != badx)
Just set logic OR in condition
while(y != bady || x != badx);
&& matters that both conditions should be true

Check if a given sequence of moves for a robot is circular or not in Java

I am working on below task:
Given a sequence of moves for a robot, check if the sequence is circular or not. A sequence of moves is circular if first and last positions of robot are same.
A move can be on of the following.
G - Go one unit
L - Turn left
R - Turn right
Examples:
Input: path[] = "GLGLGLG"
Output: Given sequence of moves is circular
Input: path[] = "GLLG"
Output: Given sequence of moves is circular
The movements described in the input string are repeated for an infinite time. Your task is to find if there exists a circle, whose radius is some positive real number R,
such that the robot never leaves it. If such a circle exists return "YES" otherwise "NO"
I found a solution for this task :
public class Circle {
String check(String commands) {
int initialX = 0;
int initialY = 0;
int x = 0;
int y = 0;
String direction = "north";
for (int i = 0; i < commands.length(); i++) {
if (direction.equals("north")) {
if (commands.charAt(i) == 'G') {
y++;
} else if (commands.charAt(i) == 'L') {
direction = "west";
} else if (commands.charAt(i) == 'R') {
direction = "east";
} else {
System.out.println("Wrong command");
}
} else if (direction.equals("east")) {
if (commands.charAt(i) == 'G') {
x++;
} else if (commands.charAt(i) == 'L') {
direction = "north";
} else if (commands.charAt(i) == 'R') {
direction = "south";
} else {
System.out.println("Wrong command");
}
} else if (direction.equals("south")) {
if (commands.charAt(i) == 'G') {
y--;
} else if (commands.charAt(i) == 'L') {
direction = "east";
} else if (commands.charAt(i) == 'R') {
direction = "west";
} else {
System.out.println("Wrong command");
}
} else if (direction.equals("west")) {
if (commands.charAt(i) == 'G') {
x--;
} else if (commands.charAt(i) == 'L') {
direction = "south";
} else if (commands.charAt(i) == 'R') {
direction = "north";
} else {
System.out.println("Wrong command");
}
}
}
if (direction.equals("north") && (((x-initialX)*(x-initialX) + (y-initialY)*(y-initialY)) > 0)) {
return "NO";
} else {
return "YES";
}
}
}
Everything seems perfect, but I am not able to understand the condition:
if (direction.equals("north") && (((x-initialX)*(x-initialX) + (y-initialY)*(y-initialY)) > 0))
Can you please help me in understanding why we need to return NO for this case, what the formula && (((x-initialX)*(x-initialX) + (y-initialY)*(y-initialY)) > 0 indicates? and why the condition is checking only for direction "north" and not for other directions.
The last condition could be shortened to:
if (direction.equals("north") && (x != 0 || y != 0))
This condition means that after given sequence of steps robot has initial direction but not the initial position. In this case, this sequence shifts the position of the robot by (x, y). That means that after n repetitions of this sequence robot will have position (n*x, n*y). That is not bound by any radius when x != 0 || y != 0.
When both x and y are equal to zero, the robot has the initial direction and initial position after the given sequence of steps. That is a cycle and the answer is "Yes".
Otherwise, the direction of the robot has changed after the sequence of steps. There are two possibilities:
The direction has changed to the opposite (south). Let's assume that after the sequence of steps robot shifted to coordinates (x, y). But when we repeat this sequence in opposite direction coordinates will be changed by (-x, -y) and we will return to the (0, 0) coordinates with the initial direction.
The direction has changed to west or east. In this case, we will return to the initial position with the initial direction after four sequences of steps. For example, let's assume that direction was changed to east and position is (x, y) after the first sequence then:
Direction | Coordinates
-----------+--------------
north | (0, 0)
east | (x, y)
south | (x+y, y-x)
west | (y, -x)
north | (0, 0)

testing tic tac toe win condition [duplicate]

This question already has answers here:
Algorithm for Determining Tic Tac Toe Game Over
(26 answers)
Closed 9 years ago.
I'm looking for the most efficient java way to test if somebody has won at tic tac toe. The data is in a 2d array like so...
char[][] ticTacToe =
{{'X',' ','O'},
{'O','X','O'},
{'X',' ','X'},};
I know this isn't the professional way to initialize an array but I'm just testing here.
The best I can do for right now is an exhaustive if/else tree.
Here's one of those trees...
if (ticTacToe[1][1] == 'X'){
if (ticTacToe[0][0] == 'X'){
if (ticTacToe[2][2] == 'X'){
System.out.println("X wins");
}
}
else if (ticTacToe[0][1] == 'X'){
if (ticTacToe[2][1] == 'X'){
System.out.println("X wins");
}
}
else if (ticTacToe[1][0] == 'X'){
if (ticTacToe[1][2] == 'X'){
System.out.println("X wins");
}
}
else if (ticTacToe[2][0] == 'X'){
if (ticTacToe[0][2] == 'X'){
System.out.println("X wins");
}
}
}
This one only cares about what's in the middle
This is very basic and I want to improve it as far as minimizing lines of code goes.
Just for fun, keep two numbers, starting as zeros, one for X, one for O. Update them by oring with the moves. To check for a winner, first and, then xor with the mask.
277 & 273 ^ 273
0 ==> we have a winner.
276 & 273 ^ 273
1 ==> not.
277 == parseInt("100010101",2)
273 == parseInt("100010001",2)
276 == parseInt("100010100",2)
For more fun, here's an example that plays O in your favorite JavaScript console:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<body>
<script>
var x = 0, o = 0, count = 0, w = 0
ws = [0007,0070,0700,0111,0222,0444,0124,0421]
function t1(v){
var w1 = 0
for (var i in ws)
w1 |= !(v & ws[i] ^ ws[i])
return w1
}
function t(i){
var ot = count % 2, m = 1 << (9 - i), bd = x | o
if (!ot && (i > 9 || i < 1 || i != Math.floor(i)))
return "Out of bounds."
else if (m & bd)
return "Position taken."
if (ot){
var n1 = 0, a1 = -2
while (bd & (1 << n1))
n1++
var n = n1
while (n1 < 9){
var m1 = 1 << n1
if (!(bd & m1)){
var bt = -mx(x,o | m1,count + 1)
if (bt > a1){
a1 = bt
n = n1
}
}
n1++
}
w = t1(o |= 1 << n)
}
else
w = t1(x |= m)
var b = "\n", p = 0400
while (p > 0){
if (p & x)
b += "X"
else if (p & o)
b += "O"
else b += "."
if (p & 0110)
b += "\n"
p >>= 1
}
if (w)
b += "\n\n" + (ot ? "O" : "X") + " wins!"
else if (!(bd ^ 0777))
b += "\n\nDraw."
if (!ot){
console.log(b + '\n\n"""')
count++
console.log(t(-1))
count++
}
else
return b + "\n"
return '"'
}
function mx(x1,o1,c1){
var ot1 = c1 % 2, w1 = ot1 ? t1(x1) : t1 (o1),
b1 = x1 | o1, p = 0400
if (w1)
return -1
if (!(b1 ^ 0777))
return 0
var a = -2
while (p > 0){
if (!(b1 & p))
a = Math.max(a,-mx(ot1 ? x1 : x1 | p,ot1 ? o1 | p : o1,c1 + 1))
p >>= 1
}
return a
}
console.log(' Plays O!'
+ '\nTo play, type t(MOVE); MOVE is from 1-9')
</script>
</body>
</html>
Mark board as 3x3 magicSquare and you have win when sum in line is 15.
It's a bit verbose, but I think this is probably the most efficient way to do it (unless someone can come up with a clever way to check both diagonals at once).
public class TicTacToe
{
char[][] ticTacToe =
{{'X',' ','O'},
{'O','X','O'},
{'X',' ','X'},};
private Character winner = null;
public Character getWinner()
{
return this.winner;
}
public boolean isSolved()
{
this.checkSolved();
return this.winner != null;
}
private void checkSolved()
{
for(int i = 0; i < ticTacToe.length; i++)
{
Character win = checkRow(i);
if(win != null || (win = checkColumn(i)) != null)
{
this.winner = win;
return;
}
}
//Check diagonal top left to bottom right
if(this.ticTacToe[0][0] != ' ')
{
if(this.ticTacToe[0][0] == this.ticTacToe[1][1] &&
this.ticTacToe[1][1] == this.ticTacToe[2][2])
{
this.winner = this.ticTacToe[0][0];
}
}
//Check diagonal top right to bottom left
else if(this.ticTacToe[0][2] != ' ')
{
if(this.ticTacToe[0][2] == this.ticTacToe[1][1] &&
this.ticTacToe[1][1] == this.ticTacToe[2][0])
{
this.winner = this.ticTacToe[0][2];
}
}
}
private Character checkRow(int row)
{
if(this.ticTacToe[row][0] == ' ')
{
return null;
}
if(this.ticTacToe[row][0] == this.ticTacToe[row][1] &&
this.ticTacToe[row][1] == this.ticTacToe[row][2])
{
return this.ticTacToe[row][0];
}
return null;
}
private Character checkColumn(int column)
{
if(this.ticTacToe[0][column] == ' ')
{
return null;
}
if(this.ticTacToe[0][column] == this.ticTacToe[1][column] &&
this.ticTacToe[1][column] == this.ticTacToe[2][column])
{
return this.ticTacToe[column][0];
}
return null;
}
public static void main(String[] args)
{
TicTacToe ttt = new TicTacToe();
if(ttt.isSolved())
{
System.out.println(ttt.getWinner()); // X
}
}
}
For a player, say 'x', there are 8 ways to win and each corresponds to 3 'x' in a row/column/diagonal.
Hence, you can create an array of length 8 and each item corresponds to the number of 'x' in that row/column/diagonal.
When the player chooses a move, then you update the array and check whether there exists 3 in the array.
Although it needs more space, it is easier to generalize to a large board.
There are four different ways to win at tick-tack-toe:
form a horizontal line
form a vertical line
form a diagonal line from the upper-left to the lower-right corner
form a diagonal line from the lower-left to the upper-right corner
All of these four win-conditions can be solved with a for-loop. The advantage of this solution is that it can be applied to any matrix-size.

Categories

Resources