Currently i'm creating tic-tac-toe-game in android
i'm successfully created game but facing some issues
Here is my code that i have tried so far
Here is My BoardView
public class BoardView extends View implements GestureDetector.OnGestureListener, ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
private static final int STROKE_WIDTH = 10;
private static final int SWEEPER_WIDTH = 20;
private float[] gridLinePoints;
private Paint gridPaint;
private PointF[][] centerPoints;
private Paint signPaint;
private List<SignData> signDataList;
private #Constants.WinLinePosition int winLinePosition;
private Paint winLinePaint;
private GestureDetector clickDetector;
private OnBoardInteractionListener onBoardInteractionListener;
private ValueAnimator clickAnimator;
private ValueAnimator winLineAnimator;
private ValueAnimator resetAnimator;
private float signRadius;
private float winLineLength;
private float sweeperStartPosition;
private Paint sweeperPaint;
private int[] sweeperColors;
private float[] sweeperStops;
public BoardView(Context context) {
super(context);
init();
}
public BoardView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public BoardView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#TargetApi(Build.VERSION_CODES.M)
private void init() {
gridLinePoints = new float[16];
centerPoints = new PointF[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
centerPoints[i][j] = new PointF();
}
}
signDataList = new ArrayList<>();
winLinePosition = Constants.NONE;
gridPaint = new Paint();
gridPaint.setColor(getContext().getResources().getColor(R.color.holo_green_dark, null));
gridPaint.setAntiAlias(true);
gridPaint.setStrokeWidth(dpToPx(STROKE_WIDTH));
gridPaint.setStrokeCap(Paint.Cap.ROUND);
signPaint = new Paint();
signPaint.setColor(getContext().getResources().getColor(R.color.holo_orange_dark, null));
signPaint.setAntiAlias(true);
signPaint.setStyle(Paint.Style.STROKE);
signPaint.setStrokeWidth(dpToPx(STROKE_WIDTH));
signPaint.setStrokeCap(Paint.Cap.ROUND);
winLinePaint = new Paint();
winLinePaint.setColor(getContext().getResources().getColor(R.color.holo_red_dark, null));
winLinePaint.setAntiAlias(true);
winLinePaint.setStrokeWidth(dpToPx(STROKE_WIDTH));
winLinePaint.setStrokeCap(Paint.Cap.ROUND);
clickDetector = new GestureDetector(getContext(), this);
clickAnimator = new ValueAnimator();
clickAnimator.setDuration(150);
clickAnimator.setInterpolator(new DecelerateInterpolator());
clickAnimator.addUpdateListener(this);
clickAnimator.addListener(this);
winLineAnimator = new ValueAnimator();
winLineAnimator.setDuration(150);
winLineAnimator.setInterpolator(new DecelerateInterpolator());
winLineAnimator.addUpdateListener(this);
winLineAnimator.addListener(this);
resetAnimator = new ValueAnimator();
resetAnimator.setDuration(500);
resetAnimator.setInterpolator(new AccelerateInterpolator());
resetAnimator.addUpdateListener(this);
resetAnimator.addListener(this);
sweeperPaint = new Paint();
sweeperPaint.setAntiAlias(true);
sweeperPaint.setStyle(Paint.Style.FILL);
sweeperColors = new int[3];
sweeperColors[0] = Color.parseColor("#0000DDFF");
sweeperColors[1] = Color.parseColor("#FF00DDFF");
sweeperColors[2] = Color.parseColor("#0000DDFF");
sweeperStops = new float[3];
sweeperStops[0] = 0;
sweeperStops[1] = 0.5f;
sweeperStops[2] = 1;
setLayerType(LAYER_TYPE_SOFTWARE, sweeperPaint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
getLayoutParams().height = getMeasuredWidth();
setGridLinePoints();
setCenterPoints();
setAnimationValues();
}
#Override
protected void onDraw(Canvas canvas) {
drawGrid(canvas);
super.onDraw(canvas);
if (resetAnimator.isRunning()) {
canvas.clipRect(0, sweeperStartPosition, getMeasuredWidth(), getMeasuredWidth());
setSweeperGradient();
canvas.drawRect(0, sweeperStartPosition, getMeasuredWidth(), sweeperStartPosition + dpToPx(SWEEPER_WIDTH), sweeperPaint);
}
drawSigns(canvas);
drawWinLine(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if ((!isEnabled()) || (clickAnimator.isRunning()) || (isAnimationFlagSet())) {
return super.onTouchEvent(event);
} else {
return clickDetector.onTouchEvent(event);
}
}
private boolean isAnimationFlagSet() {
for (SignData signData : signDataList) {
if (signData.isAnimationFlag()) {
return true;
}
}
return false;
}
private void setGridLinePoints() {
int side = getMeasuredWidth();
float padding = dpToPx(STROKE_WIDTH / 2f);
gridLinePoints[0] = gridLinePoints[4] = gridLinePoints[9] = gridLinePoints[13] = padding;
gridLinePoints[1] = gridLinePoints[3] = gridLinePoints[8] = gridLinePoints[10] = side / 3f;
gridLinePoints[2] = gridLinePoints[6] = gridLinePoints[11] = gridLinePoints[15] = side - padding;
gridLinePoints[5] = gridLinePoints[7] = gridLinePoints[12] = gridLinePoints[14] = (2 * side) / 3f;
}
private void setCenterPoints() {
float a = getMeasuredWidth() / 6f;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
centerPoints[i][j].x = a + (j * (2 * a));
centerPoints[i][j].y = a + (i * (2 * a));
}
}
}
private void setAnimationValues() {
clickAnimator.setFloatValues(0, (getMeasuredWidth() / 6f) - dpToPx(2 * STROKE_WIDTH));
winLineAnimator.setFloatValues(0, getMeasuredWidth());
resetAnimator.setFloatValues(-dpToPx(SWEEPER_WIDTH), getMeasuredWidth());
}
private void setSweeperGradient() {
float axis = sweeperStartPosition + (dpToPx(SWEEPER_WIDTH / 2f));
LinearGradient horizontalGradient = new LinearGradient(0, axis, getMeasuredWidth(), axis,
sweeperColors, sweeperStops, Shader.TileMode.CLAMP);
LinearGradient verticalGradient = new LinearGradient(getMeasuredWidth() / 2f, sweeperStartPosition,
getMeasuredWidth() / 2f, sweeperStartPosition + dpToPx(SWEEPER_WIDTH), sweeperColors, sweeperStops,
Shader.TileMode.CLAMP);
ComposeShader shader = new ComposeShader(horizontalGradient, verticalGradient, PorterDuff.Mode.MULTIPLY);
sweeperPaint.setShader(shader);
}
private void drawGrid(Canvas canvas) {
canvas.drawLines(gridLinePoints, gridPaint);
}
private void drawSigns(Canvas canvas) {
for (int i = 0; i < signDataList.size(); i++) {
SignData signData = signDataList.get(i);
switch (signData.getSign()) {
case Constants.CIRCLE:
drawCircle(canvas, centerPoints[signData.getRow()][signData.getColumn()], signData.isAnimationFlag());
break;
case Constants.CROSS:
drawCross(canvas, centerPoints[signData.getRow()][signData.getColumn()], signData.isAnimationFlag());
break;
case Constants.EMPTY:
break;
}
}
}
private void drawCircle(Canvas canvas, PointF center, boolean animationFlag) {
float radius = animationFlag ? signRadius : (getMeasuredWidth() / 6f) - dpToPx(2 * STROKE_WIDTH);
canvas.drawCircle(center.x, center.y, radius, signPaint);
}
private void drawCross(Canvas canvas, PointF center, boolean animationFlag) {
float radius = animationFlag ? signRadius : (getMeasuredWidth() / 6f) - dpToPx(2 * STROKE_WIDTH);
canvas.drawLine(center.x - radius, center.y - radius, center.x + radius, center.y + radius, signPaint);
canvas.drawLine(center.x - radius, center.y + radius, center.x + radius, center.y - radius, signPaint);
}
private void drawWinLine(Canvas canvas) {
float length = winLineLength;
float a = getMeasuredWidth() / 6f;
float padding = dpToPx(STROKE_WIDTH);
switch (winLinePosition) {
case Constants.NONE:
break;
case Constants.ROW_1:
canvas.drawLine(padding, a, length - padding, a, winLinePaint);
break;
case Constants.ROW_2:
canvas.drawLine(padding, a + (2 * a), length - padding, a + (2 * a), winLinePaint);
break;
case Constants.ROW_3:
canvas.drawLine(padding, a + (4 * a), length - padding, a + (4 * a), winLinePaint);
break;
case Constants.COLUMN_1:
canvas.drawLine(a, padding, a, length - padding, winLinePaint);
break;
case Constants.COLUMN_2:
canvas.drawLine(a + (2 * a), padding, a + (2 * a), length - padding, winLinePaint);
break;
case Constants.COLUMN_3:
canvas.drawLine(a + (4 * a), padding, a + (4 * a), length - padding, winLinePaint);
break;
case Constants.DIAGONAL_1:
canvas.drawLine(padding, padding, length - padding, length - padding, winLinePaint);
break;
case Constants.DIAGONAL_2:
canvas.drawLine(getMeasuredWidth() - padding, padding, padding + getMeasuredWidth()
- length, length - padding, winLinePaint);
break;
}
}
void addSignToBoard(#Constants.Sign int sign, int row, int column) {
SignData signData = new SignData();
signData.setSign(sign);
signData.setRow(row);
signData.setColumn(column);
signData.setAnimationFlag(true);
if (clickAnimator.isRunning()) {
clickAnimator.end();
}
signDataList.add(signData);
clickAnimator.start();
}
void showWinLine(#Constants.WinLinePosition int winLinePosition) {
this.winLinePosition = winLinePosition;
winLineAnimator.start();
}
void resetBoard() {
if (!resetAnimator.isRunning()) {
resetAnimator.start();
}
}
boolean isAlreadyAdded(int row, int column) {
for (int i = 0; i < signDataList.size(); i++) {
SignData signData = signDataList.get(i);
if ((signData.getRow() == row) && (signData.getColumn() == column)) {
return true;
}
}
return false;
}
private float dpToPx(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());
}
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public void onShowPress(MotionEvent e) {
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
float x = e.getX();
float y = e.getY();
int row = detectIndexOfPartition(y);
int column = detectIndexOfPartition(x);
if ((row != -1) && (column != -1)) {
onBoardInteractionListener.onBoardClick(BoardView.this, row, column);
}
return true;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
#Override
public void onLongPress(MotionEvent e) {
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
private int detectIndexOfPartition(float value) {
float maxValue = getMeasuredWidth();
float totalNumberOfPartitions = 3;
float lengthOfSinglePartition = maxValue / totalNumberOfPartitions;
return (int) (value / lengthOfSinglePartition);
}
public void setOnBoardInteractionListener(OnBoardInteractionListener onBoardInteractionListener) {
this.onBoardInteractionListener = onBoardInteractionListener;
}
#Override
public void onAnimationUpdate(ValueAnimator animation) {
if (animation == clickAnimator) {
signRadius = (float) animation.getAnimatedValue();
} else if (animation == winLineAnimator) {
winLineLength = (float) animation.getAnimatedValue();
} else if (animation == resetAnimator) {
sweeperStartPosition = (float) animation.getAnimatedValue();
}
invalidate();
}
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
if (animation == clickAnimator) {
SignData signData = signDataList.get(signDataList.size() - 1);
signData.setAnimationFlag(false);
onBoardInteractionListener.onSignAdded(signData.getSign(), signData.getRow(), signData.getColumn());
signRadius = 0;
} else if (animation == resetAnimator) {
signDataList.clear();
winLinePosition = Constants.NONE;
onBoardInteractionListener.onBoardReset();
}
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
interface OnBoardInteractionListener {
void onBoardClick(BoardView board, int row, int column);
void onSignAdded(#Constants.Sign int sign, int row, int column);
void onBoardReset();
}
private class SignData {
private #Constants.Sign int sign;
private int row;
private int column;
private boolean animationFlag;
#Constants.Sign int getSign() {
return sign;
}
void setSign(#Constants.Sign int sign) {
this.sign = sign;
}
int getRow() {
return row;
}
void setRow(int row) {
this.row = row;
}
int getColumn() {
return column;
}
void setColumn(int column) {
this.column = column;
}
boolean isAnimationFlag() {
return animationFlag;
}
void setAnimationFlag(boolean animationFlag) {
this.animationFlag = animationFlag;
}
}
}
My Brain class
class Brain {
private static Brain INSTANCE;
private #Constants.Sign
int[][] board = new int[3][3];
private int rowOfResult;
private int columnOfResult;
private int depth;
private #Constants.Sign
int computerSign;
private #Constants.Sign
int playerSign;
private OnProcessCompleteListener onProcessCompleteListener;
private static final int HORIZONTAL = 0;
private static final int VERTICAL = 1;
private static final int DIAGONAL = 2;
#IntDef({HORIZONTAL, VERTICAL, DIAGONAL})
#interface DirectionOfWinLine {
}
// References used by isWin function.
private int[] winSequence = new int[3];
private int[] row = new int[3];
private int[] column = new int[3];
private int[] diagonal1 = new int[3];
private int[] diagonal2 = new int[3];
private Brain() {
}
static Brain getInstance() {
if (INSTANCE == null) {
INSTANCE = new Brain();
}
return INSTANCE;
}
void play() {
if (onProcessCompleteListener == null) {
return;
}
calculateNextMove(computerSign, depth);
onProcessCompleteListener.onNextMoveCalculated(rowOfResult, columnOfResult);
}
private int calculateNextMove(#Constants.Sign int sign, int depth) {
if (isWin(computerSign, false)) {
return 10 - depth;
} else if (isWin(playerSign, false)) {
return depth - 10;
}
if (depth >= 9) {
return 0;
}
List<Integer> scores = new ArrayList<>(), rowIndices = new ArrayList<>(), columnIndices = new ArrayList<>();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == Constants.EMPTY) {
board[i][j] = sign;
scores.add(calculateNextMove(getOppositeSign(sign), depth + 1));
rowIndices.add(i);
columnIndices.add(j);
board[i][j] = Constants.EMPTY;
}
}
}
if (sign == computerSign) {
int maxScore = -100;
for (int i = 0; i < scores.size(); i++) {
if (scores.get(i) > maxScore) {
maxScore = scores.get(i);
}
}
return randomizeScore(maxScore, scores, rowIndices, columnIndices);
} else {
int minScore = 100;
for (int i = 0; i < scores.size(); i++) {
if (scores.get(i) < minScore) {
minScore = scores.get(i);
}
}
return randomizeScore(minScore, scores, rowIndices, columnIndices);
}
}
private int randomizeScore(int score, List<Integer> scores, List<Integer> rowIndices, List<Integer> columnIndices) {
List<Integer> equalScoreIndices = new ArrayList<>();
for (int i = 0; i < scores.size(); i++) {
if (scores.get(i) == score) {
equalScoreIndices.add(i);
}
}
Random rand = new Random();
int randomIndex = equalScoreIndices.get(rand.nextInt(equalScoreIndices.size()));
rowOfResult = rowIndices.get(randomIndex);
columnOfResult = columnIndices.get(randomIndex);
return score;
}
private boolean isWin(#Constants.Sign int sign, boolean notifyWinEnabled) {
for (int i = 0; i < 3; i++) {
winSequence[i] = sign;
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == j) {
diagonal1[i] = board[i][j];
}
if ((i + j) == 2) {
diagonal2[i] = board[i][j];
}
row[j] = board[i][j];
column[j] = board[j][i];
}
if (isEqual(row, winSequence)) {
if (notifyWinEnabled) {
notifyWin(sign, HORIZONTAL, i + 1);
}
return true;
} else if (isEqual(column, winSequence)) {
if (notifyWinEnabled) {
notifyWin(sign, VERTICAL, i + 1);
}
return true;
}
}
if (isEqual(diagonal1, winSequence)) {
if (notifyWinEnabled) {
notifyWin(sign, DIAGONAL, 1);
}
return true;
} else if (isEqual(diagonal2, winSequence)) {
if (notifyWinEnabled) {
notifyWin(sign, DIAGONAL, 2);
}
return true;
}
return false;
}
private boolean isEqual(int[] x, int[] y) {
for (int i = 0; i < 3; i++) {
if (x[i] != y[i]) {
return false;
}
}
return true;
}
void analyzeBoard() {
if (onProcessCompleteListener == null) {
return;
}
if ((!isWin(Constants.CIRCLE, true)) && (!isWin(Constants.CROSS, true)) && (depth >= 9)) {
onProcessCompleteListener.onGameDraw();
}
}
private void notifyWin(#Constants.Sign int sign, #DirectionOfWinLine int direction, int index) {
if (onProcessCompleteListener == null) {
return;
}
#Constants.WinLinePosition int winLinePosition = Constants.NONE;
switch (direction) {
case HORIZONTAL:
switch (index) {
case 1:
winLinePosition = Constants.ROW_1;
break;
case 2:
winLinePosition = Constants.ROW_2;
break;
case 3:
winLinePosition = Constants.ROW_3;
break;
}
break;
case VERTICAL:
switch (index) {
case 1:
winLinePosition = Constants.COLUMN_1;
break;
case 2:
winLinePosition = Constants.COLUMN_2;
break;
case 3:
winLinePosition = Constants.COLUMN_3;
break;
}
break;
case DIAGONAL:
switch (index) {
case 1:
winLinePosition = Constants.DIAGONAL_1;
break;
case 2:
winLinePosition = Constants.DIAGONAL_2;
break;
}
break;
}
onProcessCompleteListener.onGameWin(sign, winLinePosition);
}
void reset() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = Constants.EMPTY;
}
}
depth = 0;
}
void setComputerSign(int computerSign) {
this.computerSign = computerSign;
playerSign = getOppositeSign(computerSign);
}
void updateBoard(#Constants.Sign int sign, int row, int column) {
board[row][column] = sign;
depth++;
}
private #Constants.Sign
int getOppositeSign(#Constants.Sign int sign) {
return sign == Constants.CIRCLE ? Constants.CROSS : Constants.CIRCLE;
}
void setOnProcessCompleteListener(OnProcessCompleteListener onProcessCompleteListener) {
this.onProcessCompleteListener = onProcessCompleteListener;
}
interface OnProcessCompleteListener {
void onNextMoveCalculated(int row, int column);
void onGameWin(#Constants.Sign int sign, #Constants.WinLinePosition int winLinePosition);
void onGameDraw();
}
void destroy() {
INSTANCE = null;
}
}
I have created github repo for this all code available here
https://github.com/SuperSaiyanGoku3/MyGame
I'm facing some issue in above code
The Above code only support hard level (Impossible), how can i create easy medium and hard level in above game algorithm again computer(CPU).
how can i set custom icon instead of O and X
how can i set all three game mode randomly in above code, as easy medium and hard level, so when user start the game, cpu will come randomly, wither easy or medium or hard.
Here are some links that i have tried so far but unable to understand how to create easy medium and hard level
Learn to create a Tic-Tac-Toe Game for Android
Android Studio - JAVA - TIC TAC TOE
Android tic tac toe game - logic issue
Tic-Tac-Toe (TableLayout) Android App
Tic Tac Toe Game
If need more information please do let me know. Thanks in advance. Your efforts will be appreciated.
Implement difficulty: For support easy and medium difficulty, I suggest you just use random. You have implemented HARD difficulty, so you just need lesser difficult logic that making "mistakes", and this mistake can be implemented by random.
private void calculateNextMoveRandom() {
Random rand = new Random();
int randomRow;
int randomColumn;
while (true) {
randomRow = rand.nextInt(3);
randomColumn = rand.nextInt(3);
if (Constants.EMPTY == board[randomRow][randomColumn]) {
rowOfResult = randomRow;
columnOfResult = randomColumn;
return;
}
}
}
2. **Bitmap marker:** You can use `BitmapFactory.decodeResource()` to draw bitmap on screen.
private void drawCircle(Canvas canvas, PointF center, boolean animationFlag) {
int iconSize = (int) LayoutUtil.getPixelFromDp(MARKER_SIZE, getContext());
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android);
Bitmap scaled = Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, true);
canvas.drawBitmap(scaled, center.x - (iconSize >> 1), center.y - (iconSize >> 1), signPaint);
}
3. **Random difficulty:** Just use random to set difficulty.
brain.setDifficulty(new Random().nextInt(3));
Here is my pull request: (Fallen link)
https://github.com/SuperSaiyanGoku3/MyGame/pull/1
If you are using a minimax strategy to play tic-tac-toe, you can have multiple switch cases that correspond to different difficulty levels in the game. The most naive method of doing this is by putting different depth thresholds in the minimax tree. For example, you can expand the minimax game tree until only depth 2 (assuming for a 3*3 tic-tac-toe) for easy level and say until the end of the search tree for the highest difficulty level. You can set this threshold depending on the board size and the difficulty level expected.
Another way of implementing difficulty levels is by implementing different heuristic functions to calculate the board score (a goodness measure to the current state of the board). You can have your heuristic function that evaluates the individual row/column/diagonal score based on the number of cells that you occupy in that row/column/diagonal. For example, if the number of cells occupied is 1, then score = x (x can be any arbitrary number). If the number of cells occupied is 2, then score = x^2 and if it is 3, then score = x^3. Then multiply all individual line scores to get a measure of goodness (or you can think of this as a winning probability) in each row, column or diagonal. You can calculate a similar score for your opponent and then take a difference to get a board score. Thus the idea is to implement different ways of evaluating current board states by designing different variations of the heuristic function for each difficulty level. A bad heuristic function would work as an easy level since it will lose a lot of games whereas a properly designed heuristic will have a no-lose policy (it will end up winning or drawing the game).
In order to randomly choose a difficulty level at each run of the game, you can use a random number generator to pick a difficulty level. You can assign '0' as easy, '1' as medium and '2' as hard. You can use the following java function to generate an integer between 0 and (n-1)
int random = Random.nextInt(n)
Complete Tic Tac Toe with "n x n matrix"
Basic ideas is that we just have to check if column / row / diagonal elements are same.
code written in C#, with basic unit test.
I am doing this project that simulates the solar system using java's stdDraw. I want to make the change where I can show the trace of the corn, because my ultimate goal is to make this corn fly in a heart shape and if I can draw out the trace of the corn I can present the heart. Right now I've been trying to do it, but it seems like the background image is blocking the trace. And if I comment out the background image, all of the planets will show their trace. I don't know what to do, help!!!
Here is the Object Class:
public class BodyExtreme{
public double xxPos;
public double yyPos;
public double xxVel;
public double yyVel;
public double mass;
public String imgFileName;
private static final double G = 6.67e-11;
public BodyExtreme(double xP, double yP, double xV, double yV, double m, String img){
xxPos = xP;
yyPos = yP;
xxVel = xV;
yyVel = yV;
mass = m;
imgFileName = img;
}
public BodyExtreme(BodyExtreme b){
xxPos = b.xxPos;
yyPos = b.yyPos;
xxVel = b.xxVel;
yyVel = b.yyVel;
mass = b.mass;
imgFileName = b.imgFileName;
}
public double calcDistance(BodyExtreme b) {
double dx = b.xxPos - this.xxPos;
double dy = b.yyPos - this.yyPos;
return Math.sqrt(dx * dx + dy * dy);
}
public double calcForceExertedBy(BodyExtreme b) {
if (this.calcDistance(b) == 0) {
return 0;
} else {
return (G * b.mass * this.mass)/(this.calcDistance(b) * this.calcDistance(b));
}
}
public double calcForceExertedByX(BodyExtreme b) {
return (this.calcForceExertedBy(b) * (b.xxPos - this.xxPos) / this.calcDistance(b));
}
public double calcForceExertedByY(BodyExtreme b) {
return (this.calcForceExertedBy(b) * (b.yyPos - this.yyPos) / this.calcDistance(b));
}
public double calcNetForceExertedByX(BodyExtreme[] b) {
int i = 0;
double sum = 0;
while (i < b.length) {
if (this.equals(b[i])) {
sum += 0;
i += 1;
} else {
sum = sum + this.calcForceExertedByX(b[i]);
i += 1;
}
} return sum;
}
public double calcNetForceExertedByY(BodyExtreme[] b) {
int i = 0;
double sum = 0;
while (i < b.length) {
if (this.equals(b[i])) {
sum += 0;
i += 1;
} else {
sum = sum + this.calcForceExertedByY(b[i]);
i += 1;
}
} return sum;
}
public void update(double dt, double fX, double fY) {
double ax = fX / this.mass;
double ay = fY / this.mass;
double vx = this.xxVel + dt * ax;
double vy = this.yyVel + dt * ay;
double px = this.xxPos + dt * vx;
double py = this.yyPos + dt * vy;
this.xxPos = px;
this.yyPos = py;
this.xxVel = vx;
this.yyVel = vy;
}
public void draw() {
StdDraw.picture(this.xxPos, this.yyPos, "images/" + this.imgFileName);
}
public void lonelyplanet_update1(){
this.xxPos = this.xxPos + 45000000;
this.yyPos = this.yyPos + 100000000;
this.draw();
}
}
Here is the Main method class:
import java.util.Scanner;
public class NBodyExtreme{
public static double readRadius(String name) {
In in = new In(name);
int NumPlanets = in.readInt();
double Size = in.readDouble();
return Size;
}
public static BodyExtreme[] readBodies(String name) {
In in = new In(name);
int NumPlanets = in.readInt();
double Size = in.readDouble();
BodyExtreme[] bodies = new BodyExtreme[NumPlanets];
int i = 0;
while (i < NumPlanets) {
bodies[i] = new BodyExtreme(in.readDouble(), in.readDouble(), in.readDouble(), in.readDouble(), in.readDouble(), in.readString());
i += 1;
}
return bodies;
}
public static void main(String[] args) {
double T = Double.parseDouble(args[0]); /** Stoping Time */
double dt = Double.parseDouble(args[1]); /** Time Step */
String filename = args[2];
BodyExtreme[] bodies = readBodies(filename); /** Array of Bodies */
double radius = readRadius(filename); /** Canvas Radius */
In in = new In(filename);
int NumPlanets = in.readInt(); /** Number of Planets */
String imageToDraw = "images/starfield.jpg"; /** Background */
StdDraw.enableDoubleBuffering();
StdDraw.setScale(-2*radius, 2*radius);
StdDraw.clear();
StdDraw.picture(0, 0, imageToDraw); /** Draw Initial Background */
StdDraw.show();
int k = 0;
while (k < NumPlanets-1) { /** Draw Planets */
bodies[k].draw();
k += 1;
}
StdDraw.enableDoubleBuffering();
double time = 0.0;
while (time < T) {
double[] xForces = new double[NumPlanets-1];
double[] yForces = new double[NumPlanets-1];
int i = 0;
while (i < NumPlanets-1) {
xForces[i] = bodies[i].calcNetForceExertedByX(bodies);
yForces[i] = bodies[i].calcNetForceExertedByY(bodies);
i += 1;
}
i = 0;
while (i < NumPlanets-1) {
bodies[i].update(dt, xForces[i], yForces[i]);
i += 1;
}
bodies[NumPlanets-1].lonelyplanet_update1();
bodies[NumPlanets-1].draw();
StdDraw.show();
StdDraw.picture(0, 0, imageToDraw);
int j = 0;
while (j < NumPlanets) {
bodies[j].draw();
j += 1;
}
StdDraw.show();
StdDraw.pause(10);
}
time += dt;
}
}
This is what happens when the trace of route is blocked with the background image:
This is what happens when the trace is not blocked, but I only want the corn's trace not to be blokcekd.
you have a flaw in your animation logic:
to animate your screen you have to
update the model (each element, eg. backgroud or bodY),
then draw each model by using StdDraw.picture(..) and
finally make that content visible (by using StdDraw.show();)
for each time step in your animation (while (time < T){..}) you have to do all three steps.
public static void main(String[] args) {
...
StdDraw.enableDoubleBuffering(); //it's enough to call this only once!
double time = 0.0;
while (time < T) {
//do all the update stuff first, as shown in your code above
//then draw ONCE the BackGround:
StdDraw.picture(0, 0, imageToDraw);
//then draw all the planets (yes, i missed one)
while (j < NumPlanets) {
bodies[j].draw();
j += 1;
}
//finally make all the previous drawing visible
StdDraw.show();
//wait a bit for the next animation step
StdDraw.pause(10);
time += dt;
}
}
I'm trying to figure out how to count the number of stars that were printed last time the print() method was used.
I'm confused on how to take the value of starsInLastPrint variable into the starsInLastPrint() method. My understanding is that this isn't possible. I assume there are plenty of things wrong with my current code that isn't helping. Below is my current state as I am stuck.
import java.util.Random;
public class NightSky {
private double density;
private int width;
private int height;
private int starsInLastPrint;
public NightSky(double density) {
width = 20;
height = 10;
this.density = density;
}
public NightSky(int width, int height) {
density = 0.1;
this.width = width;
this.height = height;
}
public NightSky(double density, int width, int height) {
this.density = density;
this.width = width;
this.height = height;
}
public void printLine() {
Random starPlacement = new Random();
String[] stars = new String[(this.width)];
for (int i = 0; i < this.width; i++) {
double random = starPlacement.nextDouble();
if (random <= this.density) {
stars[i] = "*";
this.starsInLastPrint++;
} else {
stars[i] = " ";
}
}
int j = 0;
while (j < stars.length) {
System.out.print(stars[j]);
j++;
}
System.out.println("");
}
public void print() {
NightSky nightSky = new NightSky(this.density, this.width, this.height);
this.starsInLastPrint = 0;
int i = 0;
while (i < this.height) {
nightSky.printLine();
i++;
}
}
public int starsInLastPrint() {
return this.starsInLastPrint;
}
}
You are on the right track. Though, you don't need to instantiate another NightSky object inside the print method. You can just do the following,
public void print() {
this.starsInLastPrint = 0;
int i=0;
while (i < this.height) {
printLine();
i++;
}
}
So, everytime you call print, it will update the stars count for that print method call. Here is the whole code,
import java.util.Random;
public class NightSky {
private double density;
private int width;
private int height;
private int starsInLastPrint;
public static void main(String[] args){
NightSky sky = new NightSky(5,5);
sky.print();
System.out.println(sky.starsInLastPrint());
sky.print();
System.out.println(sky.starsInLastPrint());
}
public NightSky(double density) {
width = 20;
height = 10;
this.density = density;
}
public NightSky(int width, int height) {
density = 0.1;
this.width = width;
this.height = height;
}
public NightSky(double density, int width, int height) {
this.density = density;
this.width = width;
this.height = height;
}
public void printLine() {
Random starPlacement = new Random();
String[] stars = new String[(this.width)];
for (int i = 0; i < this.width; i++) {
double random = starPlacement.nextDouble();
if (random <= this.density) {
stars[i] = "*";
this.starsInLastPrint++;
} else {
stars[i] = " ";
}
}
int j = 0;
while (j < stars.length) {
System.out.print(stars[j]);
j++;
}
System.out.println("");
}
public void print() {
this.starsInLastPrint = 0;
int i=0;
while (i < this.height) {
printLine();
i++;
}
}
public int starsInLastPrint() {
return this.starsInLastPrint;
}
}
Sample run of the above code:
* *
*
*
4
0
I am writing a program that sorts 2 arrays of the same values by using two different algorithms. It loops through the arrays once each time a button is clicked. My problem is that it only sorts the first time you click the button. Every other time nothing happens. I put a count incrementer to see if the code was running and it was. I'm stumped. Any help will be appreciated.
I fixed the selection sort.
public class TwoSortsPanel extends JPanel
{
private int width = 10, gap = 3, x = 200, y = 50;
private int[] ranArr1 = new int[15], ranArr2 = new int[15];
private Color blue = Color.blue, red = Color.red, pink = Color.pink, gray = Color.gray;
public static int count = 0, indexSel = 0;
{
for(int i = 0; i < ranArr1.length-1; i++)
{
ranArr1[i] = (int) (Math.random() * 15);
ranArr2[i] = ranArr1[i];
}
}
public TwoSortsPanel()
{
printArray(ranArr1);
setBackground(pink);
setPreferredSize (new Dimension (400,300));
JButton sort = new JButton ("Sort");
sort.addActionListener(new ButtonListener());
add (sort);
}
public static void printArray(int[] c)
{
System.out.println(Arrays.toString(c));
}
public void paintComponent (Graphics page)
{
super.paintComponent(page);
page.drawString("" + count, 10, 12);
if (insertion() == false || selection() == false)
{
int yPlus = 50;
for(int i = 0; i < ranArr1.length; i++)
{
page.setColor(blue);
page.fillRect(x, yPlus, ranArr1[i]*10, width);
yPlus += width + gap;
}
yPlus = 50;
for(int i = 0; i < ranArr2.length; i++)
{
page.setColor(red);
page.fillRect(x, yPlus, -ranArr2[i]*10, width);
yPlus += width + gap;
}
}
else
{
int yPlus = 50;
for(int i = 0; i < ranArr1.length; i++)
{
page.setColor(gray);
page.fillRect(x, yPlus, ranArr1[i]*10, width);
yPlus += width + gap;
}
yPlus = 50;
for(int i = 0; i < ranArr2.length; i++)
{
page.setColor(gray);
page.fillRect(x, yPlus, -ranArr2[i]*10, width);
yPlus += width + gap;
}
}
}
private class ButtonListener implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
displaySelection(ranArr1);
displayInsertion(ranArr2);
count++;
printArray(ranArr1);
repaint();
}
}
public static void displaySelection(int[] a)
{
int temp;
int min = indexSel;
for (int scan = indexSel+1; scan < a.length ; scan++)
if (a[scan] < a[min])
min = scan;
temp = a[min];
a[min] = a[indexSel];
a[indexSel] = temp;
count++;
indexSel++;
}
public static void displayInsertion(int[] b)
{
int index = 1;
int key = b[index];
int position = index;
while (position > 0 && b[position-1] > key )
{
b[position] = b[position-1];
position--;
}
b[position] = key;
}
public boolean selection()
{
for (int i = 0; i < ranArr1.length-1; i++)
{
if(ranArr1[i] > ranArr1[i+1])
{
return false;
}
}
return true;
}
public boolean insertion()
{
for (int i = 0; i < ranArr2.length-1; i++)
{
if(ranArr2[i] > ranArr2[i+1])
{
return false;
}
}
return true;
}
}
Sorry. I didn't want the post to look too busy and I guess it lost meaning.