Skip to content

Commit

Permalink
Merge pull request #41 from SEbbaDK/generic-quests
Browse files Browse the repository at this point in the history
Generic quests + second quest
  • Loading branch information
Simon97 committed May 23, 2021
2 parents 34931e4 + ccedd5e commit 1cddfae
Show file tree
Hide file tree
Showing 14 changed files with 496 additions and 336 deletions.
23 changes: 0 additions & 23 deletions client/lib/quests/bench_quest/backrest_bench_quest.dart

This file was deleted.

37 changes: 37 additions & 0 deletions client/lib/quests/bench_quests/backrest_bench_quest.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:latlong/latlong.dart';
import 'package:osm_api/osm_api.dart' as osm;

import 'package:client/quests/simple_tag_quest.dart';
import 'package:client/quests/quest_finder.dart';
import 'package:client/quests/quest.dart';

class BackrestBenchQuestFinder implements QuestFinder {
@override
Quest construct(osm.Element e) => BackrestBenchQuest(e);

@override
bool applicable(osm.Element e) =>
e.isNode &&
e.tags['amenity'] == 'bench' &&
!e.tags.containsKey('backrest');
}

class BackrestBenchQuest extends SimpleTagQuest {
BackrestBenchQuest(osm.Element element) : super(element);

@override
String tag() => 'backrest';

@override
question() => 'Does the bench have a backrest?';

@override
String changesetComment() => 'Added backrest tag for a bench';

@override
Widget icon() => Icon(Icons.airline_seat_recline_normal_sharp);

@override
Map<String, String> possibilitiesToTags() => {'Yes': 'yes', 'No': 'no'};
}
123 changes: 123 additions & 0 deletions client/lib/quests/building_quests/building_type_quest.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import 'package:flutter/material.dart';
import 'package:latlong/latlong.dart';
import 'package:osm_api/osm_api.dart' as osm;

import 'package:client/quests/simple_tag_quest.dart';
import 'package:client/quests/quest.dart';
import 'package:client/quests/quest_finder.dart';

class BuildingTypeQuestFinder implements QuestFinder {
@override
Quest construct(osm.Element e) => BuildingTypeQuest(e);

@override
bool applicable(osm.Element e) =>
e.isWay &&
e.tags['building'] == "yes";
}

class BuildingTypeQuest extends SimpleTagQuest {
BuildingTypeQuest(osm.Element element) : super(element);

String tag() => 'building';

@override
String question() => "What type of building is this?";

@override
String changesetComment() => "Added buildingtype tag to a building";

@override
Widget icon() => Icon(Icons.house);

@override
Map<String, String> possibilitiesToTags() => {
//Accomodation
'Apartments': 'apartments',
'Bungalow': 'bungalow',
'Cabin': 'cabin',
'Detached': 'detached',
'Dormitory': 'dormitory',
'Farm': 'farm',
'Ger': 'ger',
'Hotel': 'hotel',
'House': 'house',
'Houseboat': 'houseboat',
'Residential': 'residential',
'Semidetached house': 'semidetached_house',
'Static caravan': 'static_caravan',
'Terrace': 'terrace',
// Commercial
'Commercial': 'commercial',
'Industrial': 'industrial',
'Kiosk': 'kiosk',
'Office': 'office',
'Retail': 'retail',
'Supermarket': 'supermarket',
'Warehouse': 'warehouse',
// Religious
'Cathedral': 'cathedral',
'Chapel': 'chapel',
'Church': 'church',
'Monastery': 'monastery',
'Mosque': 'mosque',
'Presbytery': 'presbytery',
'Religious': 'religious',
'Shine': 'shine',
'Synagogue': 'synagogue',
'Temple': 'temple',
//Civic/Amenity
'Bakehouse': 'bakehouse',
'Civic': 'civic',
'Fire station': 'fire_station',
'Government': 'government',
'Hospital': 'hospital',
'Public': 'public',
'Toilets': 'toilets',
'Train station': 'train_station',
'Transportation': 'transportation',
'Kindergarten': 'kindergarten',
'School': 'school',
'University': 'university',
'College': 'college',
//Agriculture
'Barn': 'barn',
'Conservatory': 'conservatory',
'Cowshed': 'cowshed',
'Farm auxiliary': 'farm_auxiliary',
'Greenhouse': 'greenhouse',
'Slurry tank': 'slurry_tank',
'Stable': 'stable',
'Sty': 'sty',
//spots
'Grandstand': 'grandstand',
'Pavilion': 'pavilion',
'Riding hall': 'riding_hall',
'Sports hall': 'sports_hall',
'Stadium': 'stadium',
//Storage
'Hangar': 'hangar',
'Hut': 'hut',
'Shed': 'shed',
//Cars
'Carport': 'carport',
'Garage': 'garage',
'Garages': 'garages',
'Parking': 'parking',
//Power
'Digester': 'digester',
'Service': 'service',
'Transformer tower': 'transformer_tower',
'Water tower': 'water_tower',
//Other
'Military': 'military',
'Bunker': 'bunker',
'Bridge': 'bridge',
'Construction': 'construction',
'Container': 'container',
'Gatehouse': 'gatehouse',
'Roof': 'roof',
'Ruins': 'ruins',
'Tree house': 'tree_house',
};
}
31 changes: 24 additions & 7 deletions client/lib/quests/quest.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import 'package:latlong/latlong.dart';
import 'package:flutter/material.dart';
import 'package:osm_api/osm_api.dart' as osm;
import 'package:latlong/latlong.dart';
import 'package:quiver/core.dart';

