Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Christopher League
FloodGame
Commits
aa8e31ce
Commit
aa8e31ce
authored
Jul 08, 2019
by
Christopher League
Browse files
More documentation, save/restore history
parent
8cd27942
Changes
3
Hide whitespace changes
Inline
Side-by-side
app/src/main/java/edu/liu/floodgame/GridActivity.java
View file @
aa8e31ce
...
...
@@ -11,9 +11,14 @@ import android.widget.ImageButton;
import
android.widget.LinearLayout
;
import
android.widget.TextView
;
import
java.util.Arrays
;
import
java.util.Random
;
import
java.util.Stack
;
/* This is the primary hub of the game. It contains a grid of cells, buttons to
* select colors, feedback on number of moves (and when game is over), and an
* undo button.
*/
public
class
GridActivity
extends
AppCompatActivity
implements
FloodGrid
{
TypedArray
colors
;
...
...
@@ -22,11 +27,13 @@ public class GridActivity extends AppCompatActivity implements FloodGrid {
final
String
COLOR_ARRAY_KEY
=
"COLOR_ARRAY"
;
final
String
NUM_MOVES_KEY
=
"NUM_MOVES"
;
final
String
HISTORY_KEY
=
"HISTORY"
;
private
GridLayout
gridLayout
;
private
LinearLayout
buttonBar
;
private
TextView
numMovesText
;
private
ImageButton
undoButton
;
private
int
numColors
;
private
int
numMoves
=
0
;
private
boolean
gameOver
=
false
;
...
...
@@ -41,17 +48,22 @@ public class GridActivity extends AppCompatActivity implements FloodGrid {
// Grab palette
Intent
intent
=
getIntent
();
colors
=
getResources
().
obtainTypedArray
(
intent
.
getIntExtra
(
MainActivity
.
PALETTE_KEY
,
R
.
array
.
accentPalette
));
numColors
=
intent
.
getIntExtra
(
MainActivity
.
NUM_COLORS_KEY
,
colors
.
length
());
colors
=
getResources
().
obtainTypedArray
(
intent
.
getIntExtra
(
MainActivity
.
PALETTE_KEY
,
R
.
array
.
accentPalette
));
numColors
=
intent
.
getIntExtra
(
MainActivity
.
NUM_COLORS_KEY
,
colors
.
length
());
// buttons are at odd offsets.
// We have to update the button bar to match the number of
// colors being used. Buttons are at odd offsets.
buttonBar
=
findViewById
(
R
.
id
.
buttonBar
);
int
buttonIdx
=
0
;
for
(
;
buttonIdx
<
numColors
;
buttonIdx
++)
{
ColorButton
button
=
(
ColorButton
)
buttonBar
.
getChildAt
(
2
*
buttonIdx
+
1
);
ColorButton
button
=
(
ColorButton
)
buttonBar
.
getChildAt
(
2
*
buttonIdx
+
1
);
button
.
setColor
(
buttonIdx
);
}
//
Remov
e any subsequent buttons and gaps
//
Hid
e any subsequent buttons and gaps
for
(
;
buttonIdx
<
MAX_COLORS
;
buttonIdx
++)
{
buttonBar
.
getChildAt
(
2
*
buttonIdx
).
setVisibility
(
View
.
GONE
);
buttonBar
.
getChildAt
(
2
*
buttonIdx
+
1
).
setVisibility
(
View
.
GONE
);
...
...
@@ -60,21 +72,65 @@ public class GridActivity extends AppCompatActivity implements FloodGrid {
// Set up grid
gridLayout
=
findViewById
(
R
.
id
.
grid
);
gridLayout
.
removeAllViews
();
final
int
BOARD_SIZE
=
intent
.
getIntExtra
(
MainActivity
.
BOARD_SIZE_KEY
,
5
);
final
int
BOARD_SIZE
=
intent
.
getIntExtra
(
MainActivity
.
BOARD_SIZE_KEY
,
5
);
gridLayout
.
setColumnCount
(
BOARD_SIZE
);
for
(
int
i
=
0
;
i
<
BOARD_SIZE
*
BOARD_SIZE
;
i
++)
{
gridLayout
.
addView
(
new
GridCellView
(
this
));
}
if
(
savedInstanceState
==
null
)
{
FloodGridOps
.
randomize
(
this
,
new
Random
(),
numColors
);
gameOver
=
false
;
setNumMoves
(
0
);
newGame
();
}
else
{
FloodGridOps
.
fromArray
(
this
,
savedInstanceState
.
getIntArray
(
COLOR_ARRAY_KEY
));
// TODO: restore history
gameOver
=
FloodGridOps
.
gameOver
(
this
);
setNumMoves
(
savedInstanceState
.
getInt
(
NUM_MOVES_KEY
));
numMoves
=
savedInstanceState
.
getInt
(
NUM_MOVES_KEY
);
/* Restoring history -- it's a flat array in the bundle, but
* we must parcel it back out into the stack.
*/
int
[]
flatHistory
=
savedInstanceState
.
getIntArray
(
HISTORY_KEY
);
history
.
clear
();
for
(
int
m
=
0
;
m
<
numMoves
;
m
++)
{
history
.
add
(
Arrays
.
copyOfRange
(
flatHistory
,
m
*
numCells
(),
(
m
+
1
)*
numCells
()));
}
}
updateUI
();
}
void
newGame
()
{
FloodGridOps
.
randomize
(
this
,
new
Random
(),
numColors
);
history
.
clear
();
gameOver
=
false
;
numMoves
=
0
;
}
/* The elements of the screen to be updated on each move include
* enabling/disabling the undo button, reporting the number of moves (and
* possibly "game over"), and updating the grid with neighborhood
* information.
*/
void
updateUI
()
{
/* undoButton is an ImageButton, which doesn't visually distinguish
* enabled from disabled, so we need to also mess with some visual
* indicator, like alpha.
*/
if
(
history
.
size
()
>
0
)
{
undoButton
.
setEnabled
(
true
);
undoButton
.
setAlpha
(
1
f
);
}
else
{
undoButton
.
setEnabled
(
false
);
undoButton
.
setAlpha
(
0.5f
);
}
if
(
gameOver
)
{
numMovesText
.
setText
(
String
.
format
(
"Solved in %d moves"
,
numMoves
));
}
else
{
numMovesText
.
setText
(
Integer
.
toString
(
numMoves
));
}
undoButton
.
setEnabled
(
history
.
size
()
>
0
);
recordNeighborsThroughout
();
}
...
...
@@ -83,6 +139,17 @@ public class GridActivity extends AppCompatActivity implements FloodGrid {
super
.
onSaveInstanceState
(
outState
);
outState
.
putIntArray
(
COLOR_ARRAY_KEY
,
FloodGridOps
.
toArray
(
this
));
outState
.
putInt
(
NUM_MOVES_KEY
,
numMoves
);
/* We also need to save the history, which is a stack of integer arrays.
* Simplest thing(?) is to concatenate them all?
*/
int
[]
flatHistory
=
new
int
[
history
.
size
()
*
numCells
()];
int
i
=
0
;
for
(
int
[]
h
:
history
)
{
for
(
int
c
:
h
)
{
flatHistory
[
i
++]
=
c
;
}
}
outState
.
putIntArray
(
HISTORY_KEY
,
flatHistory
);
}
@Override
...
...
@@ -121,7 +188,7 @@ public class GridActivity extends AppCompatActivity implements FloodGrid {
public
void
recordNeighborsAt
(
int
row
,
int
column
)
{
int
index
=
row
*
edgeSize
()
+
column
;
GridCellView
cell
=
(
GridCellView
)
gridLayout
.
getChildAt
(
index
);
int
color
=
cell
.
c
olor
;
int
color
=
cell
.
getC
olor
()
;
boolean
west
=
color
==
safeGetColorAt
(
row
,
column
-
1
);
boolean
northwest
=
color
==
safeGetColorAt
(
row
-
1
,
column
-
1
);
...
...
@@ -146,7 +213,7 @@ public class GridActivity extends AppCompatActivity implements FloodGrid {
@Override
public
int
getColorAt
(
int
index
)
{
GridCellView
cell
=
(
GridCellView
)
gridLayout
.
getChildAt
(
index
);
return
cell
.
c
olor
;
return
cell
.
getC
olor
()
;
}
@Override
...
...
@@ -164,32 +231,17 @@ public class GridActivity extends AppCompatActivity implements FloodGrid {
return
colors
.
getColor
(
c
,
0
);
}
public
void
setNumMoves
(
int
m
)
{
numMoves
=
m
;
if
(
gameOver
)
{
numMovesText
.
setText
(
String
.
format
(
"Solved in %d moves"
,
numMoves
));
}
else
{
numMovesText
.
setText
(
Integer
.
toString
(
numMoves
));
}
}
public
void
onClickUndo
(
View
v
)
{
FloodGridOps
.
fromArray
(
this
,
history
.
pop
());
gameOver
=
false
;
setNumMoves
(
numMoves
-
1
);
undoButton
.
setEnabled
(
history
.
size
()
>
0
);
recordNeighborsThroughout
();
numMoves
--;
updateUI
();
}
public
void
onClickColor
(
int
color
)
{
if
(
gameOver
)
{
// Clicking when game already over restarts
FloodGridOps
.
randomize
(
this
,
new
Random
(),
numColors
);
gameOver
=
false
;
setNumMoves
(
0
);
history
.
clear
();
undoButton
.
setEnabled
(
false
);
newGame
();
}
else
{
history
.
push
(
FloodGridOps
.
toArray
(
this
));
...
...
@@ -197,10 +249,8 @@ public class GridActivity extends AppCompatActivity implements FloodGrid {
if
(
FloodGridOps
.
gameOver
(
this
))
{
gameOver
=
true
;
}
setNumMoves
(
numMoves
+
1
)
;
numMoves
++
;
}
undoButton
.
setEnabled
(
history
.
size
()
>
0
);
recordNeighborsThroughout
();
updateUI
();
}
}
app/src/main/java/edu/liu/floodgame/GridCellView.java
View file @
aa8e31ce
...
...
@@ -6,25 +6,58 @@ import android.graphics.Paint;
import
android.support.v7.widget.GridLayout
;
import
android.view.View
;
/* A cell on the game grid. It stores an integer color index, and sets the
* actual color by querying the palette from the GridActivity. It also handles
* drawing the shapes and borders to make contiguous colors regions appear
* connected.
*/
public
class
GridCellView
extends
View
{
int
color
;
private
int
color
;
private
Paint
fill
=
new
Paint
();
private
Paint
stroke
=
new
Paint
();
private
Corner
[]
neighbors
=
new
Corner
[]
{
Corner
.
NO_NO
,
Corner
.
NO_NO
,
Corner
.
NO_NO
,
Corner
.
NO_NO
};
/* Using width/height=0 and weight=1 makes sure everything is equally
* spaced. (In the XML, the entire GridLayout is constrained to a square
* aspect ratio.)
*/
GridCellView
(
GridActivity
activity
)
{
super
(
activity
);
GridLayout
.
LayoutParams
lp
=
new
GridLayout
.
LayoutParams
();
lp
.
rowSpec
=
lp
.
columnSpec
=
GridLayout
.
spec
(
GridLayout
.
UNDEFINED
,
1
f
);
lp
.
rowSpec
=
lp
.
columnSpec
=
GridLayout
.
spec
(
GridLayout
.
UNDEFINED
,
1
f
);
lp
.
width
=
lp
.
height
=
0
;
setLayoutParams
(
lp
);
fill
.
setStyle
(
Paint
.
Style
.
FILL
);
stroke
.
setStyle
(
Paint
.
Style
.
STROKE
);
stroke
.
setColor
(
Color
.
BLACK
);
stroke
.
setStrokeWidth
(
3
f
);
stroke
.
setAntiAlias
(
true
);
stroke
.
setAlpha
(
127
);
}
/* Could just use setBackgroundColor here.
*/
void
setColor
(
int
color
)
{
this
.
color
=
color
;
//GridActivity activity = (GridActivity) getContext();
//setBackgroundColor(activity.colorFromPalette(color));
invalidate
();
}
int
getColor
()
{
return
color
;
}
/* An enumeration of each quadrant of the cell. Helpful for tracking the
* local neighborhood.
*/
enum
Quadrant
{
NW
(
0
),
NE
(
1
),
SE
(
2
),
SW
(
3
);
final
int
value
;
...
...
@@ -33,11 +66,28 @@ public class GridCellView extends View {
}
}
/* Enumeration of the possible neighborhood conditions. For NorthWest
* quadrant, this refers to the cells to the left, above, and diagonally
* above-left. Then we use mirroring to reason about other quadrants. We
* only care about the diagonal when the two directly-adjacent neighbors are
* the same color.
*/
enum
Corner
{
NO_NO
,
NO_YES
,
YES_NO
,
YES_NO_YES
,
YES_YES_YES
NO_NO
,
// No neighbors of same color; draw as a corner piece
NO_YES
,
// Neighbor above, so draw vertically to edge
YES_NO
,
// Neighbor to left, so draw horizontally
YES_NO_YES
,
// Both above and left, but cut-out the diagonal
YES_YES_YES
// All neighbors, so fill entire cell.
}
static
Corner
corner
(
boolean
adjacent1
,
boolean
diagonal
,
boolean
adjacent2
)
{
/* Short-hand for specifying one of the five corner types using three
* boolean flags.
*/
static
Corner
corner
(
boolean
adjacent1
,
boolean
diagonal
,
boolean
adjacent2
)
{
if
(
adjacent1
)
{
if
(!
adjacent2
)
return
Corner
.
YES_NO
;
else
if
(
diagonal
)
return
Corner
.
YES_YES_YES
;
...
...
@@ -47,10 +97,8 @@ public class GridCellView extends View {
else
return
Corner
.
NO_NO
;
}
private
Paint
fill
=
new
Paint
();
private
Paint
stroke
=
new
Paint
();
private
Corner
[]
neighbors
=
new
Corner
[]
{
Corner
.
NO_NO
,
Corner
.
NO_NO
,
Corner
.
NO_NO
,
Corner
.
NO_NO
};
/* We rely on the parent (GridActivity) to inform us about our local neighborhood.
*/
void
setNeighbors
(
Corner
nw
,
Corner
ne
,
Corner
se
,
Corner
sw
)
{
boolean
changed
=
false
;
if
(
neighbors
[
0
]
!=
nw
)
{
...
...
@@ -72,39 +120,35 @@ public class GridCellView extends View {
if
(
changed
)
invalidate
();
}
/* Draw each quadrant to match local neighborhood. Relies on helper versions of drawLine and
* drawRect to do appropriate mirroring of axes based on the quadrant.
*/
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
super
.
onDraw
(
canvas
);
GridActivity
activity
=
(
GridActivity
)
getContext
();
fill
.
setStyle
(
Paint
.
Style
.
FILL
);
fill
.
setColor
(
activity
.
colorFromPalette
(
color
));
stroke
.
setStyle
(
Paint
.
Style
.
STROKE
);
stroke
.
setColor
(
Color
.
BLACK
);
stroke
.
setStrokeWidth
(
3
f
);
stroke
.
setAntiAlias
(
true
);
stroke
.
setAlpha
(
127
);
final
float
z
=
getWidth
();
final
float
c
=
z
*
0.5f
;
final
float
m
=
z
*
0.07f
;
for
(
Quadrant
q
:
Quadrant
.
values
())
{
System
.
out
.
print
(
" "
+
q
.
value
+
"="
+
q
+
":"
+
neighbors
[
q
.
value
]);
switch
(
neighbors
[
q
.
value
])
{
case
NO_NO:
drawRect
(
canvas
,
q
,
m
,
m
,
c
,
c
,
fill
);
// corner
(nn)
drawRect
(
canvas
,
q
,
m
,
m
,
c
,
c
,
fill
);
// corner
drawLine
(
canvas
,
q
,
m
,
m
,
m
,
c
,
stroke
);
drawLine
(
canvas
,
q
,
m
,
m
,
c
,
m
,
stroke
);
break
;
case
NO_YES:
drawRect
(
canvas
,
q
,
m
,
0
,
c
,
c
,
fill
);
// vert
(ny)
drawRect
(
canvas
,
q
,
m
,
0
,
c
,
c
,
fill
);
// vert
drawLine
(
canvas
,
q
,
m
,
0
,
m
,
c
,
stroke
);
break
;
case
YES_NO:
drawRect
(
canvas
,
q
,
0
,
m
,
c
,
c
,
fill
);
// horiz
(yn)
drawRect
(
canvas
,
q
,
0
,
m
,
c
,
c
,
fill
);
// horiz
drawLine
(
canvas
,
q
,
0
,
m
,
c
,
m
,
stroke
);
break
;
case
YES_YES_YES:
drawRect
(
canvas
,
q
,
0
,
0
,
c
,
c
,
fill
);
// full
(yyy)
drawRect
(
canvas
,
q
,
0
,
0
,
c
,
c
,
fill
);
// full
break
;
case
YES_NO_YES:
drawRect
(
canvas
,
q
,
m
,
0
,
c
,
c
,
fill
);
// vert
...
...
@@ -114,10 +158,17 @@ public class GridCellView extends View {
break
;
}
}
System
.
out
.
println
();
}
void
drawRect
(
Canvas
canvas
,
Quadrant
quadrant
,
float
left
,
float
top
,
float
right
,
float
bottom
,
Paint
paint
)
{
/* Quadrant-sensitive version of drawRect.
*/
void
drawRect
(
Canvas
canvas
,
Quadrant
quadrant
,
float
left
,
float
top
,
float
right
,
float
bottom
,
Paint
paint
)
{
// Maybe flip horizontal coordinates
float
tmp
;
switch
(
quadrant
)
{
...
...
@@ -137,7 +188,15 @@ public class GridCellView extends View {
canvas
.
drawRect
(
left
,
top
,
right
,
bottom
,
paint
);
}
void
drawLine
(
Canvas
canvas
,
Quadrant
quadrant
,
float
x1
,
float
y1
,
float
x2
,
float
y2
,
Paint
paint
)
{
/* Quadrant-sensitive version of drawLine.
*/
void
drawLine
(
Canvas
canvas
,
Quadrant
quadrant
,
float
x1
,
float
y1
,
float
x2
,
float
y2
,
Paint
paint
)
{
switch
(
quadrant
)
{
case
NE:
case
SE:
x1
=
getWidth
()
-
x1
;
...
...
app/src/main/java/edu/liu/floodgame/PaletteSwatchesView.java
View file @
aa8e31ce
...
...
@@ -8,13 +8,20 @@ import android.graphics.Paint;
import
android.util.AttributeSet
;
import
android.view.View
;
/* On the options screen (MainActivity), we let players select the color
* palette. This displays swatches from a given palette, and updates to match
* the number of colors selected.
*/
public
class
PaletteSwatchesView
extends
View
{
int
paletteArrayId
=
R
.
array
.
accentPalette
;
int
numColors
=
6
;
int
paletteArrayId
;
int
numColors
;
Paint
paint
=
new
Paint
();
public
PaletteSwatchesView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
paint
.
setStyle
(
Paint
.
Style
.
FILL
);
}
public
void
setPaletteId
(
int
paletteArrayId
)
{
...
...
@@ -30,8 +37,6 @@ public class PaletteSwatchesView extends View {
protected
void
onDraw
(
Canvas
canvas
)
{
super
.
onDraw
(
canvas
);
TypedArray
ta
=
getResources
().
obtainTypedArray
(
paletteArrayId
);
Paint
paint
=
new
Paint
();
paint
.
setStyle
(
Paint
.
Style
.
FILL
);
int
h
=
canvas
.
getHeight
();
int
w
=
canvas
.
getWidth
()
/
numColors
;
for
(
int
i
=
0
;
i
<
numColors
;
i
++)
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment