Giter VIP home page Giter VIP logo

minesweeper-j-compose's Introduction

Minesweeper w/ Jetpack Compose

This is a Minesweeper-like puzzle game, built using Jetpack Compose, for Android.

The objective of this game is to clear a rectangular board containing hidden "mines" or bombs without detonating any of them, with help from clues about the number of neighboring mines in each cell.

โฌ‡๏ธ Try out the app, download the apk from the link below:

Minesweeper-JC

Demo

MJC-Demo-1.0.0.mov

Features :

  • Zoomable and pannable minefield
  • Safe first click - The first cell is never a mine as the minefield is generated around the first click
  • Automatically save and resume game progress
  • Multiple difficulty levels to choose from
  • Settings screen to update and persist user preferences
  • Quick toggle for click / flag mode
  • Haptic & Aural feedback
  • Day / Night theme
  • Randomly generated levels

Controls :

  • Tap a cell to reveal it
  • Long press an unrevealed cell to flag / un-flag it
  • Tap an already revealed cell to expose potentially solved cells
  • Change default tap / long-press behaviour from the quick toggle

Package Structure :

com.jayasuryat.minesweeperjc
โ”œโ”€โ”€ ๐Ÿ“‚ app/                          # App module
โ”‚   โ”œโ”€โ”€ data/                         # Data source mappings
โ”‚   โ”œโ”€โ”€ di/                           # DI wiring
โ”‚   โ”œโ”€โ”€ presentation/                 # Navigation & Screens
โ”‚   โ”œโ”€โ”€ theme/                        # Theming
โ”‚   โ””โ”€โ”€ MinesweeperApp.kt
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ buildScripts/                 # Build scripts and pre-commit hooks
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ buildSrc/                     # Dependency versions LUT
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ minesweeper-engine/           # Module for driving all the logics of the game
โ”‚   โ”œโ”€โ”€ controller/                   # Game actions, events, game controller and action handlers
โ”‚   โ”‚   โ””โ”€โ”€ model/                    # Models for actions and events
โ”‚   โ”œโ”€โ”€ gridgenerator/                # Generators for the minefield
โ”‚   โ””โ”€โ”€ model/                        # Models for cells and grid
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ minesweeper-engine-debug/     # Module for debug utils related to minesweeper-engine
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ minesweeper-ui/               # Module for all of the UI components of the mine grid
โ”‚   โ”œโ”€โ”€ action/                       # Action listeners for Minefield interaction actions
โ”‚   โ”œโ”€โ”€ cell/                         # All composables related to MineCells
โ”‚   โ”œโ”€โ”€ component/                    # Helper composables
โ”‚   โ”œโ”€โ”€ config/                       # UI configuration for mine grid
โ”‚   โ”œโ”€โ”€ grid/                         # All composables related to MineGrid
โ”‚   โ”œโ”€โ”€ model/                        # UI models for all the MineCells and layout information
โ”‚   โ””โ”€โ”€ theme/                        # Theming for Minefield UI components
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ data/                         # A Kotlin Multiplatform Mobile module for all of the data operations
โ”‚   โ”œโ”€โ”€ androidMain/                  # Android implementations
โ”‚   โ”‚   โ”œโ”€โ”€ di/                       # Wiring of Android specific implementations
โ”‚   โ”‚   โ””โ”€โ”€ sqldelight/               # Android Sqlite driver setup
โ”‚   โ”œโ”€โ”€ iosMain/                      # iOS implementations
โ”‚   โ”‚   โ”œโ”€โ”€ di/                       # Wiring of iOS specific implementations
โ”‚   โ”‚   โ””โ”€โ”€ sqldelight/               # Native Sqlite driver setup
โ”‚   โ”œโ”€โ”€ commonMain/                   # Common infrastructure
โ”‚   โ”‚   โ”œโ”€โ”€ sqldelight/               # Sqlite query definitions
โ”‚   โ”‚   โ””โ”€โ”€ kotlin/                   
โ”‚   โ”‚       โ”œโ”€โ”€ di/                   # DI wiring for all of the data layer
โ”‚   โ”‚       โ”œโ”€โ”€ model/                # Data models for the data layer
โ”‚   โ”‚       โ”œโ”€โ”€ source/               # Data sources
โ”‚   โ”‚       โ””โ”€โ”€ sqldelight/           # DB setup
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ ui-game/                      # Module for the actual MineField screen
โ”‚   โ”œโ”€โ”€ composable/                   # All UI components
โ”‚   โ”‚   โ”œโ”€โ”€ feedback/                 # Composables for handling feedback
โ”‚   โ”‚   โ”œโ”€โ”€ toggle/                   # Composables for in game quick-toggle
โ”‚   โ”‚   โ””โ”€โ”€ topbar/                   # Composables for game TopBar
โ”‚   โ”œโ”€โ”€ data/                         # Data layer skeletons for game state persistence
โ”‚   โ”œโ”€โ”€ feedback/                     # Helper classes for performing feedback operations
โ”‚   โ”œโ”€โ”€ logic/                        # Game logic coordinators
โ”‚   โ””โ”€โ”€ GameScreen.kt                 # Actual Game-Screen
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ ui-difficulty-selection/      # Module for difficulty selection screen
โ”‚
โ””โ”€โ”€ ๐Ÿ“‚ util/                         # Module for common utilities

