Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add board section and word models #11

Merged
merged 2 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/packages/game_domain/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
targets:
$default:
builders:
json_serializable:
options:
explicit_to_json: true
58 changes: 58 additions & 0 deletions api/packages/game_domain/lib/src/models/board_section.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:equatable/equatable.dart';
import 'package:game_domain/game_domain.dart';
import 'package:json_annotation/json_annotation.dart';

part 'board_section.g.dart';

/// {@template board_section}
/// A model that represents a board section with all the words that
/// it contains.
/// {@endtemplate}
@JsonSerializable(ignoreUnannotated: true)
class BoardSection extends Equatable {
/// {@macro board_section}
const BoardSection({
required this.id,
required this.position,
required this.width,
required this.height,
required this.words,
});

/// {@macro board_section}
factory BoardSection.fromJson(Map<String, dynamic> json) =>
_$BoardSectionFromJson(json);

/// Unique identifier of board section.
@JsonKey()
final String id;

/// Position of the board section in the board. The origin is the top left.
@JsonKey()
@PointConverter()
final Point<int> position;

/// Width of the board section.
@JsonKey()
final int width;

/// Height of the board section.
@JsonKey()
final int height;

/// The words that are contained in this board section.
@JsonKey()
final List<Word> words;

/// Returns a json representation from this instance.
Map<String, dynamic> toJson() => _$BoardSectionToJson(this);

@override
List<Object?> get props => [
id,
position,
width,
height,
words,
];
jsgalarraga marked this conversation as resolved.
Show resolved Hide resolved
}
27 changes: 27 additions & 0 deletions api/packages/game_domain/lib/src/models/board_section.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions api/packages/game_domain/lib/src/models/models.dart
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export 'dart:math' show Point;

export 'board_section.dart';
export 'leaderboard_player.dart';
export 'point_converter.dart';
export 'word.dart';
26 changes: 26 additions & 0 deletions api/packages/game_domain/lib/src/models/point_converter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:game_domain/game_domain.dart';
import 'package:json_annotation/json_annotation.dart';

/// {@template point_converter}
/// A converter that converts a [Point] to a [Map] and vice versa.
/// {@endtemplate}
class PointConverter extends JsonConverter<Point<int>, Map<String, dynamic>> {
/// {@macro point_converter}
const PointConverter();

@override
Point<int> fromJson(Map<String, dynamic> json) {
return Point<int>(
json['x'] as int,
json['y'] as int,
);
}

@override
Map<String, dynamic> toJson(Point<int> object) {
return {
'x': object.x,
'y': object.y,
};
}
}
71 changes: 71 additions & 0 deletions api/packages/game_domain/lib/src/models/word.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import 'package:equatable/equatable.dart';
import 'package:game_domain/game_domain.dart';
import 'package:json_annotation/json_annotation.dart';

part 'word.g.dart';

/// {@template word}
/// A model that represents a word in the crossword.
/// {@endtemplate}
@JsonSerializable(ignoreUnannotated: true)
class Word extends Equatable {
/// {@macro word}
const Word({
required this.id,
required this.position,
required this.answer,
required this.clue,
required this.hints,
required this.visible,
required this.solvedTimestamp,
});

/// {@macro word}
factory Word.fromJson(Map<String, dynamic> json) => _$WordFromJson(json);

/// Unique identifier of the word.
@JsonKey()
final String id;

/// Position of the board section in the board. The origin is the top left.
@JsonKey()
@PointConverter()
final Point<int> position;

/// The word answer to display in the crossword when solved.
@JsonKey()
final String answer;

/// The clue to show users when guessing for the first time.
@JsonKey()
final String clue;

/// The hints to show users when asked for more hints.
@JsonKey()
final List<String> hints;

/// Whether the word should be visible or not in the board. Independent of
/// the word being solved or not.
/// Every solved word is visible, but not every visible word is solved.
@JsonKey()
final bool visible;

/// The timestamp when the word was solved. In milliseconds since epoch.
/// If the word is not solved, this value is null.
@JsonKey()
final int? solvedTimestamp;

/// Returns a json representation from this instance.
Map<String, dynamic> toJson() => _$WordToJson(this);

@override
List<Object?> get props => [
id,
position,
answer,
clue,
hints,
visible,
solvedTimestamp,
];
}
28 changes: 28 additions & 0 deletions api/packages/game_domain/lib/src/models/word.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions api/packages/game_domain/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ publish_to: none
environment:
sdk: ">=3.0.0 <4.0.0"

dependencies:
equatable: ^2.0.5
json_annotation: ^4.8.1

dev_dependencies:
build_runner: ^2.4.8
mocktail: ^1.0.0
json_serializable: ^6.7.1
mocktail: ^1.0.3
test: ^1.19.2
very_good_analysis: ^5.1.0

dependencies:
equatable: ^2.0.5
json_annotation: ^4.8.1
very_good_analysis: ^5.1.0
113 changes: 113 additions & 0 deletions api/packages/game_domain/test/src/models/board_section_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// ignore_for_file: prefer_const_constructors
// ignore_for_file: prefer_const_literals_to_create_immutables

import 'package:game_domain/game_domain.dart';
import 'package:test/test.dart';

void main() {
group('BoardSection', () {
test('creates correct json object from BoardSection object', () {
final boardSection = BoardSection(
id: 'id',
position: Point(1, 2),
width: 3,
height: 4,
words: [
Word(
id: 'id',
position: Point(1, 2),
answer: 'answer',
clue: 'clue',
hints: ['hints'],
visible: false,
solvedTimestamp: 1234,
),
],
);
final json = boardSection.toJson();

expect(
json,
equals({
'id': 'id',
'position': {'x': 1, 'y': 2},
'width': 3,
'height': 4,
'words': [
{
'id': 'id',
'position': {'x': 1, 'y': 2},
'answer': 'answer',
'clue': 'clue',
'hints': ['hints'],
'visible': false,
'solvedTimestamp': 1234,
},
],
}),
);
});

test('creates correct BoardSection object from json object', () {
final json = {
'id': 'id',
'position': {'x': 1, 'y': 2},
'width': 3,
'height': 4,
'words': [
{
'id': 'id',
'position': {'x': 1, 'y': 2},
'answer': 'answer',
'clue': 'clue',
'hints': ['hints'],
'visible': false,
'solvedTimestamp': 1234,
},
],
};
final boardSection = BoardSection.fromJson(json);
expect(
boardSection,
equals(
BoardSection(
id: 'id',
position: Point(1, 2),
width: 3,
height: 4,
words: [
Word(
id: 'id',
position: Point(1, 2),
answer: 'answer',
clue: 'clue',
hints: ['hints'],
visible: false,
solvedTimestamp: 1234,
),
],
),
),
);
});

test('supports equality', () {
final firstBoardSection = BoardSection(
id: 'id',
position: Point(1, 2),
width: 3,
height: 4,
words: [],
);
final secondBoardSection = BoardSection(
id: 'id',
position: Point(1, 2),
width: 3,
height: 4,
words: [],
);

expect(firstBoardSection, equals(secondBoardSection));
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ignore_for_file: prefer_const_constructors

import 'package:game_domain/game_domain.dart';
import 'package:test/test.dart';

void main() {
group('PointConverter', () {
test('creates correct json object from Point object', () {
final point = Point(1, 2);
final json = PointConverter().toJson(point);
expect(json, equals({'x': 1, 'y': 2}));
});

test('creates correct Point object from json object', () {
final json = {'x': 1, 'y': 2};
final point = PointConverter().fromJson(json);
expect(point, equals(Point(1, 2)));
});
});
}
Loading
Loading