Skip to content

Instantly share code, notes, and snippets.

@mrowdy
Last active August 29, 2015 13:56
Show Gist options
  • Save mrowdy/9235990 to your computer and use it in GitHub Desktop.
Save mrowdy/9235990 to your computer and use it in GitHub Desktop.
library minefield;
import 'dart:html';
import 'dart:math';
part 'field.dart';
class Minefield {
int _width; // Width of canvas
int _height; // Height of canvas
int _rows; // Numer of rows
int _cols; // Number of columns
int _mines; // Number of mines
List<Field> _fields;
Element _container;
CanvasElement _canvas;
CanvasRenderingContext2D _ctx;
double _fieldWidth;
double _fieldHeight;
Map<String, String> _colors = {
'background': '#395D33',
'closed': '#4DBD33',
'open': '#734523',
'numbers': '#ffffff',
'flag': '#ffffff',
'mine': '#ff0000'
};
Minefield(this._container, [this._width = 320, this._height = 320, this._rows = 10, this._cols = 10, this._mines = 10]){
_setupCanvas();
setup();
}
void _setupCanvas(){
_canvas = new CanvasElement(width: _width, height: _height );
_ctx = _canvas.getContext('2d');
_fieldWidth = _width / _cols;
_fieldHeight = _height / _rows;
_container.style.width = '${_width}px';
_container.append(_canvas);
}
void setup(){
_setupFields();
_handleInputs();
_render();
}
void _setupFields(){
_fields = new List<Field>();
int fieldCount = _rows * _cols;
List<int> mineIndices = _generateMines(_mines);
for(int i = 0; i < fieldCount; i++){
Point position = new Point(
i % _cols,
(i / _cols).floor()
);
Field field = new Field(i, position);
if(mineIndices.contains(i)){
field.isMine = true;
}
_fields.add(field);
}
_fields.forEach((Field field){
List<Field> surrounding = _getSurroundingFields(field);
if(!field.isMine){
surrounding.forEach((Field field2){
if(field2.isMine){
field.surroundingMines++;
}
});
}
});
}
List<Field> _getSurroundingFields(Field start){
List<Field> surrounding = new List<Field>();
_fields.forEach((Field field){
if(field.position.x >= start.position.x - 1
&& field.position.x <= start.position.x + 1
&& field.position.y >= start.position.y - 1
&& field.position.y <= start.position.y + 1
&& field != start
){
surrounding.add(field);
}
});
return surrounding;
}
void _handleInputs(){
_canvas.onMouseUp.listen((MouseEvent event){
int index = _positionToIndex(event.offset.x, event.offset.y);
if(event.button == 2){
_flagField(index);
} else {
_openField(index);
}
});
_canvas.onContextMenu.listen((MouseEvent event){
event.preventDefault();
});
}
int _positionToIndex(x, y){
x = (x / _width * _cols).floor();
y = (y / _height * _rows).floor();
return x + (y * _cols);
}
void _openField(int index){
Field field = _fields[index];
if(field.isOpen || field.isFlagged ){
return;
}
field.isOpen = true;
if(field.isMine == true){
_fields.forEach((field){ field.isOpen = true; });
_gameOver();
} else if(field.surroundingMines == 0){
_getSurroundingFields(field).forEach((Field surr){
if(!surr.isMine && !surr.isOpen && surr != field){
_openField(surr.index);
}
});
}
_update();
}
void _gameOver(){
}
void _flagField(int index){
Field field = _fields[index];
if(field.isOpen){
return;
}
field.isFlagged = !field.isFlagged;
_update();
}
List<int> _generateMines(int count){
if(count >= _rows * _cols){
count = _rows * _cols;
}
List<int> mineIndices = new List<int>();
Random rand = new Random();
while(mineIndices.length < count){
int index = rand.nextInt(_rows * _cols);
if(!mineIndices.contains(index)){
mineIndices.add(index);
}
}
return mineIndices;
}
void _update(){
_render();
}
void _render(){
_ctx..fillStyle = _colors['background']
..fillRect(0, 0, _width, _height);
_fields.forEach((field) => _renderField(field));
}
void _renderField(Field field){
String color = _colors['closed'];
if(field.isOpen) {
color = _colors['open'];
}
_ctx..fillStyle = color
..fillRect(
field.position.x * _fieldWidth + 1,
field.position.y * _fieldHeight + 1,
_fieldWidth - 2,
_fieldHeight - 2
);
if(field.isOpen && !field.isMine && field.surroundingMines > 0){
_ctx..font = "14pt Calibri"
..fillStyle = _colors['numbers']
..fillText(field.surroundingMines.toString(), field.position.x * _fieldWidth + 5, field.position.y * _fieldHeight + _fieldHeight - 5);
}
if(field.isFlagged && !field.isOpen){
_drawCircle(field, _colors['flag']);
} else if(field.isMine && field.isOpen){
_drawCircle(field, _colors['mine']);
}
}
void _drawCircle(Field field, String color){
_ctx..fillStyle = color
..beginPath()
..arc(field.position.x * _fieldWidth + _fieldWidth / 2, field.position.y * _fieldHeight + _fieldHeight / 2, 10, 0, 2 * PI, false)
..fill()
..closePath();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment