File Parser for levels (#18)
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			Co-authored-by: Debucquoy Anthony (tonitch) <debucquoy.anthony@gmail.com> Reviewed-on: #18 Reviewed-by: Mat_02 <diletomatteo@gmail.com>
This commit is contained in:
		@ -14,11 +14,20 @@ public class Map extends Shape{
 | 
			
		||||
        super(matrix);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Map() {
 | 
			
		||||
        super();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addPiece(Piece piece){
 | 
			
		||||
        piece.setLinked_map(this);
 | 
			
		||||
        pieces.add(piece);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addPiece(Piece[] pieces) {
 | 
			
		||||
        for (Piece p : pieces)
 | 
			
		||||
            this.addPiece(p);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return a matrix with all used space on the map to see if a piece can fit in a space
 | 
			
		||||
     *
 | 
			
		||||
@ -33,6 +42,8 @@ public class Map extends Shape{
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (Piece p : pieces) {
 | 
			
		||||
            if(p.getPosition() == null)
 | 
			
		||||
                continue;
 | 
			
		||||
            for(int x = 0; x < p.height; x++){
 | 
			
		||||
                for(int y = 0; y < p.width; y++){
 | 
			
		||||
                    if (p.getShape()[x][y]){
 | 
			
		||||
@ -43,4 +54,22 @@ public class Map extends Shape{
 | 
			
		||||
        }
 | 
			
		||||
        return used;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ArrayList<Piece> getPieces() {
 | 
			
		||||
        return pieces;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * return a new Clean Map without any pieces on it for saving purpose
 | 
			
		||||
     * @return a New Map Object without any pieces or saved data
 | 
			
		||||
     */
 | 
			
		||||
    public Map getCleanedMap() {
 | 
			
		||||
        try {
 | 
			
		||||
            Map ret = (Map) this.clone();
 | 
			
		||||
            ret.getPieces().clear();
 | 
			
		||||
            return ret;
 | 
			
		||||
        } catch (CloneNotSupportedException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										220
									
								
								app/src/main/java/school_project/Parsers/BinaryParser.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								app/src/main/java/school_project/Parsers/BinaryParser.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,220 @@
 | 
			
		||||
package school_project.Parsers;
 | 
			
		||||
 | 
			
		||||
import school_project.Map;
 | 
			
		||||
import school_project.Piece;
 | 
			
		||||
import school_project.Utils.Bitwise;
 | 
			
		||||
import school_project.Vec2;
 | 
			
		||||
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
public class BinaryParser implements FileParser {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Map getLevel(File file, boolean saved_data) throws IOException {
 | 
			
		||||
        Map ret;
 | 
			
		||||
 | 
			
		||||
        FileInputStream fileStream = new FileInputStream(file);
 | 
			
		||||
 | 
			
		||||
        byte[] level_data = ExtractLevelData(fileStream);
 | 
			
		||||
 | 
			
		||||
        ret = new Map(ExtractMapFromLevelData(level_data));
 | 
			
		||||
 | 
			
		||||
        ret.addPiece(ExtractPiecesFromLevelData(level_data, saved_data));
 | 
			
		||||
        
 | 
			
		||||
        fileStream.close();
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void saveLevel(File file, Map level_data, boolean save_data) throws IOException {
 | 
			
		||||
        int byteSize = getByteSizeForMap(level_data, save_data);
 | 
			
		||||
        byte[] data = new byte[byteSize];
 | 
			
		||||
        int i = 0;
 | 
			
		||||
        data[i++] = 'S'; data[i++] = 'M'; data[i++] = 'S';
 | 
			
		||||
        data[i++] = (byte) level_data.getWidth(); data[i++] = (byte) level_data.getHeight();
 | 
			
		||||
        for(byte b : BuildByteFromMatrix(level_data.getShape())){
 | 
			
		||||
            data[i++] = b;
 | 
			
		||||
        }
 | 
			
		||||
        data[i++] = (byte) level_data.getPieces().size();
 | 
			
		||||
        for (Piece p : level_data.getPieces()) {
 | 
			
		||||
            data[i++] = Bitwise.NibbleToByte((byte) p.getWidth(), (byte) p.getHeight());
 | 
			
		||||
            for(byte b : BuildByteFromMatrix(p.getShape())){
 | 
			
		||||
                data[i++] = b;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (save_data){
 | 
			
		||||
            for (Piece p : level_data.getPieces()) {
 | 
			
		||||
                Vec2 _piece_pos = p.getPosition();
 | 
			
		||||
                if(_piece_pos == null){
 | 
			
		||||
                    data[i++] = 'F';
 | 
			
		||||
                    data[i++] = 'L';
 | 
			
		||||
                }else{
 | 
			
		||||
                    data[i++] = (byte) _piece_pos.x;
 | 
			
		||||
                    data[i++] = (byte) _piece_pos.y;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        data[i++] = 'S'; data[i++] = 'M'; data[i++] = 'E';
 | 
			
		||||
        FileOutputStream save_file = new FileOutputStream(file);
 | 
			
		||||
        save_file.write(data);
 | 
			
		||||
        save_file.flush();
 | 
			
		||||
        save_file.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Extract Level data from file content
 | 
			
		||||
     * @param fileStream file stream to read extract data from
 | 
			
		||||
     * @return Level data as an array of byte
 | 
			
		||||
     * @throws IOException Expected if we can't read the file
 | 
			
		||||
     */
 | 
			
		||||
    static byte[] ExtractLevelData(InputStream fileStream) throws IOException {
 | 
			
		||||
 | 
			
		||||
        byte[] bytes = fileStream.readAllBytes();
 | 
			
		||||
 | 
			
		||||
        int start_position = 0, end_position = 0;
 | 
			
		||||
        for (int i = 0; i < bytes.length; i++) {
 | 
			
		||||
            if(bytes[i] == 83 && bytes[i+1] == 77 && bytes[i+2] == 83){ // SMS
 | 
			
		||||
                start_position = i+3;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = start_position; i < bytes.length - 2; i++) {
 | 
			
		||||
            if(bytes[i] == 83 && bytes[i+1] == 77 && bytes[i+2] == 69){ // SME
 | 
			
		||||
                end_position = i;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Arrays.copyOfRange(bytes, start_position, end_position);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get Pieces out of the level data
 | 
			
		||||
     *
 | 
			
		||||
     * @param levelData  full data of the level without header and footer
 | 
			
		||||
     * @param saved_data Should extract saved data and included it in the pieces
 | 
			
		||||
     * @return array of Piece from level data
 | 
			
		||||
     */
 | 
			
		||||
    static Piece[] ExtractPiecesFromLevelData(byte[] levelData, boolean saved_data) {
 | 
			
		||||
        byte map_width = levelData[0], map_height = levelData[1];
 | 
			
		||||
        byte piece_count = levelData[2 + map_width * map_height / 8 + (map_height * map_width % 8 != 0 ? 1 : 0)];
 | 
			
		||||
        Piece[] ret = new Piece[piece_count];
 | 
			
		||||
        byte[] pieces_data = Arrays.copyOfRange(levelData, 3 + map_width * map_height / 8 + (map_height * map_width % 8 != 0 ? 1 : 0), levelData.length);
 | 
			
		||||
        byte[] pieces_positions = saved_data ? Arrays.copyOfRange(levelData, levelData.length - piece_count*2,levelData.length ): null;
 | 
			
		||||
        int piece_offset = 0;
 | 
			
		||||
        for (int piece_index = 0; piece_index < piece_count; piece_index++) {
 | 
			
		||||
            Vec2 _piece_size = Bitwise.ByteToNible(pieces_data[piece_index + piece_offset]);
 | 
			
		||||
 | 
			
		||||
            byte[] _piece_data = Arrays.copyOfRange(pieces_data, piece_index + piece_offset + 1, piece_index + piece_offset + 1 + _piece_size.x * _piece_size.y / 8 + (_piece_size.x * _piece_size.y % 8 != 0 ? 1 : 0));
 | 
			
		||||
 | 
			
		||||
            boolean[][] _piece_matrix = BuildMatrixFromBytes(_piece_size.x, _piece_size.y, _piece_data);
 | 
			
		||||
 | 
			
		||||
            ret[piece_index] = new Piece(_piece_matrix);
 | 
			
		||||
 | 
			
		||||
            if(saved_data){
 | 
			
		||||
                Vec2 _piece_pos = new Vec2(pieces_positions[piece_index*2], pieces_positions[piece_index*2 + 1]);
 | 
			
		||||
                ret[piece_index].setPosition(_piece_pos);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            piece_offset += _piece_size.x * _piece_size.y / 8 + (_piece_size.x * _piece_size.y % 8 != 0 ? 1 : 0);
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the Map Matrix out of the level data
 | 
			
		||||
     * @param level_data full data of the level without header and footer
 | 
			
		||||
     * @return boolean matrix of the map
 | 
			
		||||
     */
 | 
			
		||||
    static boolean[][] ExtractMapFromLevelData(byte[] level_data){
 | 
			
		||||
        int map_width = level_data[0], map_height = level_data[1];
 | 
			
		||||
        byte[] map_data = Arrays.copyOfRange(level_data, 2, 2 + map_width * map_height / 8 + (map_height * map_width % 8 != 0 ? 1 : 0));
 | 
			
		||||
        return BuildMatrixFromBytes(map_width, map_height, map_data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * take a boolean matrix and build an array of byte following the specs of the parser
 | 
			
		||||
     * @param shape bolean matrix where true are 1 and false are 0
 | 
			
		||||
     * @return byte array with each element compiled for file format
 | 
			
		||||
     */
 | 
			
		||||
    static byte[] BuildByteFromMatrix(boolean[][] shape){
 | 
			
		||||
        int width = shape[0].length , height = shape.length;
 | 
			
		||||
        boolean[] b_list = new boolean[width * height];
 | 
			
		||||
        for (int x = 0; x < shape.length; x++) {
 | 
			
		||||
            for (int y = 0; y < shape[x].length; y++) {
 | 
			
		||||
                b_list[x * shape[x].length + y] = shape[x][y];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        byte[] ret = new byte[width * height  / 8 + (width * height % 8 == 0 ? 0 : 1)];
 | 
			
		||||
        for (int i = 0; i < ret.length; i++) {
 | 
			
		||||
            byte current_byte = 0;
 | 
			
		||||
            boolean[] current_byte_data = Arrays.copyOfRange(b_list, i * 8, i * 8 + 8);
 | 
			
		||||
            for (boolean curr_data: current_byte_data) {
 | 
			
		||||
                current_byte = (byte) (current_byte << 1);
 | 
			
		||||
                current_byte = (byte) (current_byte | (curr_data ? 1 : 0));
 | 
			
		||||
            }
 | 
			
		||||
            ret[i] = current_byte;
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Build a boolean Matrix From a byte array
 | 
			
		||||
     * Each Byte is composed of 8 bit, each bit is 1 or 0
 | 
			
		||||
     *  if the bit is 0 then it's a false for this cell
 | 
			
		||||
     *  else it's true for this cell
 | 
			
		||||
     * @param matrix_width width of the matrix
 | 
			
		||||
     * @param matrix_height height of the matrix
 | 
			
		||||
     * @param matrix_data byte array of the data to export
 | 
			
		||||
     * @return boolean Matrix of the data decompiled
 | 
			
		||||
     */
 | 
			
		||||
    static boolean[][] BuildMatrixFromBytes(int matrix_width, int matrix_height, byte[] matrix_data){
 | 
			
		||||
        boolean[][] ret = new boolean[matrix_height][matrix_width];
 | 
			
		||||
 | 
			
		||||
        // Transforming the bit from matrix_data's byte into boolean array for better manipulation
 | 
			
		||||
        boolean[] b_array = new boolean[matrix_height * matrix_width];
 | 
			
		||||
        int index = 0;
 | 
			
		||||
        for(byte b: matrix_data){
 | 
			
		||||
            for (int i = 0; i < 8; i++) { // because 8 bit in a byte
 | 
			
		||||
                b_array[index] = Bitwise.IsBitSetAt(b, i);
 | 
			
		||||
                index++;
 | 
			
		||||
                if(index >= matrix_height * matrix_width)
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Transforming b_array to a 2D matrix
 | 
			
		||||
        for (int x = 0; x < matrix_height; x++) {
 | 
			
		||||
            for (int y = 0; y < matrix_width; y++) {
 | 
			
		||||
                ret[x][y] = b_array[y + x * matrix_width];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * give the amount of byte needed to store the given Map
 | 
			
		||||
     * following the binary file format
 | 
			
		||||
     * @param level the map to check
 | 
			
		||||
     * @param data should add save data or only level data
 | 
			
		||||
     * @return integer of the ammount of byte needed
 | 
			
		||||
     */
 | 
			
		||||
    public static int getByteSizeForMap(Map level, boolean data){
 | 
			
		||||
        int ret = 6; // header + footer
 | 
			
		||||
        ret += 2; //size of the piece
 | 
			
		||||
        ret += ((level.getWidth() * level.getHeight()) / 8); // size of the map
 | 
			
		||||
        ret += level.getHeight() * level.getWidth() % 8 == 0 ? 0 : 1; // Add 1 if the size of map is not a mult of 8
 | 
			
		||||
        ret += 1; // amount of pieces
 | 
			
		||||
        for(Piece p: level.getPieces()){
 | 
			
		||||
            ret += 1; // size of the piece
 | 
			
		||||
            ret += p.getHeight() * p.getWidth() / 8;
 | 
			
		||||
            ret += p.getHeight() * p.getWidth() % 8 == 0 ? 0 : 1; // add 1 if the size of the piece is not mult of 8
 | 
			
		||||
            if(data){
 | 
			
		||||
                ret += 2; // if the piece is not placed, only one byte else 2
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								app/src/main/java/school_project/Parsers/FileParser.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/src/main/java/school_project/Parsers/FileParser.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
package school_project.Parsers;
 | 
			
		||||
 | 
			
		||||
import school_project.Map;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
public interface FileParser {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parse the file and create a Map with its shape and pieces setup
 | 
			
		||||
     *
 | 
			
		||||
     * @param file file to parse
 | 
			
		||||
     * @param saved_data does the saved data should be added to the map
 | 
			
		||||
     * @return Map Object parsed with file data
 | 
			
		||||
     * @see "TODO: Add Specification when done"
 | 
			
		||||
     * @throws FileNotFoundException if the file was not found or was not accessible
 | 
			
		||||
     * @throws IOException if an I/O occurs
 | 
			
		||||
     */
 | 
			
		||||
    Map getLevel(File file, boolean saved_data) throws IOException;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Save Map to a file without all it's data
 | 
			
		||||
     * Could be used for generating level file. might not be used in game.
 | 
			
		||||
     * @param file the file where to save
 | 
			
		||||
     * @param levelData the map to save
 | 
			
		||||
     * @param save_data should save the map data (need to be false only in development I think)
 | 
			
		||||
     * @throws FileNotFoundException The file could not be created
 | 
			
		||||
     * @throws IOException if an I/O occurs
 | 
			
		||||
     */
 | 
			
		||||
    void saveLevel(File file, Map levelData, boolean save_data) throws IOException;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,83 @@
 | 
			
		||||
package school_project.Parsers;
 | 
			
		||||
 | 
			
		||||
import javafx.util.Pair;
 | 
			
		||||
import school_project.Map;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.NotSerializableException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is used to find the right parser to parser a save/level file.
 | 
			
		||||
 * This should be the only right way to save/load a file! you can just use `Map loadMapFromFile(File)` to load a file
 | 
			
		||||
 * and `void saveFileFromMap(File, Map)` to save a file
 | 
			
		||||
 *
 | 
			
		||||
 * <p>
 | 
			
		||||
 * there is currently 2 file format with 2 variation each (save file or level file)
 | 
			
		||||
 * - BinaryParser
 | 
			
		||||
 *  - ".level"
 | 
			
		||||
 *  - ".slevel"
 | 
			
		||||
 * - SerializeParser
 | 
			
		||||
 *  - ".serialized"
 | 
			
		||||
 *  - ".sserialized"
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 * <p>
 | 
			
		||||
 * More file format can be added in the future by adding a new class that implement parser
 | 
			
		||||
 * and adding it to this file
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author tonitch
 | 
			
		||||
 */
 | 
			
		||||
public class FileParserFactory {
 | 
			
		||||
    /**
 | 
			
		||||
     * Load a file and return a map
 | 
			
		||||
     * If this is a save map, return the map with its save data
 | 
			
		||||
     * @param file file to get data from
 | 
			
		||||
     * @return Map generated from the file
 | 
			
		||||
     * @throws FileNotFoundException if the file was not found or was not accessible
 | 
			
		||||
     * @throws IOException if an I/O occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static Map loadMapFromFile(File file) throws IOException {
 | 
			
		||||
        Pair<FileParser, Boolean> parser= getFileParser(file);
 | 
			
		||||
        return parser.getKey().getLevel(file, parser.getValue());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Save a file in a specific format, this format is defined by the file extension
 | 
			
		||||
     * This file extention could be: ".level", ".slevel", ".serialized", ".sserialized"
 | 
			
		||||
     * for save file use the .s variations
 | 
			
		||||
     * @param file file name to be saved to with the right extension
 | 
			
		||||
     * @param map map file to save
 | 
			
		||||
     * @throws NotSerializableException the file extension is not recognised
 | 
			
		||||
     * @throws FileNotFoundException The file could not be created
 | 
			
		||||
     * @throws IOException if an I/O occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static void saveFileFromMap(File file, Map map) throws IOException {
 | 
			
		||||
        Pair<FileParser, Boolean> parser= getFileParser(file);
 | 
			
		||||
        parser.getKey().saveLevel(file, map, parser.getValue());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Pair<FileParser, Boolean> getFileParser(File file) throws NotSerializableException {
 | 
			
		||||
        FileParser fileParser;
 | 
			
		||||
        boolean save_data;
 | 
			
		||||
 | 
			
		||||
        if (file.toString().toLowerCase().endsWith(".level")){
 | 
			
		||||
            fileParser = new BinaryParser();
 | 
			
		||||
            save_data = false;
 | 
			
		||||
        }else if(file.toString().toLowerCase().endsWith(".slevel")){
 | 
			
		||||
            fileParser = new BinaryParser();
 | 
			
		||||
            save_data = true;
 | 
			
		||||
        }else if(file.toString().toLowerCase().endsWith(".serialized")){
 | 
			
		||||
            fileParser = new SerializeParser();
 | 
			
		||||
            save_data = false;
 | 
			
		||||
        }else if(file.toString().toLowerCase().endsWith(".sserialized")) {
 | 
			
		||||
            fileParser = new SerializeParser();
 | 
			
		||||
            save_data = true;
 | 
			
		||||
        }else {
 | 
			
		||||
            throw new NotSerializableException("This file format is not supported");
 | 
			
		||||
        }
 | 
			
		||||
        return new Pair<FileParser, Boolean>(fileParser, save_data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
package school_project.Parsers;
 | 
			
		||||
 | 
			
		||||
import school_project.Map;
 | 
			
		||||
 | 
			
		||||
import java.io.*;
 | 
			
		||||
 | 
			
		||||
public class SerializeParser implements FileParser{
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Map getLevel(File file, boolean saved_data) throws IOException {
 | 
			
		||||
        // saved_data is ignored in this case because the file is serialized data and it already knows if should have saved_data or not at this point
 | 
			
		||||
        FileInputStream fileStream = new FileInputStream(file);
 | 
			
		||||
        ObjectInputStream objectStream = new ObjectInputStream(fileStream);
 | 
			
		||||
        try {
 | 
			
		||||
            return (Map) objectStream.readObject();
 | 
			
		||||
        } catch (ClassNotFoundException e) {
 | 
			
		||||
            throw new IOException("the serialized file format has not found any object in the file");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void saveLevel(File file, Map levelData, boolean save_data) throws IOException {
 | 
			
		||||
        FileOutputStream fileStream = new FileOutputStream(file);
 | 
			
		||||
        ObjectOutputStream objectStream = new ObjectOutputStream(fileStream);
 | 
			
		||||
        objectStream.writeObject(save_data ? levelData : levelData.getCleanedMap());
 | 
			
		||||
 | 
			
		||||
        objectStream.close();
 | 
			
		||||
        fileStream.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -24,10 +24,6 @@ public class Piece extends Shape{
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPosition(Vec2 position){
 | 
			
		||||
        if (linked_map == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.Position = position;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -56,4 +52,14 @@ public class Piece extends Shape{
 | 
			
		||||
            matrix = temp_matrix;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object obj) {
 | 
			
		||||
        if(obj instanceof Piece pieceObj){
 | 
			
		||||
            if( pieceObj.getPosition().equals(this.getPosition()) && pieceObj.getShape().equals(getShape())) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,12 +1,14 @@
 | 
			
		||||
package school_project;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base class for everything that is a shape kind, like map and pieces
 | 
			
		||||
 * it contain a matrix of boolean where the shape is defined by the true's
 | 
			
		||||
 */
 | 
			
		||||
public class Shape {
 | 
			
		||||
 | 
			
		||||
public class Shape implements Serializable, Cloneable{
 | 
			
		||||
    
 | 
			
		||||
    protected boolean[][] matrix;
 | 
			
		||||
    protected int height, width;
 | 
			
		||||
 | 
			
		||||
@ -41,4 +43,17 @@ public class Shape {
 | 
			
		||||
    public boolean[][] getShape() {
 | 
			
		||||
        return matrix;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        String ret = "";
 | 
			
		||||
        for (boolean[] row : matrix) {
 | 
			
		||||
            for (boolean el : row) {
 | 
			
		||||
                if(el) ret = ret.concat("⬛");
 | 
			
		||||
                else ret = ret.concat("⬜");
 | 
			
		||||
            }
 | 
			
		||||
            ret = ret.concat("\n");
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										43
									
								
								app/src/main/java/school_project/Utils/Bitwise.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								app/src/main/java/school_project/Utils/Bitwise.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
package school_project.Utils;
 | 
			
		||||
 | 
			
		||||
import school_project.Vec2;
 | 
			
		||||
 | 
			
		||||
public class Bitwise {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the bit at pos is 1 or 0
 | 
			
		||||
     * @param b byte to test
 | 
			
		||||
     * @param pos position in b to check
 | 
			
		||||
     * @return true if the bit at pos is 1 or false if it is 0
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean IsBitSetAt(byte b, int pos){
 | 
			
		||||
        pos = 7 - pos;
 | 
			
		||||
        return (b & (1 << pos))!= 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Transform a byte (8 bit) to two Nible (4 bit) with a split in the middle
 | 
			
		||||
     * Exemple:
 | 
			
		||||
     * in = 01000101 (=69)
 | 
			
		||||
     * out = { 00000100, 00000101 } (={4, 5})
 | 
			
		||||
     *
 | 
			
		||||
     * @param in the byte to split
 | 
			
		||||
     * @return an arrya of 2 byte ret[0] = left part; ret[1] = right part
 | 
			
		||||
     */
 | 
			
		||||
    public static Vec2 ByteToNible(byte in){
 | 
			
		||||
        Vec2 ret = new Vec2();
 | 
			
		||||
        ret.x = (byte) (in >> 4);
 | 
			
		||||
        ret.y = (byte) (in & 15); // apply the mask '00001111'
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Transform 2 byte into 1 with a left part ( 4 bits ) and a right part ( 4 bits)
 | 
			
		||||
     * @param left first 4 bits
 | 
			
		||||
     * @param right last 4 bits
 | 
			
		||||
     * @return concatenated byte
 | 
			
		||||
     */
 | 
			
		||||
    public static byte NibbleToByte(byte left, byte right){
 | 
			
		||||
        return (byte) ((left << 4) | right);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +1,12 @@
 | 
			
		||||
package school_project;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is used to represent a position/vector/... any ensemble of 2 elements that have to work together in
 | 
			
		||||
 * a plan. This way we can use some basic operations over them.
 | 
			
		||||
 */
 | 
			
		||||
public class Vec2 {
 | 
			
		||||
public class Vec2 implements Serializable {
 | 
			
		||||
    public int x, y;
 | 
			
		||||
 | 
			
		||||
    public Vec2() {
 | 
			
		||||
@ -16,4 +18,12 @@ public class Vec2 {
 | 
			
		||||
        this.x = x;
 | 
			
		||||
        this.y = y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object obj) {
 | 
			
		||||
        if (obj instanceof Vec2 vec) {
 | 
			
		||||
            return this.x == vec.x && this.y == vec.y;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user