abstract class Quest {
LatLng position;

osm.Element element;
LatLng position = LatLng(0,0);

Quest(this.element);

Widget icon();

String changesetComment();

Quest(this.position, this.element);
String question();

String getChangesetComment();
Future<void> solve(osm.Api api, String possibility);

String getQuestion();
@override
bool operator ==(Object that) {
return that is Quest &&
this.element.type == that.element.type &&
this.element.id == that.element.id &&
this.question() == that.question();
}

List<String> getPossibilities();
// Inspired by this: https://stackoverflow.com/questions/20577606/whats-a-good-recipe-for-overriding-hashcode-in-dart
@override
int get hashCode {
return hash3(element.type.hashCode, element.id.hashCode, question());
}
}
8 changes: 8 additions & 0 deletions client/lib/quests/quest_finder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:osm_api/osm_api.dart';
import 'package:client/quests/quest.dart';

abstract class QuestFinder {
bool applicable(Element e);
Quest construct(Element e);
}

111 changes: 49 additions & 62 deletions client/lib/quests/quest_handler.dart
Original file line number Diff line number Diff line change
@@ -1,83 +1,70 @@
import 'package:client/location_handler.dart';
import 'package:client/login_handler.dart';
import 'package:client/quests/bench_quest/backrest_bench_quest.dart';
import 'package:client/quests/quest.dart';
import 'package:flutter/material.dart';
import 'package:latlong/latlong.dart';
import 'package:flutter/material.dart';
import 'package:osm_api/osm_api.dart' as osm;

import 'package:client/quests/bench_quests/backrest_bench_quest.dart';
import 'package:client/quests/building_quests/building_type_quest.dart';
import 'package:client/quests/quest.dart';

class QuestHandler extends ChangeNotifier {
osm.Api api;

List<Quest> quests = [];

bool _isBench(osm.Element element) {
return (element.tags.containsKey('amenity') &&
element.tags.containsValue('bench'));
}

bool _hasTagBenchBackrest(osm.Element element) {
return !(element.tags.containsKey('backrest'));
Set<Quest> quests = Set();

final finders = [
BackrestBenchQuestFinder(),
BuildingTypeQuestFinder(),
];

Map<int, osm.Element> _nodes = Map();

LatLng _position(osm.Element e) {
if (e.isNode)
return LatLng(e.lat, e.lon);
if (e.isWay) {
double latitude = 0, longitude = 0;
e.nodes.forEach((id) {
final n = _nodes[id];
latitude += n.lat;
longitude += n.lon;
});
var count = e.nodes.length;
latitude /= count;
longitude /= count;

print("Calculated pos: ${latitude}:${longitude}");
return LatLng(latitude, longitude);
}
throw Exception("Only coordinate node and way");
}

void getBenchQuests(
// Finding quests within bound
Future<void> loadQuests(
double left, double bottom, double right, double top) async {
api = osm.Api(
'id', osm.Auth.getUnauthorizedClient(), osm.ApiEnv.dev('master'));

// Fetch elements within bound
List<osm.Element> elements =
(await api.mapByBox(left, bottom, right, top)).elements;

List<Quest> benchQuests = [];
List<osm.Element> benchElements = elements
.where((element) => _isBench(element))
.where((element) => _hasTagBenchBackrest(element))
.toList();
elements.forEach((e) { if (e.isNode) _nodes[e.id] = e; });

benchElements.forEach((element) {
benchQuests
.add(BackrestBenchQuest(LatLng(element.lat, element.lon), element));
});

print(benchElements);
quests.removeWhere((element) => benchQuests.contains(element));
quests.addAll(benchQuests);

quests = benchQuests;
elements.forEach((e) => finders.forEach((f) {
if (f.applicable(e)) {
final q = f.construct(e);
if (!quests.contains(q)) {
q.position = _position(e);
quests.add(q);
}
}
}));

notifyListeners();
}

Future<void> answerBenchQuest(
LoginHandler loginHandler,
LocationHandler locationHandler,
QuestHandler questFinder,
BackrestBenchQuest quest,
int possibilityNumber,
) async {
var api = loginHandler.osmApi();

int changeSetId = await api.createChangeset(quest.getChangesetComment());

// add the new tag to the tag-map
quest.element.tags['backrest'] =
quest.getPossibilities()[possibilityNumber].toString();

int nodeId = await api.updateNode(
quest.element.id,
changeSetId,
quest.position.latitude,
quest.position.longitude,
quest.element.version,
quest.element.tags);

api.closeChangeset(changeSetId);
print('Selected answer: ' +
quest.getPossibilities()[possibilityNumber].toString());

questFinder.getBenchQuests(
locationHandler.mapController.bounds.west,
locationHandler.mapController.bounds.south,
locationHandler.mapController.bounds.east,
locationHandler.mapController.bounds.north);
void removeQuest(Quest quest) {
this.quests.remove(quest);
notifyListeners();
}
}
Loading

0 comments on commit 1cddfae

Please sign in to comment.