Merge branch 'master'

This commit is contained in:
Romain MURPHY 2025-04-09 16:56:09 +02:00
commit 5c36efc43f
17 changed files with 959 additions and 0 deletions

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-23">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

1
OOP_2B1_Project/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bin/

17
OOP_2B1_Project/.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>OOP_2B1_Project</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=23
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=23
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=23

View File

@ -0,0 +1,9 @@
BR,BN,BB,BQ,BK,BB,BN,BR
BP,BP,BP,BP,BP,BP,BP,BP
, , , , , , ,
, , , , , , ,
, , , , , , ,
, , , , , , ,
WP,WP,WP,WP,WP,WP,WP,WP
WR,WN,WB,WQ,WK,WB,WN,WR
W

BIN
OOP_2B1_Project/pieces.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

View File

@ -0,0 +1,22 @@
import backend.Board;
import backend.Move;
import backend.Piece;
import backend.PieceType;
import windowInterface.MyInterface;
public class Main {
public static void main(String[] args) {
// testing :
Board testBoard = new Board(8, 8);
testBoard.populateBoard();
System.out.println(testBoard.toString());
// launches graphical interface :
MyInterface mjf = new MyInterface();
mjf.setVisible(true);
}
}

View File

@ -0,0 +1,17 @@
package backend;
public class AutoPlayer {
/**
* returns the best Move to try on provided board for active player
* @param board
* @return
*/
public Move computeBestMove(Board board) {
return null;
}
}

View File