Contributions

Contributions are welcome! See Contributing Guidelines.

Credits

All the SFX used in this project are sourced from freesound.org and are licensed under the Creative Commons 0 License.

License

 Copyright 2022 Jaya Surya Thotapalli

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

minesweeper-j-compose's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

minesweeper-j-compose's Issues

UI / UX Enhancements

The current UI / UX situation is pretty OKAYY, there are a lot of things that could be improved.

Things to do:

(in priority order?, maybe)

All contributions are welcome, any contribution / feedback would be โ™กly.

Contributions don't necessarily need to be code only, they could be font / UI / UX suggestions, references, or design files.

Change cell reveal animation

Change cell reveal animation to scale up/down animation.

The current implementation of child cell composables doesn't quite support this.
The inverse cropped circle present in all of the child cell composables would interfere with the scale in/out animation.

FlaggedCell, UnFlaggedCell, ValueCell

That mask probably is needed to be pulled a composable layer back, maybe keeping the mask in the RawCell composable would solve this interference.

The game shouldn't be marked as complete until all the non-mine cells are revealed

Continuing from #34

Some people like to live dangerously. They don't want to flag the cells even if they know they are mines. Instead, they keep everything in mind and carefully reveal the rest of the cells.

So, for them, it would be nice if the MinefieldController could check if all of the non-mine cells are revealed, and then, if true, call it a win.

Not only this should be a check, but this should be the check.

Meaning, even tho a player has flagged the required number of mines, the game shouldn't come to an end state (or success state) until all of the non-mine cells are revealed first.

This logic is required, as in some scenarios, the player could win the game by just guessing the mine cell position by randomly flagging mines (or by brute-forcing the combinations).

For example, when only three cells are left unrevealed, and there are only two mine cells required to be flagged. Now, the player could randomly flag any two cells as mines, and if he is right, the game automatically goes to the success state, and if he is wrong, nothing happens. So he could try out different combinations until the game automatically goes into the success state.

So, for the game to go into success state, all of the non-mine cells must be revealed first.

Haptic feedback

Add haptic feedback on clicking/flagging/unflagging a cell

Add a settings screen

Add a settings screen to customise following things

  • Enable / disable sound
  • Enable / disable vibration
  • Selecting default flag / reveal mode
  • Show / hide mode toggle

TODO

  • Come up with UI / UX
  • Create a new screen for settings
  • Hook in logics to Enable / disable sound and vibration
  • Hook in default mode selection logic
  • Hook in logic for showing / hiding toggle in game screen
  • Consider persisting all of the settings in preferences

Deprecate OnGridUpdated in favour of OnCellsUpdated

Deprecate OnGridUpdated in favour of OnCellsUpdated.

