I'm trying to make a connect four game sumulation.
The program should have three threads - player 1, player 2 and game controller.The game controller thread has the responsibility of transfering control from one player to the other, has to monitor if a thread takes more than 5 second to execute, check if there is a winner and so on.
The interface the player classes must implement is:
public interface Player extends Runnable {
public int nextMove(int otherPlayerLastMove);
public void gameOver();
}
The method nextMove return the number of the column the player puts his next token in, and takes as a paramether the number of the column the oposing player put his last token.
The method gameOver must be called from the game controller thread to indicate end of the game and releasing of all resources from the player.
I don't have a problem with implementing the logic of the game it self, but I'm faceing a problem design wise. I just can't put my mind on what classes do I need and how they should interact. The obvious classes are PlayerImpl and GameController - which I think should keep the table for the game ( a 2D char array) and implement the checking logic. Or do I need a third class which contains only the table and to which the other two have access?
The basic code is here:
public class GameController implements Runnable{
private static char [][] table;
private void initTable(){
table = new char[6][7];
for (int i = 0; i < table.length; i++) {
for (int j = 0; j < table[i].length; j++) {
table[i][j] = '*';
}
}
}
public void printTable(){
for (int i = 0; i < table.length; i++) {
for (int j = 0; j < table[i].length; j++) {
System.out.print(table[i][j] + " ");
}
System.out.println();
}
}
private char checkWinner(){
//check for horizontal line
for (int i = 0; i < table.length; i++) {
for (int j = 0; j < 4; j++) {
if ( table[i][j] != '*' && table[i][j+1] != '*' && table[i][j+2] != '*' && table[i][j+3] != '*' &&
table[i][j] == table [i][j+1] && table[i][j+1] == table[i][j+2] && table[i][j+2] == table[i][j+3])
return table[i][j];
}
}
//check for vertical line
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 7; j++) {
if ( table[i][j] != '*' && table[i+1][j] != '*' && table[i+2][j] != '*' && table[i+3][j] != '*' &&
table[i][j] == table [i+1][j] && table[i+1][j] == table[i+2][j] && table[i+2][j] == table[i+3][j])
return table[i][j];
}
}
// left to right diagonals
for (int i = 0; i < 3; i++) {
for (int j = 3; j < 7; j++) {
if ( table[i][j] != '*' && table[i+1][j-1] != '*' && table[i+2][j-2] != '*' && table[i+3][j-3] != '*' &&
table[i][j] == table [i+1][j-1] && table[i+1][j-1] == table[i+2][j-2] && table[i+2][j-2] == table[i+3][j-3])
return table[i][j];
}
}
// right to left diagonals
for (int i = 0; i < 2; i++) {
for (int j = 3; j >=0; j--) {
if ( table[i][j] != '*' && table[i+1][j+1] != '*' && table[i+2][j+2] != '*' && table[i+3][j+3] != '*' &&
table[i][j] == table [i+1][j+1] && table[i+1][j+1] == table[i+2][j+2] && table[i+2][j+2] == table[i+3][j+3])
return table[i][j];
}
}
return 0;
}
public void addToken(int column, char token){
for (int i = table.length ; i >= 0 ; i--) {
if(table[i][column] == '*'){
table[i][column] = token;
break;
}
}
}
#Override
public void run() {
// TODO Auto-generated method stub
}
}
So how would you make the design of such a problem? An explanation or just a UML diagram would be great. Thanks in advance :)
The fact that you have methods on your Runnable tells me you are kinda going for an actor model.
This just means conceptually, you have the players and a controller, all having their own thread (they are all "actors"), and communicate through sending messages. In your case, you are doing that by accepting method calls (nextMove, gameOver).
Here is something that gets your code closer to an actor pattern.
class User extends Runnable {
int userId;
Controller controller;
Queue<Message> msgQueue;
void nextMove(int whoMoved, int whatMove){
msgQueue.offer(new NextMove(whoMoved, whatMove));
}
void gameOver(){
msgQueue.offer(new GameOver());
}
run(){
while(true){
Message msg = msgQueue.poll();
if(msg != null){
// deal with it
// Maybe send message to controller
controller.nextMove(new NextMove(userId, 4));
} else {
// Do something else, like talking to user
// sleep to avoid hogging CPU
Thread.sleep(10);
}
}
}
}
The code has many problems (like that fact that it will scale terribly, abstraction not being great etc. etc.), but I hope it illustrates the approach. Typical real actor model implementation use green threads to tackle scalability and provide standardised way to send and receive messages (e.g. see Akka, Erlang).
Related
I have basically everything in place to finish the tic tac toe game I've been working on, but am having trouble checking to see who won the game. Essentially, I'm trying to see if somebody won the game, and if they did, then to display a message saying which player won.
I've tried just brute-force checking every JButton row/column/diagonal but it doesn't seem to be working. I have the JButtons layed out in a 3 by 3 grid btw.
if((gameButton[0].getText().equals("X") && gameButton[1].getText().equals("X") && gameButton[2].getText().equals("X"))||
(gameButton[3].getText().equals("X") && gameButton[4].getText().equals("X") && gameButton[5].getText().equals("X"))||
(gameButton[6].getText().equals("X") && gameButton[7].getText().equals("X") && gameButton[8].getText().equals("X"))||
(gameButton[0].getText().equals("X") && gameButton[3].getText().equals("X") && gameButton[6].getText().equals("X"))||
(gameButton[1].getText().equals("X") && gameButton[4].getText().equals("X") && gameButton[7].getText().equals("X"))||
(gameButton[2].getText().equals("X") && gameButton[5].getText().equals("X") && gameButton[8].getText().equals("X"))||
(gameButton[0].getText().equals("X") && gameButton[4].getText().equals("X") && gameButton[8].getText().equals("X"))||
(gameButton[2].getText().equals("X") && gameButton[4].getText().equals("X") && gameButton[6].getText().equals("X"))) {
wonLabel.setText("Player X has won!");
}
else if((gameButton[0].getText().equals("O") && gameButton[1].getText().equals("O") && gameButton[2].getText().equals("O"))||
(gameButton[3].getText().equals("O") && gameButton[4].getText().equals("O") && gameButton[5].getText().equals("O"))||
(gameButton[6].getText().equals("O") && gameButton[7].getText().equals("O") && gameButton[8].getText().equals("O"))||
(gameButton[0].getText().equals("O") && gameButton[3].getText().equals("O") && gameButton[6].getText().equals("O"))||
(gameButton[1].getText().equals("O") && gameButton[4].getText().equals("O") && gameButton[7].getText().equals("O"))||
(gameButton[2].getText().equals("O") && gameButton[5].getText().equals("O") && gameButton[8].getText().equals("O"))||
(gameButton[0].getText().equals("O") && gameButton[4].getText().equals("O") && gameButton[8].getText().equals("O"))||
(gameButton[2].getText().equals("O") && gameButton[4].getText().equals("O") && gameButton[6].getText().equals("O"))) {
wonLabel.setText("Player O has won!");
}
I expected this to output a message of which player won, but when I interacted with the GUI and purposely made a certain row/column/diagonal either all "X" or "O", nothing happens. Any feedback/recommendations to make this more efficient would be welcome.
Might I suggest doing something like this, storing the text as a boolean array. After each time the button is pressed, set the point in the array to be true (if X) or false (if O). I'm going to assume that you already have a turn counter, with a boolean, it'll be referenced later.
Make sure that this boolean array is global!!!
boolean[3][3] check = new boolean[3][3];
In your actionEventListener having this run,
public void actionPerformed (ActionEvent e){
Object source = e.getSource();
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++){
if (source == board[i][j], turn == true){
check[i][j] = true;
}
else{
check[i][j] = false;
}
}
}
}
After this, you can probably just have this method, which runs after each turn, or however you see fit.
private void win (){
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
int winO = 0;
int winX = 0;
for (int x = 0; x < 2; x++)
{
if (check[i][j] == false)
{
winO++;
if (check[i+x][j+x] == false)
{
winO++;
System.out.println(winO);
}
}
else if (check[i][j] == true)
{
winX++;
if (check[i+x][j+x] == true)
{
winX++;
System.out.println(winX);
}
}
if (winO == 4)
{
wonLabel.setText("Player O has won!");
break;
}
else if (winX == 4)
{
wonLabel.setText("Player X has won!");
break;
}
}
}
}
}
Fair warning. This only checks for diagonals! If you want to check for horizontal / vertical, you'll have to add the x value to i and/or j individually
There might be more efficient ways to do this, but this is the best I can do, hope it helps
So I have a solid slide function, the problem is (which is very hard to explain!) it goes through all the possibilities including spaces in the 2d array that have already been added together: say there is a setup like this: 4,4,8,2 ---after one swipe to the right, it ends up like this: ,_,16,2. however in the actual game, after one swipe right, it should look like this: ___,8,2.
Basically, how can I fix this? You don't need to tell me the code, it's my project for my final, but I'd like to get some sort of explanation as to why this is happening.
I've attempted to loop through the array from right to left but that resulted in the numbers not even moving.
processUserChoice(String i) {
if (i.equals("d")) {
while ((slideRight())) {
moveRight();
}
}
printBoard();
}
public boolean slideRight() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length - 1; j++) {
if (board[i][j + 1] == 0 && board[i][j] != 0) {
return true;
} else if (board[i][j + 1] == board[i][j] && board[i][j] != 0) {
return true;
}
}
}
return false;
}
public void moveRight() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length - 1; j++) {
if (board[i][j + 1] == 0 && board[i][j] != 0) {
board[i][j + 1] = board[i][j];
board[i][j] = 0;
} else if (board[i][j + 1] == board[i][j] && board[i][j] != 0) {
board[i][j + 1] = board[i][j + 1] + board[i][j];
board[i][j] = 0;
}
}
}
//checkLose();
}
After one swipe right, it should look like this:" ___,8,2 "(From the example before).
I did something similar to this in the past. I would to do it pretty much the same way as you are at the moment but add a Boolean array that checks if the tile has collided or not and only merges tiles that haven't been collided.
class Tile {
public int value;
public Boolean collided;
public Tile(int value) {
this.value = value;
collided = false;
}
public Tile attemptMerge(Tile target) {
if (target.value == value) {
Tile t = new Tile(value * 2);
t.collided = true;
return t;
} else {
return null;
}
}
public void reset() {
value = 0;
collided = false;
}
}
Somewhere in your main update loop:
void slideRight() {
for (int row = 0; row < 4; row++) {
for (int column = 3; column >= 0; column--) {
Tile current = board[row][column];
if (current.value == 0) continue;
for (int slot = column + 1; slot < 3; slot++) {
Tile target = board[row][slot];
if (target.value == 0) {
target.value = current.value;
current = target;
board[row][slot - 1].reset();
} else if (target.value == current.value) {
Tile product = target.merge(current);
if (!target.collided && !current.collided) {
current = product;
board[row][slot - 1].reset();
} else {
break;
}
} else {
break;
}
}
}
}
}
I believe something along those lines should work. Sorry if the logic is a bit flawed.
I have a vector of vectors filled with characters from a text file. It is essentially a simple outbreak simulator, with 'i' characters being infected, and 's' characters being susceptible to infection. The point is to run through the matrix and if it comes across an 'i', it then changes all 's' around it into an 'i'. I run into a problem when checking the elements around it due to checking positions out of the bounds on the edges of the matrix. Is there a way to check these bounds in my if statements?
Here is the code:
for (int i = 0; i < population.size(); i++) {
for(int j = 0; j < population[i].size(); j++) {
if(population[i][j] == 'i') {
if(population[i-1][j] == 's') {
population[i-1][j] = 'i';
}
if(population[i-1][j+1] == 's') {
population[i-1][j+1] = 'i';
}
if(population[i][j+1] == 's') {
population[i][j+1] = 'i';
}
if(population[i+1][j+1] == 's') {
population[i+1][j+1] = 'i';
}
if(population[i+1][j] == 's') {
population[i+1][j] = 'i';
}
if(population[i+1][j-1] == 's') {
population[i+1][j-1] = 'i';
}
if(population[i][j-1] == 's') {
population[i][j-1] = 'i';
}
}
}
}
Instead of directly referencing a particular array entry, you could do something like the following:
void checkForInfectionAndInfectIfNeeded(int i, int j) {
for (int row = -1; row <= 1; row++) {
for (int column = -1; column <=1; column++) {
infect(i + row, j + column);
}
}
}
void infect(int i, int j) {
if (i < 0 || i >= population.size() || j < 0 || j >= population[j].size()) {
return;
} else {
population[i][j] = 'i';
}
}
This way, the infect method is the only that checks the boundaries, and you replace your long list of manually checking the surrounding locations with two loops.
I am working on Conway game of college problem. I have been able to print the first generation and the second but when it comes to the following ones they all copy the second generation. I was wondering if y'all can help me out.
public void computeNextGeneration(int generation)
{
char[][] newBoard = new char[board.length][board[0].length];
for(int i = 0; i < board.length; i++)
{
for(int j = 0; j < board[0].length; j++)
{
if(board[i][j] == '0' && numOfNeighbors(i,j) == 3)
{
newBoard[i][j] = 'X';
}
else if(board[i][j] == 'X' && numOfNeighbors(i,j) < 2)
{
newBoard[i][j] = '0';
}
else if(board[i][j] == 'X' && numOfNeighbors(i,j) >3)
{
newBoard[i][j] = '0';
}
else if(board[i][j] == 'X' && numOfNeighbors(i,j) == 2 || numOfNeighbors(i,j) == 3)
{
newBoard[i][j] = 'X'; //change x to 0
}
else{
newBoard[i][j] +=board[i][j];
}
}
}
for (int i = 0; i < newBoard.length; i++)
{
for(int j = 0; j < newBoard[0].length; j++)
{
System.out.print(newBoard[i][j]);
}
System.out.println();
}
}
After you calculate the new board you have to assign it back to the class field board. Add as the last line of computeNextGeneration board = newboard.
You start counting your generations from 2 for(int i = 2; i <= gen; i++) as the constructor doesnt generate a starting generation this should be a 0.
I have been looking over this flood fill implementation for some time now and keep running into the dreaded stack overflow. I am dropping pieces randomly on a 12x10 grid and calling the checkMatches method after each random piece drop to check for groups of three or more, hence the flood fill use.
EDIT: See comment
public void checkMatches(int x, int y, int type)
{
if (x < 0 || x >= PIECES_WIDE || y < 0 || y >= PIECES_TALL || type == 0)
return;
if (grid[x][y].getType() != type)
return;
int checkL = x;
while (checkL >= 0 && grid[checkL][y].getType() == type)
{
grid[checkL][y].setDestroy(true);
numMatches++;
checkL--;
}
checkL++;
int checkR = x;
while (checkR < PIECES_WIDE - 1 && grid[checkR][y].getType() == type)
{
grid[checkR][y].setDestroy(true);
numMatches++;
checkR++;
}
checkR--;
for (int i = checkL; i <= checkR; i++)
{
if (y > 0 && grid[i][y - 1].getType() == type)
checkMatches(i, y - 1, type);
if (y < PIECES_TALL - 1 && grid[i][y + 1].getType() == type)
checkMatches(i, y + 1, type);
}
}
Then the relevant code to call the method and destroy the pieces if there have been three matched pieces:
checkMatches(x, y, type);
if (numMatches >= 3)
{
for (int i = 0; i < PIECES_WIDE; i++)
{
for (int j = 0; j < PIECES_TALL; j++)
{
if (grid[i][j].isDestroy())
destroyPiece(grid[i][j]);
}
}
} else
{
numMatches = 0;
for (int i = 0; i < PIECES_WIDE; i++)
{
for (int j = 0; j < PIECES_TALL; j++)
{
grid[i][j].setDestroy(false);
}
}
}
My eyes and brain hurt. I know that the recursion is causing the overflow, but I also know that this implementation is possible in some form. Therefore I'm doing something wrong. Thanks in advance.
You need to put a mark on the pieces that you have already found matching. Then you can make a loop to extend your matchings, until you notice that no more pieces have been marked. Then you can stop.