Skip to content

Commit

Permalink
Merge 503c32f into 1182306
Browse files Browse the repository at this point in the history
  • Loading branch information
albertms10 committed Dec 8, 2022
2 parents 1182306 + 503c32f commit 746e18a
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 43 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"cSpell.words": ["powerable", "Powerable"]
}
4 changes: 2 additions & 2 deletions bin/main.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'dart:math';

import 'package:christmas_lights_kata/grid.dart';
import 'package:christmas_lights_kata/grid/powerable_grid.dart';

void main(List<String> arguments) {
final grid = Grid(1000)
final grid = PowerableGrid(1000)
..turnOn(const Point(887, 9), const Point(959, 629))
..turnOn(const Point(454, 398), const Point(844, 448))
..turnOff(const Point(539, 243), const Point(559, 965))
Expand Down
8 changes: 8 additions & 0 deletions lib/grid/dimmable_grid.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:christmas_lights_kata/grid/grid.dart';
import 'package:christmas_lights_kata/led/dimmable_led.dart';

/// A grid of dimmable LEDs.
class DimmableGrid extends Grid<DimmableLed> {
/// Creates a new [Grid] of [DimmableLed]s.
DimmableGrid(int size) : super(size, DimmableLed.new);
}
21 changes: 8 additions & 13 deletions lib/grid.dart → lib/grid/grid.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import 'dart:math';

import 'package:christmas_lights_kata/led.dart';
import 'package:christmas_lights_kata/led/led.dart';

/// A squared grid of LEDs.
class Grid {
class Grid<T extends Led<dynamic>> {
/// Constructs a new [Grid] from [size].
Grid(this.size)
: assert(size > 0, 'Size must be positive'),
Grid(this.size, T Function() constructor)
: assert(size > 0, '"size" must be positive'),
leds = [
for (var x = 0; x < size; x++) [for (var y = 0; y < size; y++) Led()],
for (var x = 0; x < size; x++)
[for (var y = 0; y < size; y++) constructor()],
];

/// The size of this [Grid].
final int size;

/// The two-dimensional matrix of [Led]s.
late final List<List<Led>> leds;
final List<List<T>> leds;

/// Turns on all [Led]s from [start] to [end] positions.
void turnOn(Point<int> start, Point<int> end) =>
Expand All @@ -32,7 +33,7 @@ class Grid {
void _actOnLedsFrom(
Point<int> start,
Point<int> end,
void Function(Led led) action,
void Function(Led<dynamic> led) action,
) {
for (var x = start.x; x <= end.x; x++) {
for (var y = start.y; y <= end.y; y++) {
Expand All @@ -41,12 +42,6 @@ class Grid {
}
}

/// Returns the number of powered [Led]s in the [Grid].
int get poweredLedsCount => leds.fold<int>(
0,
(count, row) => count + row.where((led) => led.isPowered).length,
);

@override
String toString() => leds.map((row) => row.join()).join('\n');
}
14 changes: 14 additions & 0 deletions lib/grid/powerable_grid.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:christmas_lights_kata/grid/grid.dart';
import 'package:christmas_lights_kata/led/powerable_led.dart';

/// A grid of powerable LEDs.
class PowerableGrid extends Grid<PowerableLed> {
/// Creates a new [Grid] of [PowerableLed]s.
PowerableGrid(int size) : super(size, PowerableLed.new);

/// Returns the number of powered [PowerableLed]s in the [Grid].
int get poweredLedsCount => leds.fold<int>(
0,
(count, row) => count + row.where((led) => led.isPowered).length,
);
}
40 changes: 40 additions & 0 deletions lib/led/dimmable_led.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:christmas_lights_kata/led/led.dart';
import 'package:christmas_lights_kata/utils/map_int_v_extension.dart';

const _offLight = '⚫️';
const _brightnessLights = {
0: _offLight,
1: '🔅',
10: '🔆',
};

/// A dimmable LED.
class DimmableLed extends Led<int> {
/// Constructs a new [DimmableLed].
DimmableLed() : _brightness = 0;

int _brightness;

/// Whether this [DimmableLed] is turned on or off.
int get brightness => _brightness;

/// Increases the brightness of this [DimmableLed] by 1.
@override
int turnOn() => _brightness++;

/// Reduces the brightness of this [DimmableLed] by 1.
@override
int turnOff() {
if (_brightness > 0) _brightness--;

return _brightness;
}

/// Increases the brightness of this [DimmableLed] by 2.
@override
int toggle() => _brightness = _brightness + 2;

@override
String toString() =>
_brightnessLights.valueFromThreshold(_brightness) ?? _offLight;
}
11 changes: 11 additions & 0 deletions lib/led/led.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// An LED.
abstract class Led<T> {
/// Turns on this [Led].
T turnOn();

/// Turns off this [Led].
T turnOff();

/// Toggles this [Led].
T toggle();
}
21 changes: 13 additions & 8 deletions lib/led.dart → lib/led/powerable_led.dart
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import 'package:christmas_lights_kata/led/led.dart';
import 'package:christmas_lights_kata/utils/random_string_extension.dart';

const _poweredLights = '🔴🟡🟢🔵';
const _offLight = '⚫️';

/// An LED.
class Led {
/// Constructs a new [Led].
Led({bool isPowered = false})
/// A powerable LED.
class PowerableLed extends Led<bool> {
/// Constructs a new [PowerableLed].
PowerableLed({bool isPowered = false})
: _isPowered = isPowered,
displayLight = _poweredLights.randomChar;

bool _isPowered;

/// Whether this [Led] is turned on or off.
/// Whether this [PowerableLed] is turned on or off.
bool get isPowered => _isPowered;

/// String for displaying the powered light.
late final String displayLight;

/// Turns on this [Led].
/// Turns on this [PowerableLed].
@override
bool turnOn() => _isPowered = true;

/// Turns off this [Led].
/// Turns off this [PowerableLed].
@override
bool turnOff() => _isPowered = false;

/// Toggles the powered state of this [Led] and returns the new state.
/// Toggles the powered state of this [PowerableLed] and returns the new
/// state.
@override
bool toggle() => _isPowered = !_isPowered;

@override
Expand Down
15 changes: 15 additions & 0 deletions lib/utils/map_int_v_extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// Map int to V extension.
extension MapIntVExtension<V> on Map<int, V> {
/// Returns the corresponding value [V], if any, when the [threshold] is
/// lower than or equal to one of this [Map] keys.
V? valueFromThreshold(int threshold) {
final value = this[threshold];
if (value != null) return value;

for (final entry in entries) {
if (threshold <= entry.key) return entry.value;
}

return null;
}
}
29 changes: 16 additions & 13 deletions test/grid_test.dart → test/powerable_grid_test.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import 'dart:math';

import 'package:christmas_lights_kata/grid.dart';
import 'package:christmas_lights_kata/grid/powerable_grid.dart';
import 'package:test/test.dart';

void main() {
group('Grid', () {
group('PowerableGrid', () {
group('(new)', () {
test('creates a squared grid of 10x10', () {
const gridSize = 10;
final grid = Grid(gridSize);
final grid = PowerableGrid(gridSize);
expect(grid.size, gridSize);
expect(grid.leds.length, gridSize);
expect(grid.leds.first.length, gridSize);
Expand All @@ -18,38 +18,40 @@ void main() {

group('.turnOn()', () {
test('turns on all LEDs', () {
final grid = Grid(10)..turnOn(const Point(0, 0), const Point(9, 9));
final grid = PowerableGrid(10)
..turnOn(const Point(0, 0), const Point(9, 9));
expect(grid.areAllPowered, isTrue);
print(grid);
});

test('turns on only selected LEDs', () {
const start = Point(1, 2);
const end = Point(5, 6);
final grid = Grid(10)..turnOn(start, end);
final grid = PowerableGrid(10)..turnOn(start, end);
expect(grid.isPoweredFrom(start, end), isTrue);
print(grid);
});

test('turns on only selected LEDs', () {
const start = Point(7, 2);
const end = Point(8, 3);
final grid = Grid(10)..turnOn(start, end);
final grid = PowerableGrid(10)..turnOn(start, end);
expect(grid.isPoweredFrom(start, end), isTrue);
print(grid);
});

test('turns on only selected LEDs', () {
const point = Point(1, 1);
final grid = Grid(3)..turnOn(point, point);
final grid = PowerableGrid(3)..turnOn(point, point);
expect(grid.isPoweredFrom(point), isTrue);
print(grid);
});
});

group('.turnOff()', () {
test('turns off all LEDs', () {
final grid = Grid(10)..turnOn(const Point(0, 0), const Point(9, 9));
final grid = PowerableGrid(10)
..turnOn(const Point(0, 0), const Point(9, 9));
print(grid);
grid.turnOff(const Point(0, 0), const Point(9, 9));
expect(grid.areNonePowered, isTrue);
Expand All @@ -59,7 +61,8 @@ void main() {

group('.toggle()', () {
test('toggles all LEDs', () {
final grid = Grid(10)..toggle(const Point(0, 0), const Point(9, 9));
final grid = PowerableGrid(10)
..toggle(const Point(0, 0), const Point(9, 9));
expect(grid.areAllPowered, isTrue);
print(grid);
grid.toggle(const Point(0, 0), const Point(9, 9));
Expand All @@ -70,7 +73,7 @@ void main() {

group('.poweredLedsCount', () {
test('returns the number of powered LEDs in the grid', () {
final grid = Grid(1000)
final grid = PowerableGrid(1000)
..turnOn(const Point(887, 9), const Point(959, 629))
..turnOn(const Point(454, 398), const Point(844, 448))
..turnOff(const Point(539, 243), const Point(559, 965))
Expand All @@ -87,12 +90,12 @@ void main() {
});
}

extension GridPoweredExtension on Grid {
/// Whether all LEDs in this [Grid] are powered.
extension GridPoweredExtension on PowerableGrid {
/// Whether all LEDs in this [PowerableGrid] are powered.
bool get areAllPowered =>
leds.every((row) => row.every((led) => led.isPowered));

/// Whether all LEDs in this [Grid] are not powered.
/// Whether all LEDs in this [PowerableGrid] are not powered.
bool get areNonePowered =>
leds.every((row) => row.every((led) => !led.isPowered));

Expand Down
14 changes: 7 additions & 7 deletions test/led_test.dart → test/powerable_led_test.dart
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
import 'package:christmas_lights_kata/led.dart';
import 'package:christmas_lights_kata/led/powerable_led.dart';
import 'package:test/test.dart';

void main() {
group('Led', () {
group('PowerableLed', () {
group('(new)', () {
test('is not powered by default', () {
final led = Led();
final led = PowerableLed();
expect(led.isPowered, isFalse);
print(led);
});

test('uses the powered value on construction', () {
final led = Led(isPowered: true);
final led = PowerableLed(isPowered: true);
expect(led.isPowered, isTrue);
print(led);
});
});

group('.turnOn()', () {
test('turns on this LED', () {
final led = Led()..turnOn();
final led = PowerableLed()..turnOn();
expect(led.isPowered, isTrue);
print(led);
});
});

group('.turnOff()', () {
test('turns off this LED', () {
final led = Led(isPowered: true)..turnOff();
final led = PowerableLed(isPowered: true)..turnOff();
expect(led.isPowered, isFalse);
print(led);
});
});

group('.toggle()', () {
test('toggles the powered state of this LED', () {
final led = Led()..toggle();
final led = PowerableLed()..toggle();
expect(led.isPowered, isTrue);
print(led);
led.toggle();
Expand Down

0 comments on commit 746e18a

Please sign in to comment.