Both events essentially serve the same purpose, but using OnCellsUpdated would be more performant as only the updated Cell(s) would be propagated through this event unlike OnGridUpdated which assumes that all the Cell(s) of the Grid have been updated. Which may lead to some redundant computations and side effects like #12.

Consider revealing cells radially outwards

Currently, when the first cell is revealed (or whenever a bunch of cells gets revealed due to any action), the cell revelation order is like:

"Diagonally reveal up to the topmost (and the leftmost) cell (which is getting revealed), and then start revealing linearly one by one from left-to-right then top-to-bottom."

This works fine and looks good enough when the game is totally zoomed out, as it is easier to follow.

But, when the player is zoomed in a fair bit, and if he reveals a cell, which in turn reveals a bunch of other cells, and cells offscreen start getting revealed. Here comes the problem, based on the position of cells and state of the board, the adjacent cells right next to the revealed cell might not get revealed in the first sweep and may take some to get revealed.

This particular problem is partially being solved by providing aural and haptic feedback. With this, the player should (ideally) get to know that cell revelation is in progress. Again, this is not a perfect solution to this problem, but it does help a bit.

One more thing that could help curb this problem is changing the revelation order to radially outwards from the clicked cell.

TLDR : Reveal cells radially outwards from the clicked cell.

Setup DI

There is a decent amount of object creation, and mapping one thing to another happening, manually.
It would be nice if DI is introduced and all of the object creation and dependency provisioning is wired with it.

Audio feedback

Add audio feedback on clicking/flagging/unflagging a cell

"3" cell looks similar to an unrevealed cell

The "3" cell looks pretty similar to an unrevealed cell. Sometimes the player may assume it as an unrevealed cell and continue.

Need to update the colors of the value cells so that they are distinct from each other and from the unrevealed cells as well.

Loosing progress with screen roation.

Hi Jaya,
The game is enjoyable, and moving gradient over cells is pleasing. Good job.
But, the issue that I want to bring here is : If I play the game with autorotation turned on, every time I tilt the phone, the game is getting rotated, and I am losing progress. Please fix this.
You can either make the game unaffected by screen rotation or keep the progress even after rotating the screen.

ValueCellRevealer not revealing radially outwards

Continuing on #33

All cell revelations were supposed to be sorted radially outwards, issue #33 only solved the initial cell revelation part.
Need to reveal cells in the same fashion even when the cells are revealed due to clicking of a MineCell.ValuedCell.

This could be done by utilizing RadiallySorter in ValueCellRevealer and sorting output before returning.

Add a toggle for click/flag

Different players have different style of playing this game. Some prefer flagging cells as their primary action, some prefer just revealing all the cells, and most players prefer a combination of these both. And long-pressing every time to flag a cell may slow some players down a bit.

It would be good to have a toggle to switch between clicking and flagging to accommodate different styles of playing the game better.

(This is also an extension of #34)

Game successfully competes on flagging ALL the cells

CellFlagger currently only verifies if all the MineCell(s) are flagged or not. (see)

If all of them are flagged then propagates OnGameComplete event. Which is not correct as there could be some cells which are inappropriately flagged, i.e., non MineCell(s) being flagged as well.

With this condition, essentially all one has to do to win the game is, just flag every cell.

Need to incorporate logic to also ensure that the total flagged count matches the total mine count of the Grid along with the existing conditions, before declaring that the game is complete.

Initially clicked cell should not be a mine

Right now all the Grid(s) being generated are assuming a default starCell (see).
And because of this, there is a possibility that the initially clicked cell can be a mine and the game may get over after the first click.

Need to make startCell param of GridGenerator dynamic.

Should start off with an essentially an "empty" grid, and from there considering the first click the grid should be generated (as it is being done already).

Add support for resuming game

Resuming game

It would be nice if the user could resume the game from where they left off the last time.

The flow could be something like this :

  1. User chooses a difficulty level, starts the game.
  2. Leaves the game / closes the app.
  3. User reopens the game.
  4. User is directly navigated to the game screen with the same grid where he left off the last time.
  5. He can continue from there or navigate back to the difficulty selection screen.
  6. On continuing, the user should be presented with the same grid that they had played and left the last time.
  7. In the difficulty selection screen, on selecting a difficulty level and starting a game, if a previous unfinished game with the same difficulty level exists, the user should be prompted with a dialog about whether he wants to continue or to start over.
  8. Based on what the user chooses, an appropriate game board should be rendered in the game screen.

How?

Slow down the background gradient

The animating gradient background is a little bit distracting.
-as per user feedback.

And if not for that, making the gradient animation slower would give it a more "soothing" or "calming" vibe.

  • Work out an optimal duration such that:
    • It is not distracting,
    • it looks soothing/calming
    • And if possible, not so slow that it might not look as if it were not animating.
  • Update the gradient with that 'optimal duration'.

Weird ValueCellRevealer behaviour

Cells are getting revealed in a weird fashion, especially the edge cells at the bottom.

On clicking of already revealed ValuedCell.Cell at the edge of the Grid, unrelated cells are getting revealed.

Persist user preferences

There are a bunch of user preferences to be stored, see #53.

TODO

  • Choose a persistence library (preferably a KMM one, see here)
  • Create a new module for persisting data
  • Do the thing (implement persistence logic)

ValueCellRevealer propagating already revealed cells in OnCellsUpdated event

ValueCellRevealer propagating already revealed cells in OnCellsUpdated event.

(See) for RevealedCell

(See) for FlaggedCell

Altho this will not affect UI as MutableStatefulGrid is using structuralEqualityPolicy() to generate the MutableState, so, based on diffs there might not be any recompositions triggered for these particular cells.

But, any custom logic present at any of the StatefulGrid implementation in the updateCellsWith method's onEach block will get triggered unnecessarily.

So, anyways as these cells don't need to be part of the event, at these particular branches we can just return emptyList()

`GameFeedback` in `GameScreen` is getting re-triggered on navigating back

STR

  • Finish a game by either moving to GameOver or GameCompleted state.
  • Observe GameFeedback getting triggered (sound and vibration).
  • Navigate back from the GameScreen.
  • Observer GameFeedback getting triggered again.

This is most probably being caused due to not wrapping GameFeedback properly in a side-effect.

Add a prebuilt apk

Add a prebuilt release variant APK so that folks can try out the app without having the need to build the project.

When the game is zoomed in, cells are getting revealed off-screen

This issue continues on the problem discussed @ #33

When the player is zoomed in a fair bit, and if he reveals a cell, which in turn reveals a bunch of other cells, and cells offscreen start getting revealed.

This particular problem is partially being solved by providing aural and haptic feedback. With this, the player should (ideally) get to know thatย cell revelationย is in progress. Again, this is not a perfect solution to this problem, but it does help a bit.

The player might not be aware of what is happening in the background (offscreen to be precise).

Even tho this is not a huge deal-breaker, it would be nice if we had a better solution for this problem.

Any idea is welcomeโœŒ๏ธ, things which could be considered are:

  1. More emphatic haptic and aural feedback
  2. Visual cues (like a progress bar or something, non-intrusive of-course)

Or, any completely different idea ๐Ÿ’ก

Game not completing if all the remaining cells are mines

Some people like to live dangerously. They don't want to flag the cells even if they know they are mines. Instead, they keep everything in mind and carefully reveal the rest of the cells.

So, for them, it would be nice if the MinefieldController could check if all of the non-mine cells are revealed, and then, if true, call it a win.

(this is just an exaggeration, it's a good/must? to have feature :p)

Persist zoom/pan state across theme change

Add zoom/pan state persistence across theme changes.

On changing (system) theme, the game state is persisted but the zoom and pan are being reset to default.

Options to consider :

  • Instead of exposing zoom/pan as a modifier, expose them as concrete value(s) which could be persisted using:
    • rememberSaveable
    • Or hoisting the value to the nearest viewmodel
  • Different / better ideas are welcome

https://github.com/JayaSuryaT/minesweeper-j-compose/blob/05110a71b6fda0bece0f00f6c383c4c4bc140e43/minesweeper-ui/src/main/java/com/jayasuryat/minesweeperui/grid/Minefield.kt#L33

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.