Initial commit
This commit is contained in:
commit
83eb5ac1c5
44
.gitignore
vendored
Normal file
44
.gitignore
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
|
|
||||||
|
# Android Studio will place build artifacts here
|
||||||
|
/android/app/debug
|
||||||
|
/android/app/profile
|
||||||
|
/android/app/release
|
||||||
47
lib/common/cell-position.dart
Normal file
47
lib/common/cell-position.dart
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
class CellPosition {
|
||||||
|
final int column;
|
||||||
|
final int row;
|
||||||
|
const CellPosition(this.column, this.row);
|
||||||
|
|
||||||
|
double distance(CellPosition to) {
|
||||||
|
return sqrt(pow(to.column - column, 2) + pow(to.row - row, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
CellPosition decreaseBy(int diff) {
|
||||||
|
int newCol =
|
||||||
|
column < 0 ? column + diff * diff.sign : column - diff * diff.sign;
|
||||||
|
int newRow = row < 0 ? row + diff * diff.sign : row - diff * diff.sign;
|
||||||
|
|
||||||
|
return CellPosition(newCol, newRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => "${column}:${row}".hashCode;
|
||||||
|
|
||||||
|
bool operator ==(Object pos) {
|
||||||
|
return pos is CellPosition && this.column == pos.column && this.row == pos.row;
|
||||||
|
}
|
||||||
|
|
||||||
|
CellPosition operator -(CellPosition pos) {
|
||||||
|
return CellPosition(column - pos.column, row - pos.row);
|
||||||
|
}
|
||||||
|
|
||||||
|
CellPosition operator +(CellPosition pos) {
|
||||||
|
return CellPosition(column + pos.column, row + pos.row);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return "Position(${column}x${row})";
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
"type": "BoardCell",
|
||||||
|
"column": column,
|
||||||
|
"row": row,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
22
lib/common/geometry.dart
Normal file
22
lib/common/geometry.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:boardgames_core/commons.dart';
|
||||||
|
|
||||||
|
// Hexagon | Square | Circle | ...
|
||||||
|
abstract class Geometry {
|
||||||
|
const Geometry();
|
||||||
|
bool isOnBoard(CellPosition position);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Rectangular extends Geometry {
|
||||||
|
final int columns;
|
||||||
|
final int rows;
|
||||||
|
|
||||||
|
const Rectangular(this.columns, this.rows);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isOnBoard(CellPosition position) {
|
||||||
|
return position.column >= 0 &&
|
||||||
|
position.row >= 0 &&
|
||||||
|
position.column < columns &&
|
||||||
|
position.row < rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
lib/common/mixins.dart
Normal file
30
lib/common/mixins.dart
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import 'package:boardgames_core/core.dart';
|
||||||
|
|
||||||
|
mixin Ownable {
|
||||||
|
List<Player> _owners = [];
|
||||||
|
|
||||||
|
int addOwner(Player player) {
|
||||||
|
_owners.add(player);
|
||||||
|
return _owners.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeOwner(Player player) {
|
||||||
|
_owners.remove(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isOwner(Player player) {
|
||||||
|
return _owners.contains(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasOwners() {
|
||||||
|
return _owners.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Player> getOwners() {
|
||||||
|
return _owners.sublist(0).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin Renderable {
|
||||||
|
void render();
|
||||||
|
}
|
||||||
1
lib/common/uuid.dart
Normal file
1
lib/common/uuid.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
3
lib/commons.dart
Normal file
3
lib/commons.dart
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export 'common/geometry.dart';
|
||||||
|
export 'common/mixins.dart';
|
||||||
|
export 'common/cell-position.dart';
|
||||||
5
lib/core.dart
Normal file
5
lib/core.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export './src/board.dart';
|
||||||
|
export './src/element.dart';
|
||||||
|
export './src/player.dart';
|
||||||
|
export './src/game.dart';
|
||||||
|
export './src/settings.dart';
|
||||||
1
lib/games.dart
Normal file
1
lib/games.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
export './games/checkers.dart';
|
||||||
247
lib/games/checkers.dart
Normal file
247
lib/games/checkers.dart
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
import 'package:boardgames_core/commons.dart';
|
||||||
|
import 'package:boardgames_core/core.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
|
// 4 points to check if checker can move
|
||||||
|
final List<CellPosition> _jumps = [
|
||||||
|
CellPosition(-2, -2),
|
||||||
|
CellPosition(2, -2),
|
||||||
|
CellPosition(-2, 2),
|
||||||
|
CellPosition(2, 2),
|
||||||
|
];
|
||||||
|
final List<CellPosition> _dirs = [
|
||||||
|
CellPosition(-1, -1),
|
||||||
|
CellPosition(1, -1),
|
||||||
|
CellPosition(-1, 1),
|
||||||
|
CellPosition(1, 1),
|
||||||
|
];
|
||||||
|
|
||||||
|
class Checker extends Element<Rectangular> {
|
||||||
|
static final Logger log = Logger("Checker");
|
||||||
|
@override
|
||||||
|
bool interactable = true;
|
||||||
|
@override
|
||||||
|
bool canMove = true;
|
||||||
|
List<Checker> killed = [];
|
||||||
|
|
||||||
|
Checker(super.position);
|
||||||
|
|
||||||
|
/// Moving the pawn from->to position
|
||||||
|
/// Returns null if move not possible
|
||||||
|
/// or List of killed pawns (can be empty if moving to empty cell)
|
||||||
|
List<Checker>? _venturePosition(CellPosition from, CellPosition to) {
|
||||||
|
if (board == null || !board!.geometry.isOnBoard(to)) {
|
||||||
|
// Cannot move outside the board
|
||||||
|
log.finer("Cannot move outside the board $to");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final elems = board!.getElementsAtPosition(to);
|
||||||
|
|
||||||
|
// Cannot move where occupied
|
||||||
|
if (elems.isNotEmpty) {
|
||||||
|
log.finer("Cannot move where occupied");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final vector = from - to;
|
||||||
|
|
||||||
|
// TODO: Calculate settings.canMoveBackwards depending on player? Mirror board
|
||||||
|
// Need to decide how to render board
|
||||||
|
// final settings = board!.settings as CheckerSettings;
|
||||||
|
final distance = from.distance(to).floor();
|
||||||
|
|
||||||
|
// Can move to closest adjustent cell if empty (did check elems.isNotEmpty above)
|
||||||
|
if (distance == 1) {
|
||||||
|
// Can only move diagonal
|
||||||
|
return vector.column != 0 && vector.row != 0 ? [] : null;
|
||||||
|
}
|
||||||
|
log.finest("Starting tracing back from $to back to $from");
|
||||||
|
// If distance is greater than one cell then we need to trace back to selected pawn
|
||||||
|
final owner = this.getOwners().firstOrNull;
|
||||||
|
List<CellPosition> queue = [to];
|
||||||
|
Set<CellPosition> visited = new Set();
|
||||||
|
// TODO: Revisit: Assuming only one path possible in Checkers game
|
||||||
|
visited.add(to);
|
||||||
|
Map<CellPosition, CellPosition> path = new Map();
|
||||||
|
Map<CellPosition, Checker> pawns = new Map();
|
||||||
|
List<Checker> _traceBack(CellPosition? origin) {
|
||||||
|
List<Checker> res = [];
|
||||||
|
CellPosition? it = origin;
|
||||||
|
|
||||||
|
log.finest("======");
|
||||||
|
log.finest(path);
|
||||||
|
log.finest(pawns);
|
||||||
|
log.finest("======");
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (pawns.containsKey(it)) {
|
||||||
|
res.add(pawns[it]!);
|
||||||
|
}
|
||||||
|
it = path[it];
|
||||||
|
} while (it != null);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (queue.length > 0) {
|
||||||
|
final origin = queue.removeLast();
|
||||||
|
|
||||||
|
// Exit criteria - we traced back our pawn
|
||||||
|
if (origin == from) {
|
||||||
|
log.finest("Trace back succeeded!");
|
||||||
|
return _traceBack(origin);
|
||||||
|
}
|
||||||
|
for (final vector in _jumps) {
|
||||||
|
CellPosition checkPos = origin + vector;
|
||||||
|
|
||||||
|
if (!board!.geometry.isOnBoard(checkPos)) {
|
||||||
|
// Cannot move outside the board
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visited.contains(checkPos)) {
|
||||||
|
log.finest("Already visited position $checkPos");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
visited.add(checkPos);
|
||||||
|
|
||||||
|
var elems = board!.getElementsAtPosition(checkPos);
|
||||||
|
if (elems.isNotEmpty && checkPos != from) {
|
||||||
|
// Cannot move if position occupied
|
||||||
|
// allow original position to pass to fall into exit condition above
|
||||||
|
log.finest("Checker is blocking $checkPos, skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Check if we attack someone
|
||||||
|
final jumpPos = checkPos - vector.decreaseBy(1);
|
||||||
|
elems = board!.getElementsAtPosition(jumpPos);
|
||||||
|
final checker = elems.firstOrNull as Checker?;
|
||||||
|
|
||||||
|
if (checker == null) {
|
||||||
|
// Skip if no checkers on the path
|
||||||
|
log.finest("cannot jump over empty cell at $jumpPos, skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Check if it is not ours checker
|
||||||
|
if (owner == null || checker.isOwner(owner)) {
|
||||||
|
// Cannot attack yourself or jump over empty cell
|
||||||
|
log.finest(
|
||||||
|
"Player#${owner == null ? "null" : owner.id} at $jumpPos owns this pawn, skipping");
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
log.finest("You ate checker: $checker ($jumpPos)");
|
||||||
|
}
|
||||||
|
log.finest("Can jump to $checkPos (over $jumpPos), will check it too");
|
||||||
|
path[checkPos] = origin;
|
||||||
|
pawns[checkPos] = checker;
|
||||||
|
queue.add(checkPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool canMoveTo(CellPosition position) {
|
||||||
|
killed.clear();
|
||||||
|
bool globalCanMove = super.canMoveTo(position);
|
||||||
|
|
||||||
|
(board!.game as Checkers).bank.clear();
|
||||||
|
if (!globalCanMove) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final res = this._venturePosition(this.position, position);
|
||||||
|
|
||||||
|
if (res == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
killed = res;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void moveTo(CellPosition newPosition) {
|
||||||
|
super.moveTo(newPosition);
|
||||||
|
board!.game.currentPlayer!.jail.addAll(killed);
|
||||||
|
for (var elem in killed) {
|
||||||
|
board!.elements.remove(elem);
|
||||||
|
}
|
||||||
|
killed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
canSharePosition(Element element) {
|
||||||
|
// no shared position in checkers
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<CellPosition> getAvailableMoves() {
|
||||||
|
// TODO: implement getAvailableMoves
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckerSettings extends GameSettings {
|
||||||
|
bool canMoveBackwards = false;
|
||||||
|
bool canDenyChainAttacks = false;
|
||||||
|
bool canSwapToQueen = true;
|
||||||
|
bool queenCanMoveWholeBoard = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8x8 board, 24 checkers (12 per player)
|
||||||
|
class Checkers extends Game<Rectangular, Checker, CheckerSettings> {
|
||||||
|
@override
|
||||||
|
late Board<Rectangular, Checker, CheckerSettings> board;
|
||||||
|
@override
|
||||||
|
late int maximumPlayers;
|
||||||
|
@override
|
||||||
|
late int requiredPlayers;
|
||||||
|
@override
|
||||||
|
late CheckerSettings settings = CheckerSettings();
|
||||||
|
final List<Checker> bank = [];
|
||||||
|
|
||||||
|
Checkers() : super() {
|
||||||
|
board = Board(Rectangular(8, 8));
|
||||||
|
maximumPlayers = 2;
|
||||||
|
requiredPlayers = 2;
|
||||||
|
// Adding players
|
||||||
|
players.add(new Player());
|
||||||
|
players.add(new Player());
|
||||||
|
|
||||||
|
board.setGame(this);
|
||||||
|
|
||||||
|
// Filling board
|
||||||
|
int col = -1;
|
||||||
|
int row = 0;
|
||||||
|
for (int i = 0; i < 24; i++) {
|
||||||
|
if (i > 0 && i % 4 == 0) {
|
||||||
|
row += 1;
|
||||||
|
col = row % 2 == 0 ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
col += 2;
|
||||||
|
}
|
||||||
|
final position = CellPosition(col, row);
|
||||||
|
final checker = new Checker(position);
|
||||||
|
|
||||||
|
board.addElementOnBoard(checker);
|
||||||
|
if (i < 12) {
|
||||||
|
checker.addOwner(players[0]);
|
||||||
|
} else {
|
||||||
|
checker.addOwner(players[1]);
|
||||||
|
}
|
||||||
|
if (i == 11) {
|
||||||
|
row += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Player> getWinners() {
|
||||||
|
return [currentPlayer!];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool hasGameFinished() {
|
||||||
|
return board.elements.map((e) => e.getOwners().first).toSet().length == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
lib/src/board.dart
Normal file
37
lib/src/board.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:boardgames_core/commons.dart';
|
||||||
|
import 'package:boardgames_core/core.dart';
|
||||||
|
|
||||||
|
class Board<G extends Geometry, E extends Element, S extends GameSettings> {
|
||||||
|
final G geometry;
|
||||||
|
final List<E> elements = [];
|
||||||
|
late Game game;
|
||||||
|
|
||||||
|
Board(this.geometry);
|
||||||
|
|
||||||
|
setGame(Game g) {
|
||||||
|
game = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
addElementOnBoard(E element) {
|
||||||
|
var board = element.board;
|
||||||
|
element.board = this;
|
||||||
|
if (!element.canMoveTo(element.position)) {
|
||||||
|
element.board = board;
|
||||||
|
throw new Exception(
|
||||||
|
"Cannot add element to ${element.position} on the board. There are elements that cannot share this position with it.");
|
||||||
|
}
|
||||||
|
elements.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<E> getElementsAtPosition(CellPosition position) {
|
||||||
|
// TODO: optimize with hash table
|
||||||
|
return this
|
||||||
|
.elements
|
||||||
|
.where((element) => element.position == position)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
S get settings {
|
||||||
|
return game.settings as S;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
lib/src/element.dart
Normal file
44
lib/src/element.dart
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import 'package:boardgames_core/core.dart';
|
||||||
|
import 'package:boardgames_core/commons.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
abstract class Element<G extends Geometry> with Ownable {
|
||||||
|
static final uuid = Uuid();
|
||||||
|
final CellPosition initialPosition;
|
||||||
|
final String id;
|
||||||
|
CellPosition position;
|
||||||
|
Board<G, Element, GameSettings>? board;
|
||||||
|
abstract bool interactable;
|
||||||
|
abstract bool canMove;
|
||||||
|
|
||||||
|
Element(this.position)
|
||||||
|
: initialPosition = position,
|
||||||
|
id = uuid.v4();
|
||||||
|
|
||||||
|
/// Implements rules of the Game
|
||||||
|
canSharePosition(Element element);
|
||||||
|
|
||||||
|
bool canMoveTo(CellPosition position) {
|
||||||
|
if (board == null) {
|
||||||
|
throw new Exception("Element is not on the board");
|
||||||
|
}
|
||||||
|
if (!interactable || !canMove) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final elements = board!.getElementsAtPosition(position);
|
||||||
|
return !elements.any((element) => !element.canSharePosition(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveTo(CellPosition newPosition) {
|
||||||
|
if (canMoveTo(newPosition)) {
|
||||||
|
position = newPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CellPosition> getAvailableMoves();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return "${this.runtimeType.toString()}#${position}";
|
||||||
|
}
|
||||||
|
}
|
||||||
38
lib/src/game.dart
Normal file
38
lib/src/game.dart
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import 'package:boardgames_core/core.dart';
|
||||||
|
import 'package:boardgames_core/commons.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
abstract class Game<G extends Geometry, E extends Element,
|
||||||
|
S extends GameSettings> {
|
||||||
|
static final uuid = Uuid();
|
||||||
|
int turn = 0;
|
||||||
|
abstract Board<G, E, S> board;
|
||||||
|
abstract int requiredPlayers;
|
||||||
|
abstract int maximumPlayers;
|
||||||
|
abstract S settings;
|
||||||
|
final String id;
|
||||||
|
List<Player> players = [];
|
||||||
|
Player? currentPlayer;
|
||||||
|
|
||||||
|
Game(): id = uuid.v4();
|
||||||
|
|
||||||
|
Future<void> beginTurn() async {
|
||||||
|
if (hasGameFinished()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await beforeTurn();
|
||||||
|
currentPlayer = players[turn % players.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> endTurn() async {
|
||||||
|
await afterTurn();
|
||||||
|
if (!hasGameFinished()) {
|
||||||
|
turn += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> beforeTurn() async {}
|
||||||
|
Future<void> afterTurn() async {}
|
||||||
|
bool hasGameFinished();
|
||||||
|
List<Player> getWinners();
|
||||||
|
}
|
||||||
11
lib/src/player.dart
Normal file
11
lib/src/player.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
import 'package:boardgames_core/core.dart';
|
||||||
|
|
||||||
|
class Player {
|
||||||
|
static int _counter = 0;
|
||||||
|
final int id;
|
||||||
|
final List<Element> bank = [];
|
||||||
|
final List<Element> jail = [];
|
||||||
|
|
||||||
|
Player() : id = ++_counter;
|
||||||
|
}
|
||||||
3
lib/src/settings.dart
Normal file
3
lib/src/settings.dart
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
abstract class GameSettings {
|
||||||
|
// Some common settings?
|
||||||
|
}
|
||||||
53
pubspec.lock
Normal file
53
pubspec.lock
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Generated by pub
|
||||||
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
|
packages:
|
||||||
|
collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: collection
|
||||||
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.18.0"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
|
logging:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
sprintf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sprintf
|
||||||
|
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.2"
|
||||||
|
uuid:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: uuid
|
||||||
|
sha256: e03928880bdbcbf496fb415573f5ab7b1ea99b9b04f669c01104d085893c3134
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
sdks:
|
||||||
|
dart: ">=3.1.0 <4.0.0"
|
||||||
10
pubspec.yaml
Normal file
10
pubspec.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
name: boardgames_core
|
||||||
|
version: 0.1.0
|
||||||
|
description: Board games core
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
uuid: ^4.0.0
|
||||||
|
logging: ^1.2.0
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=3.1.0 <4.0.0'
|
||||||
Loading…
x
Reference in New Issue
Block a user