You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
446 lines
15 KiB
446 lines
15 KiB
package sig.jam.challenge;
|
|
|
|
import java.awt.Point;
|
|
import java.io.File;
|
|
import java.io.FileWriter;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import com.badlogic.gdx.Gdx;
|
|
import com.badlogic.gdx.graphics.Color;
|
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
|
|
|
public class Field {
|
|
int rows = 13;
|
|
int cols = 9;
|
|
double fieldSpd = 0.01;
|
|
double fieldOffset = 0;
|
|
List<Block> block_data = new ArrayList<Block>();
|
|
boolean horizontal_cursor = true; //If false, uses vertical cursor. Vertical cursor is 1x2 with the second block being above the initial position.
|
|
Point cursor_pos = new Point(0,0);
|
|
int player_numb = 0; //AI Controlled.
|
|
//ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
|
List<Point> position_update_list = new ArrayList<Point>();
|
|
int scheduledTasks=0;
|
|
BlockColor last_selected_col = BlockColor.INVISIBLE;
|
|
int same_select_count = 0;
|
|
public int ID = 0;
|
|
|
|
public Field() {
|
|
ID = JamChallenge.FIELD_IDENTIFIER++;
|
|
CreateNewRow();
|
|
}
|
|
|
|
public Field setHorizontalCursor(boolean horizontal_cursor) {
|
|
this.horizontal_cursor=horizontal_cursor;
|
|
return this;
|
|
}
|
|
|
|
public Field setPlayerNumber(int numb) {
|
|
this.player_numb=numb;
|
|
return this;
|
|
}
|
|
|
|
public void run() {
|
|
if (scheduledTasks>0) {
|
|
//System.out.prinln("Field "+player_numb+" scheduled tasks: "+scheduledTasks);
|
|
for (int i=0;i<position_update_list.size();i++) {
|
|
Point p = position_update_list.get(i);
|
|
CheckAndRemoveMatchingBlocks(p);
|
|
scheduledTasks--;
|
|
/*try {
|
|
Thread.sleep(100);
|
|
} catch (InterruptedException e) {
|
|
e.printStackTrace();
|
|
}*/
|
|
}
|
|
position_update_list.clear();
|
|
}
|
|
if (!RowsAreFilled() /*&&
|
|
scheduledTasks==0*/) {
|
|
fieldOffset += fieldSpd;
|
|
}
|
|
if (fieldOffset>=1) {
|
|
fieldOffset=0;
|
|
if (cursor_pos.y<rows-((horizontal_cursor)?0:1)-1) {
|
|
cursor_pos.y++;
|
|
}
|
|
}
|
|
if (fieldOffset==0) {
|
|
////System.out.prinln("TEST " + fieldOffset +"("+fieldOffset%1+")");
|
|
if (RowsAreFilled()) {
|
|
//TODO Game over scenario
|
|
|
|
} else {
|
|
CreateNewRow();
|
|
}
|
|
}
|
|
if (IsRealPlayer()) {
|
|
if (Gdx.input.isKeyJustPressed(JamChallenge.KEYSET_MAP.get(player_numb)[JamChallenge.KEYCODE_LEFT])) {
|
|
if (cursor_pos.x>0) {
|
|
cursor_pos.x--;
|
|
}
|
|
}
|
|
if (Gdx.input.isKeyJustPressed(JamChallenge.KEYSET_MAP.get(player_numb)[JamChallenge.KEYCODE_UP])) {
|
|
if (cursor_pos.y<rows-((horizontal_cursor)?0:1)-1) {
|
|
cursor_pos.y++;
|
|
}
|
|
}
|
|
if (Gdx.input.isKeyJustPressed(JamChallenge.KEYSET_MAP.get(player_numb)[JamChallenge.KEYCODE_RIGHT])) {
|
|
if (cursor_pos.x<cols-((horizontal_cursor)?1:0)-1) {
|
|
cursor_pos.x++;
|
|
}
|
|
}
|
|
if (Gdx.input.isKeyJustPressed(JamChallenge.KEYSET_MAP.get(player_numb)[JamChallenge.KEYCODE_DOWN])) {
|
|
if (cursor_pos.y>0) {
|
|
cursor_pos.y--;
|
|
}
|
|
}
|
|
if (Gdx.input.isKeyJustPressed(JamChallenge.KEYSET_MAP.get(player_numb)[JamChallenge.KEYCODE_ACTIONKEY])) {
|
|
Point cursor_pos2 = cursor_pos.getLocation();
|
|
if (horizontal_cursor) {
|
|
cursor_pos2.x++;
|
|
} else {
|
|
cursor_pos2.y++;
|
|
}
|
|
////System.out.prinln("POS1 Matches: "+DetectMatchedBlocks(this,cursor_pos).size()+" / POS2 Matches: "+DetectMatchedBlocks(this,cursor_pos2).size());
|
|
int b1 = ConvertCursorPositionToBlockID(this,cursor_pos);
|
|
int b2 = ConvertCursorPositionToBlockID(this,cursor_pos2);
|
|
Block block1 = block_data.get(b1);
|
|
Block block2 = block_data.get(b2);
|
|
if (block1.col!=BlockColor.INVISIBLE &&
|
|
block2.col!=BlockColor.INVISIBLE) {
|
|
block_data.set(b2, block1);
|
|
block_data.set(b1, block2);
|
|
|
|
CheckAndRemoveMatchingBlocks(cursor_pos);
|
|
CheckAndRemoveMatchingBlocks(cursor_pos2);
|
|
} else
|
|
if (block1.col!=BlockColor.INVISIBLE ^
|
|
block2.col!=BlockColor.INVISIBLE) {
|
|
block_data.set(b2, block1);
|
|
block_data.set(b1, block2);
|
|
|
|
if (block1.col==BlockColor.INVISIBLE) {
|
|
DropDownBlocksAbove(this,cursor_pos2);
|
|
DropBlockAllTheWayDown(this,cursor_pos);
|
|
} else
|
|
if (block2.col==BlockColor.INVISIBLE) {
|
|
DropDownBlocksAbove(this,cursor_pos);
|
|
DropBlockAllTheWayDown(this,cursor_pos2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DropBlockAllTheWayDown(Field field, Point blockPos) {
|
|
Point fallPos = blockPos.getLocation();
|
|
fallPos.y--;
|
|
int blockID2 = ConvertCursorPositionToBlockID(field, fallPos);
|
|
Block b2 = block_data.get(blockID2);
|
|
//System.out.prinln("In here. b2 is "+b2.col);
|
|
do {
|
|
/*File f = new File("debug.txt");
|
|
try {
|
|
FileWriter fw = new FileWriter(f,true);
|
|
fw.write("Inside do loop.\n");
|
|
fw.close();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}*/
|
|
if (blockID2<block_data.size() && blockID2>=0 && b2.col==BlockColor.INVISIBLE) {
|
|
fallPos.y--;
|
|
blockID2 = ConvertCursorPositionToBlockID(field, fallPos);
|
|
if (blockID2<block_data.size() && blockID2>=0) {
|
|
b2 = block_data.get(blockID2);
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
fallPos.y++;
|
|
blockID2 = ConvertCursorPositionToBlockID(field, fallPos);
|
|
if (blockID2<block_data.size() && blockID2>=0) {
|
|
b2 = block_data.get(blockID2);
|
|
} else {
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
} while (true);
|
|
//System.out.prinln("Swapping to "+fallPos);
|
|
SwapBlocks(blockPos,fallPos,true);
|
|
}
|
|
|
|
private void DropDownBlocksAbove(Field field, Point fallPos) {
|
|
Point targetPos = fallPos.getLocation();
|
|
List<Point> updatePoints = new ArrayList<Point>();
|
|
for (int y=targetPos.y+1;y<rows;y++) {
|
|
Point blockPos = targetPos.getLocation();
|
|
blockPos.y=y;
|
|
SwapBlocks(blockPos,targetPos,false);
|
|
updatePoints.add(blockPos.getLocation());
|
|
updatePoints.add(targetPos.getLocation());
|
|
targetPos.y++;
|
|
}
|
|
for (Point p : updatePoints) {
|
|
scheduledTasks++;
|
|
position_update_list.add(p);
|
|
}
|
|
}
|
|
|
|
private void SwapBlocks(Point pos1, Point pos2, boolean checkmatches) {
|
|
int pos1_id = ConvertCursorPositionToBlockID(this,pos1);
|
|
int pos2_id = ConvertCursorPositionToBlockID(this,pos2);
|
|
if (pos1_id<block_data.size() && pos1_id>=0 &&
|
|
pos2_id<block_data.size() && pos2_id>=0) {
|
|
Block b1 = block_data.get(pos1_id);
|
|
Block b2 = block_data.get(pos2_id);
|
|
block_data.set(pos2_id, b1);
|
|
block_data.set(pos1_id, b2);
|
|
if (checkmatches) {
|
|
scheduledTasks++;
|
|
position_update_list.add(pos1.getLocation());
|
|
scheduledTasks++;
|
|
position_update_list.add(pos2.getLocation());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckAndRemoveMatchingBlocks(Point target_pos) {
|
|
// The first integer stores the X position of each cleared area.
|
|
// The second integer stores the highest/lowest Y space of each cleared area. To determine fall distance.
|
|
//
|
|
HashMap<Integer,Integer> HighPOS = new HashMap<Integer,Integer>(); //Blocks above here will fall.
|
|
HashMap<Integer,Integer> LowPOS = new HashMap<Integer,Integer>(); //Blocks will fall to this level.
|
|
|
|
/*List<Block> matched_blocks = DetectMatchedBlocks(this,cursor_pos);
|
|
for (Block b : matched_blocks) {
|
|
b.col = BlockColor.INVISIBLE;
|
|
AddBlockToGravityList(HighPOS, LowPOS, b);
|
|
}
|
|
if (matched_blocks.size()>0) {
|
|
Block cursorBlock = block_data.get(ConvertCursorPositionToBlockID(this,cursor_pos));
|
|
cursorBlock.col=BlockColor.INVISIBLE;
|
|
AddBlockToGravityList(HighPOS, LowPOS, cursorBlock);
|
|
}*/
|
|
List<Block> matched_blocks = DetectMatchedBlocks(this,target_pos);
|
|
for (Block b : matched_blocks) {
|
|
b.col = BlockColor.INVISIBLE;
|
|
AddBlockToGravityList(HighPOS, LowPOS, b);
|
|
}
|
|
if (matched_blocks.size()>0) {
|
|
Block cursorBlock2 = block_data.get(ConvertCursorPositionToBlockID(this,target_pos));
|
|
cursorBlock2.col=BlockColor.INVISIBLE;
|
|
AddBlockToGravityList(HighPOS, LowPOS, cursorBlock2);
|
|
}
|
|
|
|
//System.out.prinln(HighPOS.toString());
|
|
//System.out.prinln(LowPOS.toString());
|
|
|
|
for (Integer i : HighPOS.keySet()) {
|
|
for (int y=HighPOS.get(i)+1;y<rows;y++) {
|
|
Point blockPos = new Point(i,y);
|
|
int blockID = ConvertCursorPositionToBlockID(this,blockPos);
|
|
if (blockID<block_data.size() && blockID>=0) {
|
|
Point fallPos = blockPos.getLocation();
|
|
fallPos.y-=HighPOS.get(i)-LowPOS.get(i);
|
|
////System.out.prinln("Block at position "+blockPos+" moved down by "+(HighPOS.get(i)-LowPOS.get(i)));
|
|
int fallBlockID = ConvertCursorPositionToBlockID(this,fallPos);
|
|
Block b1 = block_data.get(fallBlockID);
|
|
Block b2 = block_data.get(blockID);
|
|
block_data.set(fallBlockID, b2);
|
|
block_data.set(blockID, b1);
|
|
scheduledTasks++;
|
|
position_update_list.add(fallPos.getLocation());
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private void AddBlockToGravityList(HashMap<Integer, Integer> HighPOS, HashMap<Integer, Integer> LowPOS, Block b) {
|
|
Point pos = ConvertBlockIDToCursorPosition(this,block_data.indexOf(b));
|
|
if (HighPOS.containsKey(pos.x)) {
|
|
if (pos.y>HighPOS.get(pos.x)) {
|
|
HighPOS.put(pos.x, pos.y);
|
|
}
|
|
} else {
|
|
HighPOS.put(pos.x, pos.y);
|
|
}
|
|
if (LowPOS.containsKey(pos.x)) {
|
|
if (pos.y-1<LowPOS.get(pos.x)) {
|
|
LowPOS.put(pos.x, pos.y-1);
|
|
}
|
|
} else {
|
|
LowPOS.put(pos.x, pos.y-1);
|
|
}
|
|
}
|
|
|
|
private boolean RowsAreFilled() {
|
|
if (block_data.size()>=(rows+1)*cols) {
|
|
if (TopRowIsCompletelyInvisible()) {
|
|
for (int i=0;i<9;i++) {
|
|
block_data.remove(0);
|
|
}
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private boolean TopRowIsCompletelyInvisible() {
|
|
for (int i=0;i<9;i++) {
|
|
if (block_data.get(i).col!=BlockColor.INVISIBLE) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private boolean IsRealPlayer() {
|
|
return player_numb>0;
|
|
}
|
|
|
|
private void CreateNewRow() {
|
|
for (int i=0;i<cols;i++) {
|
|
BlockColor col = last_selected_col;
|
|
do {
|
|
col = BlockColor.getRandomColor(5);
|
|
//if (player_numb>0) {System.out.println("Selected "+col);}
|
|
} while(same_select_count==1 && col==last_selected_col);
|
|
if (col==last_selected_col) {
|
|
same_select_count++;
|
|
} else {
|
|
same_select_count=0;
|
|
last_selected_col = col;
|
|
}
|
|
block_data.add(new Block(col));
|
|
/*if (block_data.size()>cols) {
|
|
scheduledTasks++;
|
|
position_update_list.add(ConvertBlockIDToCursorPosition(this,block_data.size()-1-cols));
|
|
}*/
|
|
}
|
|
for (int i=0;i<cols;i++) {
|
|
scheduledTasks++;
|
|
position_update_list.add(ConvertBlockIDToCursorPosition(this,block_data.size()-1-i));
|
|
}
|
|
}
|
|
|
|
public void draw(SpriteBatch batch, int fieldX, int fieldY) {
|
|
int blockRows = block_data.size()/cols;
|
|
for (int y=blockRows-1;y>=0;y--) {
|
|
for (int x=0;x<cols;x++) {
|
|
Block b = block_data.get((blockRows-1-y)*cols+x);
|
|
batch.setColor(b.col.col);
|
|
batch.draw(JamChallenge.onebyone,
|
|
(int)(fieldX+(x*JamChallenge.BLOCK_WIDTH)),
|
|
(int)(fieldY+(y*JamChallenge.BLOCK_HEIGHT)+(fieldOffset*JamChallenge.BLOCK_HEIGHT)),
|
|
JamChallenge.BLOCK_WIDTH,
|
|
JamChallenge.BLOCK_HEIGHT);
|
|
if (y==0) {
|
|
batch.setColor(new Color(0.4f,0.4f,0.4f,0.9f));
|
|
batch.draw(JamChallenge.onebyone,
|
|
(int)(fieldX+(x*JamChallenge.BLOCK_WIDTH)),
|
|
(int)(fieldY+(y*JamChallenge.BLOCK_HEIGHT)+(fieldOffset*JamChallenge.BLOCK_HEIGHT)),
|
|
JamChallenge.BLOCK_WIDTH,
|
|
JamChallenge.BLOCK_HEIGHT);
|
|
}
|
|
}
|
|
}
|
|
RenderCursor(batch,fieldX,fieldY);
|
|
batch.setColor(Color.WHITE);
|
|
}
|
|
|
|
private void RenderCursor(SpriteBatch batch, int fieldX, int fieldY) {
|
|
batch.setColor(new Color(1f,1f,1f,0.6f));
|
|
if (horizontal_cursor) {
|
|
batch.draw(JamChallenge.onebyone,fieldX+cursor_pos.x*JamChallenge.BLOCK_WIDTH,(int)((fieldOffset*JamChallenge.BLOCK_HEIGHT)+fieldY+JamChallenge.BLOCK_HEIGHT+cursor_pos.y*JamChallenge.BLOCK_HEIGHT),JamChallenge.BLOCK_WIDTH*2,JamChallenge.BLOCK_HEIGHT);
|
|
} else {
|
|
batch.draw(JamChallenge.onebyone,fieldX+cursor_pos.x*JamChallenge.BLOCK_WIDTH,(int)((fieldOffset*JamChallenge.BLOCK_HEIGHT)+fieldY+JamChallenge.BLOCK_HEIGHT+16+cursor_pos.y*JamChallenge.BLOCK_HEIGHT),JamChallenge.BLOCK_WIDTH,JamChallenge.BLOCK_HEIGHT*2);
|
|
}
|
|
}
|
|
|
|
/***
|
|
*
|
|
* @param field The field to check for matches on.
|
|
* @param targetBlockPos The X and Y coord of the block in the grid to check for matches.
|
|
* @return
|
|
*/
|
|
public static List<Block> DetectMatchedBlocks(Field field, Point targetBlockPos) {
|
|
List<Block> blocklist = field.block_data;
|
|
|
|
List<Block> vertical_matches = new ArrayList<Block>();
|
|
List<Block> horizontal_matches = new ArrayList<Block>();
|
|
|
|
int blockID = ConvertCursorPositionToBlockID(field, targetBlockPos);
|
|
|
|
List<Block> matched_blocks = new ArrayList<Block>();
|
|
if (blockID<field.block_data.size() && blockID>=0) {
|
|
Block targetblock = blocklist.get(blockID);
|
|
|
|
int markerX=0;
|
|
int markerY=1;
|
|
//Vertical Check
|
|
CheckForConnectingBlocks(field, targetBlockPos, blocklist, vertical_matches, targetblock, 0, 1); //Checks for connecting blocks going up.
|
|
CheckForConnectingBlocks(field, targetBlockPos, blocklist, vertical_matches, targetblock, 0, -1); //Checks for connecting blocks going down.
|
|
CheckForConnectingBlocks(field, targetBlockPos, blocklist, horizontal_matches, targetblock, -1, 0); //Checks for connecting blocks going left.
|
|
CheckForConnectingBlocks(field, targetBlockPos, blocklist, horizontal_matches, targetblock, 1, 0); //Checks for connecting blocks going right.
|
|
|
|
if (vertical_matches.size()>=2) {
|
|
matched_blocks.addAll(vertical_matches);
|
|
}
|
|
if (horizontal_matches.size()>=2) {
|
|
matched_blocks.addAll(horizontal_matches);
|
|
}
|
|
}
|
|
return matched_blocks;
|
|
}
|
|
|
|
private static void CheckForConnectingBlocks(Field field, Point targetBlockPos, List<Block> blocklist,
|
|
List<Block> matches_list, Block targetblock, int markerX, int markerY) {
|
|
boolean match=true;
|
|
Point targetPoint = targetBlockPos.getLocation();
|
|
while (match) {
|
|
/*File f = new File("debug.txt");
|
|
try {
|
|
FileWriter fw = new FileWriter(f,true);
|
|
fw.write("Inside while loop.\n");
|
|
fw.close();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}*/
|
|
match=false;
|
|
targetPoint.x+=markerX;
|
|
targetPoint.y+=markerY;
|
|
int checkBlockID = ConvertCursorPositionToBlockID(field,targetPoint);
|
|
if (checkBlockID<blocklist.size() && checkBlockID>=0 &&
|
|
targetPoint.x>=0 && targetPoint.x<field.cols &&
|
|
targetPoint.y>=-1 && targetPoint.y<field.rows) {
|
|
Block checkblock = blocklist.get(checkBlockID);
|
|
if (checkblock.col!=BlockColor.INVISIBLE &&
|
|
targetblock.col == checkblock.col) {
|
|
match=true;
|
|
matches_list.add(checkblock);
|
|
}
|
|
} else {
|
|
System.out.println(checkBlockID+": "+targetPoint+" out of bounds!");
|
|
}
|
|
}
|
|
}
|
|
|
|
private static int ConvertCursorPositionToBlockID(Field field, Point targetBlockPos) {
|
|
return targetBlockPos.x+((((field.block_data.size()/field.cols)-targetBlockPos.y-2)*field.cols));
|
|
}
|
|
|
|
private static Point ConvertBlockIDToCursorPosition(Field field, int blockID) {
|
|
return new Point(blockID%field.cols,(field.block_data.size()/field.cols)-(blockID/field.cols)-2);
|
|
}
|
|
}
|
|
|