@ -0,0 +1,180 @@
package backend;
import java.util.ArrayList;
public class Board {
public int width;
public int height;
public ArrayList<ArrayList<Piece>> board = new ArrayList<>();
public boolean select = false;
public int xm;
public int ym;
public int turnNumber;
public boolean turnColor;
public Board(int colNum, int lineNum) {
this.width = colNum;
this.height = lineNum;
int rows = 8;
int cols = 8;
for (int i = 0; i < rows; i++) {
ArrayList<Piece> row = new ArrayList<>();
for (int j = 0; j < cols; j++) {
row.add(null); // Fill with null
}
this.board.add(row);
}
this.turnNumber = 0;
this.turnColor = true;
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
public int getTurnNumber() {
return this.turnNumber;
}
public boolean isTurnWhite() {
return this.turnColor;
}
public void setPiece(int x, int y, PieceType type, boolean isWhite) {
Piece piece = new Piece(x,y,type,isWhite);
board.get(y).set(x, piece);
}
public void populateBoard() {
for (int x = 0; x < this.width;x++) {
for (int y = 0; y < this.height; y++) {
if (y ==1 || y == 6) {
if (y == 1) {
this.setPiece(x,y,PieceType.Pawn,false);
}
else if (y == 6) {this.setPiece(x,y,PieceType.Pawn,true);}
}
if (y == 0) {
boolean col = false;
if (x == 0 || x == 7) {
this.setPiece(x,y,PieceType.Rook,col);
} else if (x == 1 || x == 6) {this.setPiece(x,y,PieceType.Knight,col);}
else if (x == 2 || x == 5) {this.setPiece(x,y,PieceType.Bishop,col);}
else if (x == 3) {this.setPiece(x,y,PieceType.Queen,col);}
else if (x == 4) {this.setPiece(x,y,PieceType.King,col);}
} else if (y == 7) {
boolean col = true;
if (x == 0 || x == 7) {
this.setPiece(x,y,PieceType.Rook,col);
} else if (x == 1 || x == 6) {this.setPiece(x,y,PieceType.Knight,col);}
else if (x == 2 || x == 5) {this.setPiece(x,y,PieceType.Bishop,col);}
else if (x == 3) {this.setPiece(x,y,PieceType.Queen,col);}
else if (x == 4) {this.setPiece(x,y,PieceType.King,col);}
}
}
}
}
public void cleanBoard() {
int rows = 8;
int cols = 8;
for (int i = 0; i < rows; i++) {
ArrayList<Piece> row = new ArrayList<>();
for (int j = 0; j < cols; j++) {
row.add(null); // Fill with null
}
this.board.add(row);
}
}
@Override
public String toString() {
return "Board [width=" + width + ", height=" + height + ", board=" + board + "]";
}
public ArrayList<Piece> getPieces() {
ArrayList<Piece> pieces = new ArrayList<>();
for (ArrayList<Piece> row : board) {
for (Piece piece : row) {
if (piece != null) {
pieces.add(piece);
}
}
}
return pieces;
}
public Piece getPiece(int x, int y) {
return board.get(y).get(x);
}
public void movePiece(int x, int y) {
Piece pieceToMove = this.board.get(this.ym).get(this.xm);
this.setPiece(x,y,pieceToMove.getType(),pieceToMove.isWhite());
board.get(this.ym).set(this.xm,null);
}
public void userTouch(int x, int y) {
if (this.select == false && board.get(y).get(x) != null) {
this.xm = x;
this.ym = y;
select = true;
}
else if (select == true && this.xm != x || this.ym != y){
this.movePiece(x, y);
select = false;
this.turnNumber += 1;
// System.out.println(this.toString()); // Debug
this.turnColor = !this.turnColor;
} else {
select = false;
}
}
public boolean isSelected(int x, int y) {
boolean S;
if (this.xm == x && this.ym == y) {S = true;}
else {S = false;}
return S;
}
/* saving-loading feature :*/
public String[] toFileRep() {
//TODO
return null;
}
public Board(String[] array) {
//TODO
}
/* The following methods require more work ! */
public boolean isHighlighted(int x, int y) {
//TODO
return false;
}
public void undoLastMove() {
//TODO
}
public Board(Board board) {
//TODO
}
public void playMove(Move move) {
//TODO
}
}

View File

@ -0,0 +1,110 @@
package backend;
import windowInterface.MyInterface;
public class Game extends Thread {
private AutoPlayer aiPlayer;
private Board board;
private MyInterface mjf;
private int COL_NUM = 8;
private int LINE_NUM = 8;
private int loopDelay = 250;
boolean[] activationAIFlags;
public Game(MyInterface mjfParam) {
mjf = mjfParam;
board = new Board(COL_NUM, LINE_NUM);
loopDelay = 250;
LINE_NUM = 8;
COL_NUM = 8;
activationAIFlags = new boolean[2];
aiPlayer = new AutoPlayer();
}
public int getWidth() {
return board.getWidth();
}
public int getHeight() {
return board.getHeight();
}
public void run() {
while(true) {
aiPlayerTurn();
mjf.update(board.getTurnNumber(), board.isTurnWhite());
try {
Thread.sleep(loopDelay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private boolean isAITurn() {
return activationAIFlags[board.isTurnWhite()?1:0];
}
private void aiPlayerTurn() {
if(isAITurn()) {
board.playMove(aiPlayer.computeBestMove(new Board(board)));
}
}
public void clickCoords(int x, int y) {
int width = this.getWidth();
int height = this.getHeight();
if(0>x || 0>y || x>width || y>height) {
System.out.println("Click out of bounds");
return;
}
if(!isAITurn()) {
board.userTouch(x, y);
}
}
public void setPiece(int x, int y, PieceType type, boolean isWhite) {
board.setPiece(x, y, type, isWhite);
}
public String[] getFileRepresentation() {
return board.toFileRep();
}
public void setLoopDelay(int delay) {
this.loopDelay = delay;
}
public void setDefaultSetup() {
board.cleanBoard();
board.populateBoard();
}
public void setBoard(String[] array) {
board = new Board(array);
}
public Iterable<Piece> getPieces() {
return board.getPieces();
}
public boolean isSelected(int x, int y) {
return board.isSelected(x, y);
}
public boolean isHighlighted(int x, int y) {
return board.isHighlighted(x, y);
}
public void undoLastMove() {
board.undoLastMove();
}
public void toggleAI(boolean isWhite) {
this.activationAIFlags[isWhite?1:0] = !this.activationAIFlags[isWhite?1:0];
}
}

View File

@ -0,0 +1,5 @@
package backend;
public class Move {
}

View File

@ -0,0 +1,35 @@
package backend;
public class Piece {
public int x;
public int y;
public PieceType type;
public boolean isWhite;
public Piece(int x, int y, PieceType type, boolean isWhite) {
this.x = x;
this.y = y;
this.type = type;
this.isWhite = isWhite;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public PieceType getType() {
return this.type;
}
public boolean isWhite() {
return this.isWhite;
}
@Override
public String toString() {
return "Piece [x=" + x + ", y=" + y + ", type=" + type + ", isWhite=" + isWhite + "]";
}
}

View File

@ -0,0 +1,28 @@
package backend;
public enum PieceType {
Pawn, Rook, Knight, Bishop, Queen, King;
public String getSummary() {
if(this == PieceType.Knight) {
return "N";
}
return this.name().substring(0, 1);
}
public static PieceType fromSummary(char c) {
if(c=='P') {
return PieceType.Pawn;
}else if(c=='N') {
return PieceType.Knight;
}else if(c=='B') {
return PieceType.Bishop;
}else if(c=='R') {
return PieceType.Rook;
}else if(c=='K') {
return PieceType.King;
}
return PieceType.Queen;
}
}

View File

@ -0,0 +1,47 @@
package backend;
import java.util.ArrayList;
public class PossibleMovements {
ArrayList<ArrayList<Piece>> board;
Piece pieceToMove;
PieceType type;
int x;
int y;
boolean turnColor;
public PossibleMovements(ArrayList<ArrayList<Piece>> board, int x, int y,boolean turnColor) {
this.board = board;
this.pieceToMove = board.get(y).get(x);
this.type = pieceToMove.getType();
this.x = x;
this.y = y;
this.turnColor = turnColor;
}
public ArrayList<ArrayList<Boolean>> PM(){
ArrayList<ArrayList<Boolean>> possibleMoves = new ArrayList<>();
int rows = 8;
int cols = 8;
for (int i = 0; i < rows; i++) {
ArrayList<Boolean> row = new ArrayList<>();
for (int j = 0; j < cols; j++) {
row.add(false); // Fill with false
}
possibleMoves.add(row);
}
if (turnColor) {
if (type == PieceType.Pawn) {
if (x == 0) {
if (board.get(y).get(x+1) != null) {
possibleMoves.get(y).set(x+1, true);
}
}
if (x==7) {
if (board.get(y).get(x-1) != null) {
possibleMoves.get(y).set(x-1, true);
}
}
for (int xi = 1; xi<7;i++) {
}
}
}
}

View File

@ -0,0 +1,196 @@
package windowInterface;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import backend.Game;
import backend.Piece;
import backend.PieceType;
public class JPanelChessBoard extends JPanel {
private static final long serialVersionUID = 1L;
private Game myGame;
private MyInterface interfaceGlobal;
private BufferedImage spriteSheet;
private int PIECE_WIDTH = 16; //in spritesheet
private int PIECE_HEIGHT = 16; //in spritesheet
private int MARGIN = 6;
private boolean pieceSelectorMode;
private boolean selectedPieceIsWhite;
private PieceType selectedPieceType;
private boolean pieceAdderMode;
public JPanelChessBoard(MyInterface itf) {
super();
myGame = null;
interfaceGlobal = itf;
selectedPieceIsWhite = true;
selectedPieceType = PieceType.Pawn;
pieceSelectorMode = false;
try {
spriteSheet = ImageIO.read(new File("pieces.png"));
} catch (IOException e) {
e.printStackTrace();
}
pieceSelectorMode = false;
pieceAdderMode = false;
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
// System.out.println(me);
if(pieceSelectorMode) {
int x = Math.round(me.getX()/cellWidth());
selectedPieceType = PieceType.values()[5-x];
selectedPieceIsWhite = (me.getY() > cellHeight());
pieceSelectorMode = false;
} else {
if(myGame == null) {
interfaceGlobal.instantiateSimu();
}
int x = (me.getX()*myGame.getWidth())/getWidth();
int y = (me.getY()*myGame.getHeight())/getHeight();
if(pieceAdderMode) {
//TODO
myGame.setPiece(x, y, selectedPieceType, selectedPieceIsWhite);
pieceAdderMode = false;
} else {
myGame.clickCoords(x,y);
}
}
repaint();
}
});
}
public void setGame(Game simu) {
myGame = simu;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.black);
if(pieceSelectorMode) {
g.drawImage(
spriteSheet,
0,
0,
Math.round(5*cellWidth()),
Math.round(2*cellHeight()),
null
);
return;
}
if (myGame != null) {
// Draw Interface from state of simulator
float cellWidth = cellWidth();
float cellHeight = cellHeight();
g.setColor(Color.white);
for(int x=0; x<myGame.getWidth();x++) {
for (int y=0; y<myGame.getHeight(); y++) {
boolean isSelect = myGame.isSelected(x,y);
boolean isHighlight = myGame.isHighlighted(x,y);
if(isSelect) {
g.setColor(Color.blue);
}
if(isHighlight) {
g.setColor(Color.yellow);
}
if((x+y)%2==1 || isSelect || isHighlight) {
g.fillRect(
Math.round(x*cellWidth),
Math.round(y*cellHeight),
Math.round(cellWidth),
Math.round(cellHeight)
);
}
if(isHighlight || isSelect) {
g.setColor(Color.white);
}
}
}
g.setColor(Color.gray);
for(int x=0; x<myGame.getWidth();x++) {
int graphX = Math.round(x*cellWidth);
g.drawLine(graphX, 0, graphX, this.getHeight());
}
for (int y=0; y<myGame.getHeight(); y++) {
int graphY = Math.round(y*cellHeight);
g.drawLine(0, graphY, this.getWidth(), graphY);
}
for (Piece piece : myGame.getPieces()) {
drawPiece(g,piece);
}
}
}
private void drawPiece(Graphics g, Piece piece) {
g.drawImage(
getChessPieceImageFromType(piece.getType(), piece.isWhite()),
MARGIN+(xCoordFromGame(piece.getX())),
MARGIN+(yCoordFromGame(piece.getY())),
null
);
}
private Image getChessPieceImageFromType(PieceType type, boolean isWhite) {
int x = spriteSheetPositionOfPieceType(type)*PIECE_WIDTH;
int y = PIECE_HEIGHT * (isWhite?1:0);
Image subImage = spriteSheet.getSubimage(x, y, PIECE_WIDTH, PIECE_HEIGHT);
return subImage.getScaledInstance(
Math.round(cellWidth())-2*MARGIN,
Math.round(cellHeight())-2*MARGIN, 0
);
}
private int spriteSheetPositionOfPieceType(PieceType type) {
return 5-type.ordinal();
}
private float cellWidth() {
return (float) this.getWidth()/ (float)myGame.getWidth();
}
private float cellHeight() {
return (float)this.getHeight()/ (float)myGame.getHeight();
}
private int xCoordFromGame(int x) {
return Math.round(x*cellWidth());
}
private int yCoordFromGame(int y) {
return Math.round(y*cellHeight());
}
public void togglePieceSelector() {
pieceSelectorMode = ! pieceSelectorMode;
}
public void toggleAdderMode() {
pieceAdderMode = ! pieceAdderMode;
}
public boolean isPieceSelectorMode() {
return pieceSelectorMode;
}
public boolean isPieceAdderMode() {
return pieceAdderMode;
}
}

View File

@ -0,0 +1,269 @@
package windowInterface;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import backend.Game;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.awt.event.ActionEvent;
import javax.swing.JList;
import javax.swing.AbstractListModel;
import javax.swing.JToggleButton;
import javax.swing.JRadioButton;
import javax.swing.JCheckBox;
public class MyInterface extends JFrame {
private static final long serialVersionUID = -6840815447618468846L;
private JPanel contentPane;
private JLabel turnLabel;
private JLabel borderLabel;
private JLabel speedLabel;
private JPanelChessBoard panelDraw;
private Game game;
private JLabel actionLabel;
private JCheckBox chckbxBlackAI;
private JCheckBox chckbxWhiteAI;
/**
* Create the frame.
*/
public MyInterface() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(10, 10, 650, 650);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panelTop = new JPanel();
contentPane.add(panelTop, BorderLayout.NORTH);
JPanel panelRight = new JPanel();
contentPane.add(panelRight, BorderLayout.EAST);
panelRight.setLayout(new GridLayout(4,1));
actionLabel = new JLabel("Waiting For Start");
panelTop.add(actionLabel);
JButton btnGo = new JButton("Start/Restart");
btnGo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicButtonStart();
}
});
panelTop.add(btnGo);
turnLabel = new JLabel("Turn : X");
panelTop.add(turnLabel);
JButton btnLoad = new JButton("Load File");
btnLoad.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicLoadFileButton();
}
});
panelRight.add(btnLoad);
JButton btnSave = new JButton("Save To File");
btnSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicSaveToFileButton();
}
});
panelRight.add(btnSave);
JButton btnAdder = new JButton("Add Piece");
btnAdder.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clickButtonAdder();
}
});
panelRight.add(btnAdder);
JButton btnPieceSelector = new JButton("Piece Select");
btnPieceSelector.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clickButtonSelector();
}
});
panelRight.add(btnPieceSelector);
JButton btnUndo = new JButton("Undo");
btnUndo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicUndoButton();
}
});
panelTop.add(btnUndo);
chckbxWhiteAI = new JCheckBox("WhiteAI");
chckbxWhiteAI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicAIToggle(true);
}
});
panelTop.add(chckbxWhiteAI);
chckbxBlackAI = new JCheckBox("BlackAI");
chckbxBlackAI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicAIToggle(false);
}
});
panelTop.add(chckbxBlackAI);
panelDraw = new JPanelChessBoard(this);
contentPane.add(panelDraw, BorderLayout.CENTER);
}
public void setStepBanner(String s) {
turnLabel.setText(s);
}
public void setBorderBanner(String s) {
borderLabel.setText(s);
}
public JPanelChessBoard getPanelDessin() {
return panelDraw;
}
public void instantiateSimu() {
if(game==null) {
game = new Game(this);
panelDraw.setGame(game);
game.start();
}
}
public void clicButtonStart() {
this.instantiateSimu();
game.setDefaultSetup();
}
public void clickButtonAdder() {
panelDraw.toggleAdderMode();
}
public void clickButtonSelector() {
panelDraw.togglePieceSelector();
}
private void clicUndoButton() {
if(game == null) {
System.out.println("error : can't undo while no game present");
} else {
game.undoLastMove();
}
}
public void clicAIToggle(boolean isWhite) {
if(game == null) {
System.out.println("error : can't activate AI while no game present");
if(isWhite) {
chckbxWhiteAI.setSelected(false);
}else {
chckbxBlackAI.setSelected(false);
}
} else {
game.toggleAI(isWhite);
}
}
public void clicLoadFileButton() {
Game loadedSim = new Game(this);
String fileName=SelectFile();
LinkedList<String> lines = new LinkedList<String>();
if (fileName.length()>0) {
try {
BufferedReader fileContent = new BufferedReader(new FileReader(fileName));
String line = fileContent.readLine();
int colorID = 0;
while (line != null) {
lines.add(line);
line = fileContent.readLine();
}
loadedSim.setBoard(Arrays.stream(lines.toArray()).map(Object::toString).toArray(String[]::new));
fileContent.close();
} catch (Exception e) {
e.printStackTrace();
}
game = loadedSim;
panelDraw.setGame(game);
this.repaint();
}
}
public void clicSaveToFileButton() {
String fileName=SelectFile();
if (fileName.length()>0) {
String[] content = game.getFileRepresentation();
writeFile(fileName, content);
}
}
public String SelectFile() {
String s;
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new java.io.File("."));
chooser.setDialogTitle("Choose a file");
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
chooser.setAcceptAllFileFilterUsed(true);
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
s=chooser.getSelectedFile().toString();
} else {
System.out.println("No Selection ");
s="";
}
return s;
}
public void writeFile(String fileName, String[] content) {
FileWriter csvWriter;
try {
csvWriter = new FileWriter(fileName);
for (String row : content) {
csvWriter.append(row);
csvWriter.append("\n");
}
csvWriter.flush();
csvWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void update(int turnCount, boolean turnIsWhite) {
turnLabel.setText("Turn : "+turnCount+", "+ (turnIsWhite?"White":"Black"));
actionLabel.setText(panelDraw.isPieceAdderMode()?"Adding Piece":
(panelDraw.isPieceSelectorMode()?"Selecting Piece to Add":
"Playing"));
this.repaint();
}
public void eraseLabels() {
this.setStepBanner("Turn : X");
}
}