diff --git a/level_generator/.gitignore b/level_generator/.gitignore deleted file mode 100644 index 24476c5..0000000 --- a/level_generator/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -# 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 diff --git a/level_generator/.metadata b/level_generator/.metadata deleted file mode 100644 index 87280f8..0000000 --- a/level_generator/.metadata +++ /dev/null @@ -1,45 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled. - -version: - revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - channel: master - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - base_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - - platform: android - create_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - base_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - - platform: ios - create_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - base_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - - platform: linux - create_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - base_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - - platform: macos - create_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - base_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - - platform: web - create_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - base_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - - platform: windows - create_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - base_revision: 3443befab2bbcad4dc1c2d463df4ea983b9974f6 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/level_generator/README.md b/level_generator/README.md deleted file mode 100644 index 71481cc..0000000 --- a/level_generator/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# level_generator - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/level_generator/analysis_options.yaml b/level_generator/analysis_options.yaml deleted file mode 100644 index 61b6c4d..0000000 --- a/level_generator/analysis_options.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/level_generator/android/.gitignore b/level_generator/android/.gitignore deleted file mode 100644 index 6f56801..0000000 --- a/level_generator/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks diff --git a/level_generator/android/app/build.gradle b/level_generator/android/app/build.gradle deleted file mode 100644 index c834aaf..0000000 --- a/level_generator/android/app/build.gradle +++ /dev/null @@ -1,71 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.level_generator" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/level_generator/android/app/src/debug/AndroidManifest.xml b/level_generator/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 336b5da..0000000 --- a/level_generator/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/level_generator/android/app/src/main/AndroidManifest.xml b/level_generator/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 36ebc90..0000000 --- a/level_generator/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - diff --git a/level_generator/android/app/src/main/kotlin/com/example/level_generator/MainActivity.kt b/level_generator/android/app/src/main/kotlin/com/example/level_generator/MainActivity.kt deleted file mode 100644 index 42c3878..0000000 --- a/level_generator/android/app/src/main/kotlin/com/example/level_generator/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.level_generator - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/level_generator/android/app/src/main/res/drawable-v21/launch_background.xml b/level_generator/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f..0000000 --- a/level_generator/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/level_generator/android/app/src/main/res/drawable/launch_background.xml b/level_generator/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f..0000000 --- a/level_generator/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/level_generator/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/level_generator/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4..0000000 Binary files a/level_generator/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/level_generator/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/level_generator/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b7..0000000 Binary files a/level_generator/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/level_generator/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/level_generator/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d4391..0000000 Binary files a/level_generator/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/level_generator/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/level_generator/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d..0000000 Binary files a/level_generator/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/level_generator/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/level_generator/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372e..0000000 Binary files a/level_generator/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/level_generator/android/app/src/main/res/values-night/styles.xml b/level_generator/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 06952be..0000000 --- a/level_generator/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/level_generator/android/app/src/main/res/values/styles.xml b/level_generator/android/app/src/main/res/values/styles.xml deleted file mode 100644 index cb1ef88..0000000 --- a/level_generator/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/level_generator/android/app/src/profile/AndroidManifest.xml b/level_generator/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 336b5da..0000000 --- a/level_generator/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/level_generator/android/build.gradle b/level_generator/android/build.gradle deleted file mode 100644 index 58a8c74..0000000 --- a/level_generator/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.7.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/level_generator/android/gradle.properties b/level_generator/android/gradle.properties deleted file mode 100644 index 94adc3a..0000000 --- a/level_generator/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/level_generator/android/gradle/wrapper/gradle-wrapper.properties b/level_generator/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 3c472b9..0000000 --- a/level_generator/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/level_generator/android/settings.gradle b/level_generator/android/settings.gradle deleted file mode 100644 index 44e62bc..0000000 --- a/level_generator/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/level_generator/assets/level_test.json b/level_generator/assets/level_test.json deleted file mode 100644 index 67cb4d4..0000000 --- a/level_generator/assets/level_test.json +++ /dev/null @@ -1,37 +0,0 @@ - - -{ - "levelId": 1, - "words": [ - "SAW", "WASP", "SWAP", "NAP", "SPAWN" - ], - "boardHeight": 5, - "boardWidth": 5, - "boardData": [ - "W", - "", - "S", - "A", - "W", - "A", - "", - "W", - "", - "", - "S", - "P", - "A", - "W", - "N", - "P", - "", - "P", - "", - "A", - "", - "", - "", - "", - "P" - ] -} \ No newline at end of file diff --git a/level_generator/ios/.gitignore b/level_generator/ios/.gitignore deleted file mode 100644 index 7a7f987..0000000 --- a/level_generator/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/level_generator/ios/Flutter/AppFrameworkInfo.plist b/level_generator/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 9625e10..0000000 --- a/level_generator/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 11.0 - - diff --git a/level_generator/ios/Flutter/Debug.xcconfig b/level_generator/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee..0000000 --- a/level_generator/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/level_generator/ios/Flutter/Release.xcconfig b/level_generator/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee..0000000 --- a/level_generator/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/level_generator/ios/Runner.xcodeproj/project.pbxproj b/level_generator/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index b2fbdc3..0000000 --- a/level_generator/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,483 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.levelGenerator; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.levelGenerator; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.levelGenerator; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/level_generator/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/level_generator/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/level_generator/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/level_generator/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/level_generator/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/level_generator/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/level_generator/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/level_generator/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/level_generator/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/level_generator/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/level_generator/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index c87d15a..0000000 --- a/level_generator/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/level_generator/ios/Runner.xcworkspace/contents.xcworkspacedata b/level_generator/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a1..0000000 --- a/level_generator/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/level_generator/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/level_generator/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/level_generator/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/level_generator/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/level_generator/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/level_generator/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/level_generator/ios/Runner/AppDelegate.swift b/level_generator/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4..0000000 --- a/level_generator/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fa..0000000 --- a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 7353c41..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 797d452..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 6ed2d93..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cd7b00..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index fe73094..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 321773c..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 797d452..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 502f463..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 0ec3034..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 0ec3034..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index e9f5fea..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 84ac32a..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 8953cba..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 0467bf1..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2..0000000 --- a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725..0000000 --- a/level_generator/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/level_generator/ios/Runner/Base.lproj/LaunchScreen.storyboard b/level_generator/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c..0000000 --- a/level_generator/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/level_generator/ios/Runner/Base.lproj/Main.storyboard b/level_generator/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c2851..0000000 --- a/level_generator/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/level_generator/ios/Runner/Info.plist b/level_generator/ios/Runner/Info.plist deleted file mode 100644 index 8b023ed..0000000 --- a/level_generator/ios/Runner/Info.plist +++ /dev/null @@ -1,51 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Level Generator - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - level_generator - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/level_generator/ios/Runner/Runner-Bridging-Header.h b/level_generator/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a5..0000000 --- a/level_generator/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/level_generator/lib/core/error/failure.dart b/level_generator/lib/core/error/failure.dart deleted file mode 100644 index 71ab31f..0000000 --- a/level_generator/lib/core/error/failure.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:equatable/equatable.dart'; - -class Failure extends Equatable { - final List properties; - const Failure([this.properties = const []]); - - @override - List get props => properties; -} diff --git a/level_generator/lib/core/functionality/either.dart b/level_generator/lib/core/functionality/either.dart deleted file mode 100644 index 2a551fc..0000000 --- a/level_generator/lib/core/functionality/either.dart +++ /dev/null @@ -1,42 +0,0 @@ -// ignore_for_file: deprecated_member_use_from_same_package - -import 'package:equatable/equatable.dart'; - -@Deprecated("Use Either from dartz package instead") -abstract class Either { - const Either(); - C unfold( - C Function(L left) onLeft, - C Function(R right) onRight, - ); -} - -class Left extends Equatable implements Either { - final L _l; - const Left(this._l); - - @override - List get props => [_l]; - - @override - C unfold( - C Function(L left) onLeft, - C Function(R right) onRight, - ) => - onLeft(_l); -} - -class Right extends Equatable implements Either { - final R _r; - const Right(this._r); - - @override - List get props => [_r]; - - @override - C unfold( - C Function(L left) onLeft, - C Function(R right) onRight, - ) => - onRight(_r); -} diff --git a/level_generator/lib/core/usecases/use_case.dart b/level_generator/lib/core/usecases/use_case.dart deleted file mode 100644 index 85ac2ee..0000000 --- a/level_generator/lib/core/usecases/use_case.dart +++ /dev/null @@ -1,10 +0,0 @@ -import '../error/failure.dart'; -import 'package:dartz/dartz.dart'; - -abstract class UseCaseWithParams { - Future?>? call(Params params); -} - -abstract class UseCaseWithoutParams { - Future?>? call(); -} diff --git a/level_generator/lib/src/level_generator/domain/repos/level_generator_repo.dart b/level_generator/lib/src/level_generator/domain/repos/level_generator_repo.dart deleted file mode 100644 index 4de821f..0000000 --- a/level_generator/lib/src/level_generator/domain/repos/level_generator_repo.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:level_data/level_data.dart'; -import 'package:level_generator/core/error/failure.dart'; - -abstract class LevelGeneratorRepo { - // TODO: implement this method - // static Future _jsonLoader(String key) async { - // return await rootBundle.loadString(key); - // } - - /// Takes a dictionary and returns a LevelData object - /// Don't use this for json files, if you have a json file, use the - /// [GenerateLeveLFromJsonFile] - /// - /// ```dart - /// return LevelData( - /// levelId: dict["levelId"] as int, - /// words: dict["words"] as List, - /// boardWidth: dict["boardWidth"] as int, - /// boardHeight: dict["boardHeight"] as int, - /// boardData: dict["boardData"] as List, - /// rewards: dict["rewards"] - /// ); - ///``` - Future>? generateLevelFromDict( - Map? dict); - - /// Accepts the path of the json file and returns a LevelData object - /// Don't use this for raw HashMaps, if you have a hashmap, use the - /// [GenerateLevelFromDict] - /// - /// final data = - /// jsonDecode(await _jsonLoader(jsonPath)) as Map; - /// - /// return LevelData( - /// levelId: data["levelId"] as int, - /// words: List.from(data["words"]), - /// boardWidth: data["boardWidth"] as int, - /// boardHeight: data["boardHeight"] as int, - /// boardData: List.from(data["boardData"]), - /// rewards: data["rewards"] - /// ); - Future>? generateLevelFromJsonFile( - String? jsonPath); -} diff --git a/level_generator/lib/src/level_generator/domain/usecases/generate_level_from_dict.dart b/level_generator/lib/src/level_generator/domain/usecases/generate_level_from_dict.dart deleted file mode 100644 index ee78bf3..0000000 --- a/level_generator/lib/src/level_generator/domain/usecases/generate_level_from_dict.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; -import 'package:level_data/level_data.dart'; -import 'package:level_generator/core/error/failure.dart'; -import 'package:level_generator/core/usecases/use_case.dart'; -import 'package:level_generator/src/level_generator/domain/repos/level_generator_repo.dart'; - -class GenerateLevelFromDict - implements UseCaseWithParams { - final LevelGeneratorRepo repo; - const GenerateLevelFromDict(this.repo); - - @override - Future?> call( - GenerateLevelFromDictParams? params) async => - await repo.generateLevelFromDict(params?.dictionary); -} - -class GenerateLevelFromDictParams extends Equatable { - final Map dictionary; - const GenerateLevelFromDictParams({required this.dictionary}); - - @override - List get props => [dictionary]; -} diff --git a/level_generator/lib/src/level_generator/domain/usecases/generate_level_from_json_file.dart b/level_generator/lib/src/level_generator/domain/usecases/generate_level_from_json_file.dart deleted file mode 100644 index ae72a02..0000000 --- a/level_generator/lib/src/level_generator/domain/usecases/generate_level_from_json_file.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; -import 'package:level_data/level_data.dart'; -import 'package:level_generator/core/error/failure.dart'; -import 'package:level_generator/core/usecases/use_case.dart'; -import 'package:level_generator/src/level_generator/domain/repos/level_generator_repo.dart'; - -class GenerateLevelFromJsonFile - implements UseCaseWithParams { - final LevelGeneratorRepo repo; - GenerateLevelFromJsonFile(this.repo); - - @override - Future?> call( - GenerateLevelFromFileParams? params) async => - await repo.generateLevelFromJsonFile(params?.path); -} - -class GenerateLevelFromFileParams extends Equatable { - final String path; - const GenerateLevelFromFileParams({required this.path}); - - @override - List get props => [path]; -} diff --git a/level_generator/lib/src/rewards_generator/domain/repos/reward_repo.dart b/level_generator/lib/src/rewards_generator/domain/repos/reward_repo.dart deleted file mode 100644 index 8bf8b27..0000000 --- a/level_generator/lib/src/rewards_generator/domain/repos/reward_repo.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:level_data/level_data.dart'; -import 'package:level_generator/core/error/failure.dart'; - -abstract class RewardRepo { - Future>>? getRewards(int? levelId); -} diff --git a/level_generator/lib/src/rewards_generator/domain/usecases/get_rewards.dart b/level_generator/lib/src/rewards_generator/domain/usecases/get_rewards.dart deleted file mode 100644 index 183577d..0000000 --- a/level_generator/lib/src/rewards_generator/domain/usecases/get_rewards.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; -import 'package:level_data/level_data.dart'; -import 'package:level_generator/core/error/failure.dart'; -import 'package:level_generator/core/usecases/use_case.dart'; -import 'package:level_generator/src/rewards_generator/domain/repos/reward_repo.dart'; - -class GetRewards extends UseCaseWithParams, GetRewardsParams> { - final RewardRepo _rewardsRepo; - - GetRewards(this._rewardsRepo); - - /// Returns a list of rewards for the given level. If the level is null, it - /// returns the rewards for the first level. - /// The rewards should be generated based on the level. - /// e.g if the level is above 10, the rewards should be more valuable than - /// if the level is below 10. - - @override - Future>?> call(GetRewardsParams params) async { - return await _rewardsRepo.getRewards(params.levelId); - } -} - -class GetRewardsParams extends Equatable { - const GetRewardsParams({required this.levelId}); - final int levelId; - - @override - List get props => [levelId]; -} diff --git a/level_generator/linux/.gitignore b/level_generator/linux/.gitignore deleted file mode 100644 index d3896c9..0000000 --- a/level_generator/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/level_generator/linux/CMakeLists.txt b/level_generator/linux/CMakeLists.txt deleted file mode 100644 index 7475f11..0000000 --- a/level_generator/linux/CMakeLists.txt +++ /dev/null @@ -1,140 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.10) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "level_generator") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.level_generator") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) -# Ad adviced [here](https://github.com/rive-app/rive-flutter/issues/482#issuecomment-2961584235) -# Remove Later - target_compile_options(${TARGET} PRIVATE -Wall -Werror -Wno-error=nontrivial-memcall -Wnontrivial-memcall -Wno-unused-variable -Wno-unused-function) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/level_generator/linux/flutter/CMakeLists.txt b/level_generator/linux/flutter/CMakeLists.txt deleted file mode 100644 index d5bd016..0000000 --- a/level_generator/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/level_generator/linux/flutter/generated_plugin_registrant.cc b/level_generator/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index e71a16d..0000000 --- a/level_generator/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,11 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - - -void fl_register_plugins(FlPluginRegistry* registry) { -} diff --git a/level_generator/linux/flutter/generated_plugin_registrant.h b/level_generator/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47..0000000 --- a/level_generator/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/level_generator/linux/flutter/generated_plugins.cmake b/level_generator/linux/flutter/generated_plugins.cmake deleted file mode 100644 index 2e1de87..0000000 --- a/level_generator/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/level_generator/linux/main.cc b/level_generator/linux/main.cc deleted file mode 100644 index e7c5c54..0000000 --- a/level_generator/linux/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/level_generator/linux/my_application.cc b/level_generator/linux/my_application.cc deleted file mode 100644 index bbfe341..0000000 --- a/level_generator/linux/my_application.cc +++ /dev/null @@ -1,104 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "level_generator"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "level_generator"); - } - - gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); -} diff --git a/level_generator/linux/my_application.h b/level_generator/linux/my_application.h deleted file mode 100644 index 72271d5..0000000 --- a/level_generator/linux/my_application.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/level_generator/macos/.gitignore b/level_generator/macos/.gitignore deleted file mode 100644 index 746adbb..0000000 --- a/level_generator/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/level_generator/macos/Flutter/Flutter-Debug.xcconfig b/level_generator/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index c2efd0b..0000000 --- a/level_generator/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/level_generator/macos/Flutter/Flutter-Release.xcconfig b/level_generator/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index c2efd0b..0000000 --- a/level_generator/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/level_generator/macos/Flutter/GeneratedPluginRegistrant.swift b/level_generator/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index cccf817..0000000 --- a/level_generator/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,10 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { -} diff --git a/level_generator/macos/Runner.xcodeproj/project.pbxproj b/level_generator/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index dc6d868..0000000 --- a/level_generator/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,573 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* level_generator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "level_generator.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* level_generator.app */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* level_generator.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/level_generator/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/level_generator/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/level_generator/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/level_generator/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/level_generator/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 1aabf99..0000000 --- a/level_generator/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/level_generator/macos/Runner.xcworkspace/contents.xcworkspacedata b/level_generator/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a1..0000000 --- a/level_generator/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/level_generator/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/level_generator/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/level_generator/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/level_generator/macos/Runner/AppDelegate.swift b/level_generator/macos/Runner/AppDelegate.swift deleted file mode 100644 index d53ef64..0000000 --- a/level_generator/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Cocoa -import FlutterMacOS - -@NSApplicationMain -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } -} diff --git a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f..0000000 --- a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d..0000000 Binary files a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eb..0000000 Binary files a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa..0000000 Binary files a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb5722..0000000 Binary files a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318..0000000 Binary files a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e7..0000000 Binary files a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632c..0000000 Binary files a/level_generator/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/level_generator/macos/Runner/Base.lproj/MainMenu.xib b/level_generator/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a..0000000 --- a/level_generator/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/level_generator/macos/Runner/Configs/AppInfo.xcconfig b/level_generator/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 1a109a3..0000000 --- a/level_generator/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = level_generator - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.levelGenerator - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2022 com.example. All rights reserved. diff --git a/level_generator/macos/Runner/Configs/Debug.xcconfig b/level_generator/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd9..0000000 --- a/level_generator/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/level_generator/macos/Runner/Configs/Release.xcconfig b/level_generator/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f49..0000000 --- a/level_generator/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/level_generator/macos/Runner/Configs/Warnings.xcconfig b/level_generator/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf4..0000000 --- a/level_generator/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/level_generator/macos/Runner/DebugProfile.entitlements b/level_generator/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a3..0000000 --- a/level_generator/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/level_generator/macos/Runner/Info.plist b/level_generator/macos/Runner/Info.plist deleted file mode 100644 index 4789daa..0000000 --- a/level_generator/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/level_generator/macos/Runner/MainFlutterWindow.swift b/level_generator/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 2722837..0000000 --- a/level_generator/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/level_generator/macos/Runner/Release.entitlements b/level_generator/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a..0000000 --- a/level_generator/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/level_generator/pubspec.lock b/level_generator/pubspec.lock deleted file mode 100644 index e1dfeeb..0000000 --- a/level_generator/pubspec.lock +++ /dev/null @@ -1,236 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - dartz: - dependency: "direct main" - description: - name: dartz - sha256: e6acf34ad2e31b1eb00948692468c30ab48ac8250e0f0df661e29f12dd252168 - url: "https://pub.dev" - source: hosted - version: "0.10.1" - equatable: - dependency: "direct main" - description: - name: equatable - sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" - url: "https://pub.dev" - source: hosted - version: "2.0.7" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" - url: "https://pub.dev" - source: hosted - version: "10.0.9" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.dev" - source: hosted - version: "3.0.9" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - level_data: - dependency: "direct main" - description: - path: "../packages/level_data" - relative: true - source: path - version: "1.0.0" - lints: - dependency: transitive - description: - name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mocktail: - dependency: "direct dev" - description: - name: mocktail - sha256: c4b5007d91ca4f67256e720cb1b6d704e79a510183a12fa551021f652577dce6 - url: "https://pub.dev" - source: hosted - version: "1.0.3" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.dev" - source: hosted - version: "0.7.4" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.dev" - source: hosted - version: "15.0.0" -sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" diff --git a/level_generator/pubspec.yaml b/level_generator/pubspec.yaml deleted file mode 100644 index 616c49c..0000000 --- a/level_generator/pubspec.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: level_generator -description: A new Flutter project. - -publish_to: 'none' - -version: 1.0.0+1 - -environment: - sdk: '>=3.1.0-287.0.dev <4.0.0' - -dependencies: - dartz: ^0.10.1 - equatable: ^2.0.7 - flutter: - sdk: flutter - level_data: - path: ../packages/level_data - - -dev_dependencies: - flutter_lints: ^4.0.0 - flutter_test: - sdk: flutter - mocktail: ^1.0.3 - -flutter: - uses-material-design: true - - assets: - - assets/ diff --git a/level_generator/test/src/level_generator/domain/usecases/generate_level_from_dict_test.dart b/level_generator/test/src/level_generator/domain/usecases/generate_level_from_dict_test.dart deleted file mode 100644 index d5d37c8..0000000 --- a/level_generator/test/src/level_generator/domain/usecases/generate_level_from_dict_test.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:level_data/level_data.dart'; -import 'package:level_generator/src/level_generator/domain/repos/level_generator_repo.dart'; -import 'package:level_generator/src/level_generator/domain/usecases/generate_level_from_dict.dart'; -import 'package:mocktail/mocktail.dart'; - -class MockLevelGeneratorRepo extends Mock implements LevelGeneratorRepo {} - -void main() { - late MockLevelGeneratorRepo repo; - late GenerateLevelFromDict useCase; - - setUp(() { - repo = MockLevelGeneratorRepo(); - useCase = GenerateLevelFromDict(repo); - }); - - final testDictionary = { - "levelId": 1, - "words": ["SAW", "WASP"], - "boardHeight": 5, - "boardWidth": 5, - "boardData": ["W", "S", ""], - "rewards": [ - { - "id": 1, - "name": "Test Badge", - "description": "Test Badge Description", - "image": "Test Badge Image", - "points": 50, - }, - { - "id": 2, - "name": "Test Coin", - "description": "Test Coin Description", - "image": "Test Coin Image", - "points": 500, - }, - ], - }; - - const testLevelData = LevelData( - levelId: 1, - words: ["SAW", "WASP"], - boardHeight: 5, - boardWidth: 5, - boardData: ["W", "S", ""], - rewards: [ - Badge( - id: 1, - name: "Test Badge", - description: "Test Badge Description", - image: "Test Badge Image", - points: 50, - ), - RewardCoin( - id: 2, - name: "Test Coin", - description: "Test Coin Description", - image: "Test Coin Image", - points: 500, - ), - ]); - - test("generate level data from dictionary", () async { - when(() => repo.generateLevelFromDict(any())) - .thenAnswer((_) async => const Right(testLevelData)); - - final result = - await useCase(GenerateLevelFromDictParams(dictionary: testDictionary)); - - expect(result, const Right(testLevelData)); - - verify(() => repo.generateLevelFromDict(testDictionary)); - verifyNoMoreInteractions(repo); - }); -} diff --git a/level_generator/test/src/level_generator/domain/usecases/generate_level_from_json_file_test.dart b/level_generator/test/src/level_generator/domain/usecases/generate_level_from_json_file_test.dart deleted file mode 100644 index 6fbbf1a..0000000 --- a/level_generator/test/src/level_generator/domain/usecases/generate_level_from_json_file_test.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:level_data/level_data.dart'; -import 'package:level_generator/src/level_generator/domain/repos/level_generator_repo.dart'; -import 'package:level_generator/src/level_generator/domain/usecases/generate_level_from_json_file.dart'; -import 'package:mocktail/mocktail.dart'; - -class MockLevelGeneratorRepo extends Mock implements LevelGeneratorRepo {} - -void main() { - late MockLevelGeneratorRepo repo; - late GenerateLevelFromJsonFile useCase; - setUp(() { - repo = MockLevelGeneratorRepo(); - useCase = GenerateLevelFromJsonFile(repo); - }); - - const testPath = "assets/level_test.json"; - const testLevelData = LevelData( - levelId: 1, - words: ["SAW", "WASP"], - boardHeight: 5, - boardWidth: 5, - boardData: ["W", "S", ""], - rewards: [ - Badge( - id: 1, - name: "Test Badge", - description: "Test Badge Description", - image: "Test Badge Image", - points: 50, - ), - RewardCoin( - id: 2, - name: "Test Coin", - description: "Test Coin Description", - image: "Test Coin Image", - points: 500, - ), - ]); - - test("generate level data from json file", () async { - when(() => repo.generateLevelFromJsonFile(any())) - .thenAnswer((_) async => const Right(testLevelData)); - - final result = - await useCase(const GenerateLevelFromFileParams(path: testPath)); - - expect(result, const Right(testLevelData)); - verify(() => repo.generateLevelFromJsonFile(testPath)); - verifyNoMoreInteractions(repo); - }); -} diff --git a/level_generator/test/src/rewards_generator/domain/usecases/get_rewards_test.dart b/level_generator/test/src/rewards_generator/domain/usecases/get_rewards_test.dart deleted file mode 100644 index cdd1be8..0000000 --- a/level_generator/test/src/rewards_generator/domain/usecases/get_rewards_test.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:level_data/level_data.dart'; -import 'package:level_generator/src/rewards_generator/domain/repos/reward_repo.dart'; -import 'package:level_generator/src/rewards_generator/domain/usecases/get_rewards.dart'; -import 'package:mocktail/mocktail.dart'; - -class MockRewardRepo extends Mock implements RewardRepo {} - -void main() { - late MockRewardRepo repo; - late GetRewards useCase; - - setUp(() { - repo = MockRewardRepo(); - useCase = GetRewards(repo); - }); - - const testLevel = 1; - const testRewards = [ - Badge( - id: 1, - name: "Test Badge", - description: "Test Badge Description", - image: "Test Badge Image", - points: 50, - ), - RewardCoin( - id: 2, - name: "Test Coin", - description: "Test Coin Description", - image: "Test Coin Image", - points: 100, - ), - ]; - - test('get rewards', () async { - when(() => repo.getRewards(any())) - .thenAnswer((_) async => const Right(testRewards)); - - final result = - await useCase.call(const GetRewardsParams(levelId: testLevel)); - - expect(result, const Right(testRewards)); - verify(() => repo.getRewards(testLevel)); - verifyNoMoreInteractions(repo); - }); -} diff --git a/level_generator/web/favicon.png b/level_generator/web/favicon.png deleted file mode 100644 index 8aaa46a..0000000 Binary files a/level_generator/web/favicon.png and /dev/null differ diff --git a/level_generator/web/icons/Icon-192.png b/level_generator/web/icons/Icon-192.png deleted file mode 100644 index b749bfe..0000000 Binary files a/level_generator/web/icons/Icon-192.png and /dev/null differ diff --git a/level_generator/web/icons/Icon-512.png b/level_generator/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48..0000000 Binary files a/level_generator/web/icons/Icon-512.png and /dev/null differ diff --git a/level_generator/web/icons/Icon-maskable-192.png b/level_generator/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d7..0000000 Binary files a/level_generator/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/level_generator/web/icons/Icon-maskable-512.png b/level_generator/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c566..0000000 Binary files a/level_generator/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/level_generator/web/index.html b/level_generator/web/index.html deleted file mode 100644 index e5c8bd9..0000000 --- a/level_generator/web/index.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - level_generator - - - - - - - - - - diff --git a/level_generator/web/manifest.json b/level_generator/web/manifest.json deleted file mode 100644 index 4b4f4a9..0000000 --- a/level_generator/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "level_generator", - "short_name": "level_generator", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/level_generator/windows/.gitignore b/level_generator/windows/.gitignore deleted file mode 100644 index d492d0d..0000000 --- a/level_generator/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/level_generator/windows/CMakeLists.txt b/level_generator/windows/CMakeLists.txt deleted file mode 100644 index cc23e79..0000000 --- a/level_generator/windows/CMakeLists.txt +++ /dev/null @@ -1,101 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(level_generator LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "level_generator") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) diff --git a/level_generator/windows/flutter/CMakeLists.txt b/level_generator/windows/flutter/CMakeLists.txt deleted file mode 100644 index 930d207..0000000 --- a/level_generator/windows/flutter/CMakeLists.txt +++ /dev/null @@ -1,104 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) diff --git a/level_generator/windows/flutter/generated_plugin_registrant.cc b/level_generator/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 8b6d468..0000000 --- a/level_generator/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,11 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - - -void RegisterPlugins(flutter::PluginRegistry* registry) { -} diff --git a/level_generator/windows/flutter/generated_plugin_registrant.h b/level_generator/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d8..0000000 --- a/level_generator/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/level_generator/windows/flutter/generated_plugins.cmake b/level_generator/windows/flutter/generated_plugins.cmake deleted file mode 100644 index b93c4c3..0000000 --- a/level_generator/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/level_generator/windows/runner/CMakeLists.txt b/level_generator/windows/runner/CMakeLists.txt deleted file mode 100644 index 394917c..0000000 --- a/level_generator/windows/runner/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/level_generator/windows/runner/Runner.rc b/level_generator/windows/runner/Runner.rc deleted file mode 100644 index e47bce2..0000000 --- a/level_generator/windows/runner/Runner.rc +++ /dev/null @@ -1,121 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.example" "\0" - VALUE "FileDescription", "level_generator" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "level_generator" "\0" - VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0" - VALUE "OriginalFilename", "level_generator.exe" "\0" - VALUE "ProductName", "level_generator" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED diff --git a/level_generator/windows/runner/flutter_window.cpp b/level_generator/windows/runner/flutter_window.cpp deleted file mode 100644 index b25e363..0000000 --- a/level_generator/windows/runner/flutter_window.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); - - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} diff --git a/level_generator/windows/runner/flutter_window.h b/level_generator/windows/runner/flutter_window.h deleted file mode 100644 index 6da0652..0000000 --- a/level_generator/windows/runner/flutter_window.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/level_generator/windows/runner/main.cpp b/level_generator/windows/runner/main.cpp deleted file mode 100644 index f18791f..0000000 --- a/level_generator/windows/runner/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"level_generator", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} diff --git a/level_generator/windows/runner/resource.h b/level_generator/windows/runner/resource.h deleted file mode 100644 index 66a65d1..0000000 --- a/level_generator/windows/runner/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/level_generator/windows/runner/resources/app_icon.ico b/level_generator/windows/runner/resources/app_icon.ico deleted file mode 100644 index c04e20c..0000000 Binary files a/level_generator/windows/runner/resources/app_icon.ico and /dev/null differ diff --git a/level_generator/windows/runner/runner.exe.manifest b/level_generator/windows/runner/runner.exe.manifest deleted file mode 100644 index a42ea76..0000000 --- a/level_generator/windows/runner/runner.exe.manifest +++ /dev/null @@ -1,20 +0,0 @@ - - - - - PerMonitorV2 - - - - - - - - - - - - - - - diff --git a/level_generator/windows/runner/utils.cpp b/level_generator/windows/runner/utils.cpp deleted file mode 100644 index f5bf9fa..0000000 --- a/level_generator/windows/runner/utils.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr); - std::string utf8_string; - if (target_length == 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, utf8_string.data(), - target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} diff --git a/level_generator/windows/runner/utils.h b/level_generator/windows/runner/utils.h deleted file mode 100644 index 3879d54..0000000 --- a/level_generator/windows/runner/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ diff --git a/level_generator/windows/runner/win32_window.cpp b/level_generator/windows/runner/win32_window.cpp deleted file mode 100644 index 041a385..0000000 --- a/level_generator/windows/runner/win32_window.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "win32_window.h" - -#include -#include - -#include "resource.h" - -namespace { - -/// Window attribute that enables dark mode window decorations. -/// -/// Redefined in case the developer's machine has a Windows SDK older than -/// version 10.0.22000.0. -/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -/// Registry key for app theme preference. -/// -/// A value of 0 indicates apps should use dark mode. A non-zero or missing -/// value indicates apps should use light mode. -constexpr const wchar_t kGetPreferredBrightnessRegKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; -constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::Create(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - UpdateTheme(window); - - return OnCreate(); -} - -bool Win32Window::Show() { - return ShowWindow(window_handle_, SW_SHOWNORMAL); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - - case WM_DWMCOLORIZATIONCOLORCHANGED: - UpdateTheme(hwnd); - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} - -void Win32Window::UpdateTheme(HWND const window) { - DWORD light_mode; - DWORD light_mode_size = sizeof(light_mode); - LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, - kGetPreferredBrightnessRegValue, - RRF_RT_REG_DWORD, nullptr, &light_mode, - &light_mode_size); - - if (result == ERROR_SUCCESS) { - BOOL enable_dark_mode = light_mode == 0; - DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, - &enable_dark_mode, sizeof(enable_dark_mode)); - } -} diff --git a/level_generator/windows/runner/win32_window.h b/level_generator/windows/runner/win32_window.h deleted file mode 100644 index c86632d..0000000 --- a/level_generator/windows/runner/win32_window.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates a win32 window with |title| that is positioned and sized using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size this function will scale the inputted width and height as - // as appropriate for the default monitor. The window is invisible until - // |Show| is called. Returns true if the window was created successfully. - bool Create(const std::wstring& title, const Point& origin, const Size& size); - - // Show the current window. Returns true if the window was successfully shown. - bool Show(); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responsponds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - // Update the window frame's theme to match the system theme. - static void UpdateTheme(HWND const window); - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/lib/app.dart b/lib/app.dart index e1f7af2..71b5e0b 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:level_generator/level_generator.dart'; import 'package:sozzle/core/routes/routes.dart'; import 'package:sozzle/l10n/arb/app_localizations.dart'; import 'package:sozzle/src/apploader/application/apploader_repository.dart'; @@ -25,7 +26,15 @@ class App extends StatelessWidget { return MultiRepositoryProvider( providers: [ RepositoryProvider( - create: (context) => LevelRepository(), + create: (context) => LevelRepository( + levelGenerator: LevelGenerator( + crosswordGenerator: CrosswordGenerator(), + wordListService: WordListService( + wordListPath: 'assets/words/wordlist.txt', + ), + definitionFetcher: DefinitionFetcher(), + ), + ), ), RepositoryProvider( create: (context) => UserStatsRepository(), diff --git a/lib/src/apploader/application/apploader_repository.dart b/lib/src/apploader/application/apploader_repository.dart index 9308047..c58676e 100644 --- a/lib/src/apploader/application/apploader_repository.dart +++ b/lib/src/apploader/application/apploader_repository.dart @@ -1,5 +1,4 @@ //import 'package:http/http.dart' as http; -import 'package:level_data/level_data.dart'; import 'package:sozzle/src/apploader/apploader.dart'; import 'package:sozzle/src/level/domain/i_level_repository.dart'; import 'package:sozzle/src/level/domain/level_data.dart'; @@ -25,147 +24,8 @@ class MockApploaderRepository implements IApploaderRepository { @override Future getLevels() async { - // TODO(akyunus): get data online - list.levels.addAll([ - const LevelData( - levelId: 1, - words: [ - 'RIFLE', - 'FLIRT', - 'FIRE', - 'LEFT', - 'TIRE', - 'REFIT', - 'FILTER', - 'RELIT', - 'TIER', - ], - boardHeight: 9, - boardWidth: 8, -/* - REFIT -R I -I F R -FILTER -L I -E RELIT - T E I - F R - TIER -*/ - boardData: [ - '', - 'R', - 'I', - 'F', - 'L', - 'E', - '', - '', - '', - '', - '', - '', - 'I', - '', - '', - '', - '', - '', - 'R', - '', - 'F', - 'L', - 'I', - 'R', - 'T', - '', - '', - 'E', - '', - '', - 'T', - '', - 'E', - '', - '', - '', - 'F', - 'I', - 'R', - 'E', - '', - 'L', - 'E', - 'F', - 'T', - 'I', - '', - '', - 'R', - '', - 'I', - '', - '', - 'I', - 'T', - '', - '', - '', - '', - 'T', - 'I', - 'R', - 'E', - '', - '', - '', - '', - '', - '', - '', - '', - 'R', - ], - ), - const LevelData( - levelId: 2, - words: ['SAW', 'WASP', 'SWAP', 'NAP', 'SPAWN'], - boardHeight: 5, - boardWidth: 5, - boardData: [ - 'W', - '', - 'S', - 'A', - 'W', - 'A', - '', - 'W', - '', - '', - 'S', - 'P', - 'A', - 'W', - 'N', - 'P', - '', - 'P', - '', - 'A', - '', - '', - '', - '', - 'P', - ], - ), - ]); - /*LevelData(boardData: [], levelId: 2, words: []), - LevelData(boardData: [], levelId: 3, words: []), - LevelData(boardData: [], levelId: 4, words: []),*/ - + final levels = await levelRepository.getLevels(); + list.levels.addAll(levels); return list; } diff --git a/lib/src/game_play/bloc/game_play_bloc.dart b/lib/src/game_play/bloc/game_play_bloc.dart index 1fe608f..e27a7fe 100644 --- a/lib/src/game_play/bloc/game_play_bloc.dart +++ b/lib/src/game_play/bloc/game_play_bloc.dart @@ -157,6 +157,7 @@ class GamePlayBloc extends HydratedBloc { } } + // coverage:ignore-start FutureOr _handleRevealRandomLetter( RevealRandomLetterEvent event, Emitter emit, @@ -187,6 +188,7 @@ class GamePlayBloc extends HydratedBloc { } return state; } + // coverage:ignore-end @override Map? toJson(GamePlayState state) { diff --git a/lib/src/game_play/domain/entities/booster.dart b/lib/src/game_play/domain/entities/booster.dart index a32d4bf..fab42b4 100644 --- a/lib/src/game_play/domain/entities/booster.dart +++ b/lib/src/game_play/domain/entities/booster.dart @@ -25,8 +25,10 @@ abstract class IBooster extends Equatable { /// Decrease the [boosterCount] by the given [boosterCount] IBooster decreaseBy({int? boosterCount}); + // coverage:ignore-start @override List get props => [id]; + // coverage:ignore-end } class Booster extends IBooster { @@ -37,6 +39,7 @@ class Booster extends IBooster { required this.boosterCount, }); + // coverage:ignore-start factory Booster.fromId({required String id, required int boosterCount}) { return switch (id) { UseAHint.boosterId => UseAHint(boosterCount: boosterCount), @@ -48,6 +51,7 @@ class Booster extends IBooster { ), }; } + // coverage:ignore-end @override final String id; @@ -71,10 +75,12 @@ class Booster extends IBooster { return copyWith(boosterCount: this.boosterCount + boosterCount!); } + // coverage:ignore-start @override Booster decreaseBy({int? boosterCount}) { return copyWith(boosterCount: this.boosterCount - boosterCount!); } + // coverage:ignore-end } /// A generic booster that does nothing. diff --git a/lib/src/game_play/view/components/crossword_clues_button.dart b/lib/src/game_play/view/components/crossword_clues_button.dart new file mode 100644 index 0000000..041c2ec --- /dev/null +++ b/lib/src/game_play/view/components/crossword_clues_button.dart @@ -0,0 +1,42 @@ +// coverage:ignore-file +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:sozzle/src/game_play/bloc/game_play_bloc.dart'; +import 'package:sozzle/src/game_play/view/components/crossword_clues_dialog.dart'; +import 'package:sozzle/src/theme/theme.dart'; + +/// A button that opens a dialog showing crossword clues for the current level. +class CrosswordCluesButton extends StatelessWidget { + const CrosswordCluesButton({super.key}); + + @override + Widget build(BuildContext context) { + final theme = context.watch().state; + final levelData = context.read().levelData; + + // Don't show button if there are no crosswords + if (levelData.crosswords.isEmpty) { + return const SizedBox.shrink(); + } + + return Tooltip( + message: 'View crossword clues', + child: IconButton( + icon: const Icon(Icons.view_list_rounded), + iconSize: 30, + color: theme.primaryTextColor, + onPressed: () { + showDialog( + context: context, + builder: (dialogContext) => BlocProvider.value( + value: context.read(), + child: CrosswordCluesDialog( + levelData: levelData, + ), + ), + ); + }, + ), + ); + } +} diff --git a/lib/src/game_play/view/components/crossword_clues_dialog.dart b/lib/src/game_play/view/components/crossword_clues_dialog.dart new file mode 100644 index 0000000..6535bdb --- /dev/null +++ b/lib/src/game_play/view/components/crossword_clues_dialog.dart @@ -0,0 +1,225 @@ +// coverage:ignore-file +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:level_data/level_data.dart'; +import 'package:sozzle/src/game_play/bloc/game_play_bloc.dart'; +import 'package:sozzle/src/theme/theme.dart'; + +/// A dialog that displays crossword clues organized by direction (Across/Down). +class CrosswordCluesDialog extends StatelessWidget { + const CrosswordCluesDialog({ + required this.levelData, + super.key, + }); + + final LevelData levelData; + + @override + Widget build(BuildContext context) { + final theme = context.watch().state; + final size = MediaQuery.of(context).size; + + // Responsive sizing + final dialogWidth = size.width > 600 ? 500.0 : size.width * 0.9; + final dialogHeight = size.height > 700 ? 600.0 : size.height * 0.8; + + // Separate and sort clues by direction + final acrossClues = levelData.crosswords.values + .where((c) => c.direction == CrossWordDirection.across) + .toList() + ..sort((a, b) => a.directionIndex.compareTo(b.directionIndex)); + + final downClues = levelData.crosswords.values + .where((c) => c.direction == CrossWordDirection.down) + .toList() + ..sort((a, b) => a.directionIndex.compareTo(b.directionIndex)); + + return Dialog( + backgroundColor: theme.backgroundColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Container( + width: dialogWidth, + height: dialogHeight, + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Crossword Clues', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: theme.primaryTextColor, + ), + ), + IconButton( + icon: Icon( + Icons.close, + color: theme.primaryTextColor, + ), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + const SizedBox(height: 16), + + // Clues list + Expanded( + child: BlocBuilder( + builder: (context, state) { + final bloc = context.read(); + + return ListView( + children: [ + // Across clues + if (acrossClues.isNotEmpty) ...[ + Text( + 'ACROSS', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: theme.primaryTextColor, + letterSpacing: 1.2, + ), + ), + const SizedBox(height: 12), + ...acrossClues.map( + (clue) => _ClueItem( + clue: clue, + theme: theme, + isFound: bloc.foundWords + .contains(clue.word.toUpperCase()), + ), + ), + const SizedBox(height: 24), + ], + + // Down clues + if (downClues.isNotEmpty) ...[ + Text( + 'DOWN', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: theme.primaryTextColor, + letterSpacing: 1.2, + ), + ), + const SizedBox(height: 12), + ...downClues.map( + (clue) => _ClueItem( + clue: clue, + theme: theme, + isFound: bloc.foundWords + .contains(clue.word.toUpperCase()), + ), + ), + ], + ], + ); + }, + ), + ), + ], + ), + ), + ); + } +} + +/// Individual clue item widget. +class _ClueItem extends StatelessWidget { + const _ClueItem({ + required this.clue, + required this.theme, + required this.isFound, + }); + + final Crossword clue; + final ThemeState theme; + final bool isFound; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Clue number + SizedBox( + width: 40, + child: Text( + '${clue.directionIndex}.', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: isFound + ? theme.primaryTextColor.withValues(alpha: 0.5) + : theme.primaryTextColor, + ), + ), + ), + + // Clue definition and word info + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Definition + Text( + clue.definition ?? 'No definition available', + style: TextStyle( + fontSize: 15, + color: isFound + ? theme.primaryTextColor.withValues(alpha: 0.5) + : theme.primaryTextColor, + decoration: isFound ? TextDecoration.lineThrough : null, + ), + ), + + // Word length hint and found indicator + const SizedBox(height: 4), + Row( + children: [ + Text( + '(${clue.word.length} letters)', + style: TextStyle( + fontSize: 13, + color: theme.primaryTextColor.withValues(alpha: 0.6), + fontStyle: FontStyle.italic, + ), + ), + if (isFound) ...[ + const SizedBox(width: 8), + Icon( + Icons.check_circle, + size: 16, + color: Colors.green.withValues(alpha: 0.7), + ), + const SizedBox(width: 4), + Text( + clue.word, + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w600, + color: Colors.green.withValues(alpha: 0.7), + ), + ), + ], + ], + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/game_play/view/components/game_play_header.dart b/lib/src/game_play/view/components/game_play_header.dart index 12627ae..ff0cf56 100644 --- a/lib/src/game_play/view/components/game_play_header.dart +++ b/lib/src/game_play/view/components/game_play_header.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:sozzle/core/common/widgets/scorecard.dart'; +import 'package:sozzle/src/game_play/view/components/crossword_clues_button.dart'; import 'package:sozzle/src/game_play/view/components/hint.dart'; import 'package:sozzle/src/home/home.dart'; import 'package:sozzle/src/theme/cubit/theme_cubit.dart'; @@ -20,9 +21,9 @@ class GamePlayHeader extends StatelessWidget { builder: (context, state) { final theme = context.watch().state; return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16).copyWith( - top: renderColumn ? 16 : 32, - ), + padding: const EdgeInsets.symmetric( + horizontal: 16, + ).copyWith(top: renderColumn ? 16 : 32), child: switch (renderColumn) { true => MobileHeader(state: state, theme: theme), _ => ConstrainedBox( @@ -55,15 +56,21 @@ class DesktopHeader extends StatelessWidget { failedAttempts: '0', ), ), - IconButton( - icon: const Icon(Icons.home), - iconSize: 30, - color: theme.primaryTextColor, - onPressed: () { - context.go(HomePage.path); - }, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const CrosswordCluesButton(), + IconButton( + icon: const Icon(Icons.home), + iconSize: 30, + color: theme.primaryTextColor, + onPressed: () { + context.go(HomePage.path); + }, + ), + const Hint(), + ], ), - const Hint(), ], ); } @@ -80,12 +87,10 @@ class MobileHeader extends StatelessWidget { return Column( mainAxisSize: MainAxisSize.min, children: [ - Scorecard( - level: state.progress.currentLevel, - failedAttempts: '0', - ), + Scorecard(level: state.progress.currentLevel, failedAttempts: '0'), Row( children: [ + const CrosswordCluesButton(), IconButton( icon: const Icon(Icons.home), iconSize: 30, diff --git a/lib/src/game_play/view/components/game_play_letters.dart b/lib/src/game_play/view/components/game_play_letters.dart index 23eee19..4a47cce 100644 --- a/lib/src/game_play/view/components/game_play_letters.dart +++ b/lib/src/game_play/view/components/game_play_letters.dart @@ -11,7 +11,9 @@ import 'package:sozzle/src/game_play/view/components/guess_text.dart'; class GamePlayLetters extends StatefulWidget { const GamePlayLetters(this.levelData, {super.key}); + final LevelData levelData; + @override State createState() => _GamePlayLettersState(); } @@ -23,13 +25,60 @@ class _GamePlayLettersState extends State { @override void initState() { - // TODO(check): if needed, find anotherway to extract letters - letters = widget.levelData.boardData.toSet().toList() - ..remove(' ') - ..remove(''); + letters = []; + + for (final char in widget.levelData.boardData) { + if (char.trim().isNotEmpty) letters.add(char); + } + + normaliseLetterList(); + + letters.shuffle(); + super.initState(); } + // coverage:ignore-start + void normaliseLetterList() { + final letterCount = {}; + for (final word in widget.levelData.words) { + // Holds the count of each letter in the current word + final wordLetterCount = {}; + // For each letter in the word, count its occurrences + // and store in wordLetterCount + for (final char in word.split('')) { + wordLetterCount[char] = (wordLetterCount[char] ?? 0) + 1; + } + // Update the overall letterCount to ensure it has + // the maximum count needed for each letter + // For example, if the letter 'A' appears 2 times in one word + // and 3 times in another, letterCount['A'] should be 3 + for (final entry in wordLetterCount.entries) { + final char = entry.key; + final count = entry.value; + if (letterCount.containsKey(char)) { + letterCount[char] = + letterCount[char]! < count ? count : letterCount[char]!; + } else { + letterCount[char] = count; + } + } + } + + /// I need this check to avoid clearing letters when we're in a test + /// environment where levelData.words might be empty. + if (widget.levelData.words.isNotEmpty) { + letters.clear(); + + letterCount.forEach((char, count) { + for (var i = 0; i < count; i++) { + letters.add(char); + } + }); + } + } + + // coverage:ignore-end @override void dispose() { clearGuessTimer.cancel(); @@ -56,6 +105,7 @@ class _GamePlayLettersState extends State { ); } + // coverage:ignore-start void _onInputStart() { _clearGuess(); clearGuessTimer.cancel(); @@ -86,4 +136,5 @@ class _GamePlayLettersState extends State { guess = ''; }); } + // coverage:ignore-end } diff --git a/lib/src/game_play/view/view.dart b/lib/src/game_play/view/view.dart index 6c75b0f..95fbbeb 100644 --- a/lib/src/game_play/view/view.dart +++ b/lib/src/game_play/view/view.dart @@ -1,3 +1,5 @@ +export './components/crossword_clues_button.dart'; +export './components/crossword_clues_dialog.dart'; export './components/game_play_board.dart'; export './components/game_play_header.dart'; export './components/game_play_letters.dart'; diff --git a/lib/src/level/application/level_repository.dart b/lib/src/level/application/level_repository.dart index ff598b1..4447003 100644 --- a/lib/src/level/application/level_repository.dart +++ b/lib/src/level/application/level_repository.dart @@ -1,20 +1,72 @@ +import 'dart:developer'; + +import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:level_data/level_data.dart'; +import 'package:level_generator/level_generator.dart'; import 'package:localstore/localstore.dart'; import 'package:sozzle/src/level/domain/i_level_repository.dart'; /// Save and load [LevelData] by levelId from disk using [Localstore] class LevelRepository implements ILevelRepository { + LevelRepository({required LevelGenerator levelGenerator}) + : _levelGenerator = levelGenerator; + + final LevelGenerator _levelGenerator; final _db = Localstore.instance; @override Future getLevel(int levelId) async { // TODO(any): error handling - final data = await _db.collection('levels').doc('$levelId').get(); - return LevelData.fromMap(data!); + try { + final data = await _db.collection('levels').doc('$levelId').get(); + if (data == null) { + log( + 'Level $levelId not found in localstore, generating new level', + name: 'LevelRepository.getLevel', + ); + final levelData = await _levelGenerator.generateLevel(level: levelId); + log( + 'Generated level $levelId: ${levelData.toMap()}', + name: 'LevelRepository.getLevel', + ); + await setLevel(levelData); + log( + 'Saved generated level $levelId to localstore', + name: 'LevelRepository.getLevel', + ); + return levelData; + } + + return LevelData.fromMap(data); + } on Exception catch (e, s) { + log( + 'Error loading level $levelId: $e', + name: 'LevelRepository.getLevel', + error: e, + stackTrace: s, + ); + rethrow; + } + } + + @override + Future> getLevels() async { + final data = await _db.collection('levels').get() + as Map>?; + if (data == null) return []; + return data.values.map(LevelData.fromMap).toList(growable: false); + } + + Future deleteLevels() async { + log('Deleting all levels', name: 'LevelRepository.deleteLevels'); + + await HydratedBloc.storage.clear(); + await _db.collection('levels').delete(); } @override Future setLevel(LevelData level) async { + log('Saving level ${level.levelId}', name: 'LevelRepository.setLevel'); final data = level.toMap(); await _db.collection('levels').doc('${level.levelId}').set(data); return true; diff --git a/lib/src/level/domain/i_level_repository.dart b/lib/src/level/domain/i_level_repository.dart index f4932e4..3df6839 100644 --- a/lib/src/level/domain/i_level_repository.dart +++ b/lib/src/level/domain/i_level_repository.dart @@ -4,5 +4,6 @@ import 'package:level_data/level_data.dart'; // load/save leveldata abstract class ILevelRepository { Future getLevel(int id); + Future> getLevels(); Future setLevel(LevelData level); } diff --git a/lib/src/user_stats/application/user_stats_repository.dart b/lib/src/user_stats/application/user_stats_repository.dart index b204e57..daf09ce 100644 --- a/lib/src/user_stats/application/user_stats_repository.dart +++ b/lib/src/user_stats/application/user_stats_repository.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:localstore/localstore.dart'; import 'package:sozzle/core/environment.dart'; import 'package:sozzle/src/game_play/domain/entities/booster.dart'; diff --git a/lib/src/user_stats/domain/user_progress_data.dart b/lib/src/user_stats/domain/user_progress_data.dart index 29af83d..7ceecd7 100644 --- a/lib/src/user_stats/domain/user_progress_data.dart +++ b/lib/src/user_stats/domain/user_progress_data.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:sozzle/src/game_play/domain/entities/booster.dart'; /// Current Users progress data diff --git a/packages/level_data/analysis_options.yaml b/packages/level_data/analysis_options.yaml index dee8927..9df80aa 100644 --- a/packages/level_data/analysis_options.yaml +++ b/packages/level_data/analysis_options.yaml @@ -1,30 +1 @@ -# This file configures the static analysis results for your project (errors, -# warnings, and lints). -# -# This enables the 'recommended' set of lints from `package:lints`. -# This set helps identify many issues that may lead to problems when running -# or consuming Dart code, and enforces writing Dart using a single, idiomatic -# style and format. -# -# If you want a smaller set of lints you can change this to specify -# 'package:lints/core.yaml'. These are just the most critical lints -# (the recommended set includes the core lints). -# The core lints are also what is used by pub.dev for scoring packages. - -include: package:lints/recommended.yaml - -# Uncomment the following section to specify additional rules. - -# linter: -# rules: -# - camel_case_types - -# analyzer: -# exclude: -# - path/to/excluded/files/** - -# For more information about the core and recommended set of lints, see -# https://dart.dev/go/core-lints - -# For additional information about configuring this file, see -# https://dart.dev/guides/language/analysis-options +include: package:very_good_analysis/analysis_options.yaml diff --git a/packages/level_data/example/level_data_example.dart b/packages/level_data/example/level_data_example.dart index 5689cc2..cd79fa1 100644 --- a/packages/level_data/example/level_data_example.dart +++ b/packages/level_data/example/level_data_example.dart @@ -1,32 +1,44 @@ import 'package:level_data/level_data.dart'; void main() { - final reward = RewardCoin( + const reward = RewardCoin( id: 2, - name: "Test Coin", - description: "Test Coin Description", - image: "Test Coin Image", + name: 'Test Coin', + description: 'Test Coin Description', + image: 'Test Coin Image', points: 500, ); - final reward2 = Badge( + const reward2 = Badge( id: 1, - name: "Test Badge", - description: "Test Badge Description", - image: "Test Badge Image", + name: 'Test Badge', + description: 'Test Badge Description', + image: 'Test Badge Image', points: 50, ); - final level = LevelData( + const level = LevelData( levelId: 1, - words: ["SAW", "WASP"], + words: ['SAW', 'WASP'], + crosswords: { + 'SAW': Crossword( + word: 'SAW', + direction: CrossWordDirection.across, + directionIndex: 1, + ), + 'WASP': Crossword( + word: 'WASP', + direction: CrossWordDirection.down, + directionIndex: 1, + ), + }, boardHeight: 5, boardWidth: 5, - boardData: ["W", "S", ""], + boardData: ['W', 'S', ''], rewards: [ reward, reward2, - ] + ], ); print(level); diff --git a/packages/level_data/lib/core/extensions/string_extensions.dart b/packages/level_data/lib/core/extensions/string_extensions.dart new file mode 100644 index 0000000..967dbce --- /dev/null +++ b/packages/level_data/lib/core/extensions/string_extensions.dart @@ -0,0 +1,12 @@ +import 'package:level_data/src/crossword_base.dart'; + +extension StringExtensions on String { + CrossWordDirection toDirection() { + for (final direction in CrossWordDirection.values) { + if (direction.value == toLowerCase()) { + return direction; + } + } + throw Exception('Invalid direction string: $this'); + } +} diff --git a/packages/level_data/lib/level_data.dart b/packages/level_data/lib/level_data.dart index bc09fdd..485e8cb 100644 --- a/packages/level_data/lib/level_data.dart +++ b/packages/level_data/lib/level_data.dart @@ -1,4 +1,6 @@ -library level_data; +/// A library providing base classes for level data, crosswords, and rewards. +library; +export 'src/crossword_base.dart'; export 'src/level_data_base.dart'; export 'src/reward_base.dart'; diff --git a/packages/level_data/lib/src/crossword_base.dart b/packages/level_data/lib/src/crossword_base.dart new file mode 100644 index 0000000..2ef6b7f --- /dev/null +++ b/packages/level_data/lib/src/crossword_base.dart @@ -0,0 +1,77 @@ +import 'package:equatable/equatable.dart'; +import 'package:level_data/core/extensions/string_extensions.dart'; + +/// The direction of the crossword word +enum CrossWordDirection { + /// The word is placed horizontally + across('across'), + + /// The word is placed vertically + down('down'); + + const CrossWordDirection(this.value); + + /// The string value of the direction + final String value; +} + +/// A model representing a crossword word with its properties +class Crossword extends Equatable { + /// Creates a [Crossword] instance + const Crossword({ + required this.word, + required this.direction, + required this.directionIndex, + this.definition, + }); + + /// Creates a [Crossword] instance from a map + factory Crossword.fromMap(Map map) { + return Crossword( + word: map['word'] as String, + definition: map['definition'] as String?, + direction: (map['direction'] as String).toDirection(), + directionIndex: (map['directionIndex'] as num).toInt(), + ); + } + + /// The crossword word + final String word; + + /// The definition of the crossword word + final String? definition; + + /// The direction of the crossword word + final CrossWordDirection direction; + + /// The index of the direction (row or column) + final int directionIndex; + + /// Creates a copy of the current [Crossword] with optional new values + Crossword copyWith({ + String? word, + String? definition, + CrossWordDirection? direction, + int? directionIndex, + }) { + return Crossword( + word: word ?? this.word, + definition: definition ?? this.definition, + direction: direction ?? this.direction, + directionIndex: directionIndex ?? this.directionIndex, + ); + } + + /// Converts the [Crossword] instance to a map + Map toMap() { + return { + 'word': word, + 'definition': definition, + 'direction': direction.value, + 'directionIndex': directionIndex, + }; + } + + @override + List get props => [word, direction, directionIndex, definition]; +} diff --git a/packages/level_data/lib/src/level_data_base.dart b/packages/level_data/lib/src/level_data_base.dart index f6a08f7..0409e63 100644 --- a/packages/level_data/lib/src/level_data_base.dart +++ b/packages/level_data/lib/src/level_data_base.dart @@ -1,44 +1,58 @@ import 'dart:convert'; import 'package:equatable/equatable.dart'; +import 'package:level_data/src/crossword_base.dart'; import 'package:level_data/src/reward_base.dart'; +/// A model representing the data of a level in the game class LevelData extends Equatable { + /// Creates a [LevelData] instance const LevelData({ required this.levelId, required this.words, required this.boardWidth, required this.boardHeight, required this.boardData, + required this.crosswords, this.rewards = const [], }); - LevelData.empty() - : levelId = 0, - words = const [], - boardWidth = 0, - boardHeight = 0, - boardData = const [], - rewards = const []; - + /// Creates an empty [LevelData] instance + const LevelData.empty() + : levelId = 0, + words = const [], + boardWidth = 0, + boardHeight = 0, + boardData = const [], + crosswords = const {}, + rewards = const []; + + /// Creates a [LevelData] instance from a JSON string factory LevelData.fromJson(String json) => LevelData.fromMap(jsonDecode(json) as Map); + /// Creates a [LevelData] instance from a map factory LevelData.fromMap(Map json) => LevelData( - levelId: json['id'] as int, - boardHeight: json['rows'] as int, - boardWidth: json['cols'] as int, - boardData: List.from(json['board'] as List), - words: List.from(json['words'] as List), - rewards: List.from((json['rewards'] as List)).map((e) { - return Reward.fromJson(e); - }).toList(), - ); + levelId: json['id'] as int, + boardHeight: json['rows'] as int, + boardWidth: json['cols'] as int, + boardData: List.from(json['board'] as List), + words: List.from(json['words'] as List), + rewards: List.from(json['rewards'] as List).map((e) { + return Reward.fromJson(e); + }).toList(), + crosswords: (json['crosswords'] as Map).map( + (key, value) => MapEntry( + key, + Crossword.fromMap(value as Map), + ), + ), + ); static const _levelPoint = 50; /// The points gained from this level - static get levelPoint => _levelPoint; + static int get levelPoint => _levelPoint; /// level id final int levelId; @@ -74,30 +88,40 @@ class LevelData extends Equatable { /// The rewards gained from this level final List rewards; - Map toMap() => { - 'id': levelId, - 'board': boardData, - 'words': words, - 'rows': boardHeight, - 'cols': boardWidth, - 'rewards': rewards.map((e) => e.toJson()).toList(), - }; + /// The crosswords in the level + final Map crosswords; + /// Converts the [LevelData] instance to a map + Map toMap() => { + 'id': levelId, + 'board': boardData, + 'words': words, + 'rows': boardHeight, + 'cols': boardWidth, + 'rewards': rewards.map((e) => e.toJson()).toList(), + 'crosswords': crosswords.map( + (key, value) => MapEntry(key, value.toMap()), + ), + }; + + /// Converts the [LevelData] instance to a JSON string String toJson() => json.encode(toMap()); @override List get props => [ - levelId, - words, - boardHeight, - boardWidth, - boardData, - rewards, - ]; + levelId, + words, + boardHeight, + boardWidth, + boardData, + rewards, + crosswords.keys, + ]; @override bool get stringify => true; + /// Creates a copy of the current [LevelData] with optional new values LevelData copyWith({ int? levelId, List? words, @@ -105,6 +129,7 @@ class LevelData extends Equatable { int? boardWidth, List? boardData, List? rewards, + Map? crosswords, }) { return LevelData( levelId: levelId ?? this.levelId, @@ -113,6 +138,7 @@ class LevelData extends Equatable { boardWidth: boardWidth ?? this.boardWidth, boardData: boardData ?? this.boardData, rewards: rewards ?? this.rewards, + crosswords: crosswords ?? this.crosswords, ); } } diff --git a/packages/level_data/lib/src/reward_base.dart b/packages/level_data/lib/src/reward_base.dart index f434be5..524cc5c 100644 --- a/packages/level_data/lib/src/reward_base.dart +++ b/packages/level_data/lib/src/reward_base.dart @@ -2,43 +2,58 @@ import 'dart:convert'; import 'package:equatable/equatable.dart'; +/// A base model representing a reward abstract class Reward extends Equatable { + /// Creates a [Reward] instance const Reward(); + /// Creates a [Reward] instance from a JSON string + factory Reward.fromJson(String source) => + Reward.fromMap(json.decode(source) as Map); + + /// Creates a [Reward] instance from a map + factory Reward.fromMap(Map json) { + switch (json['type'] as String) { + case 'coin': + return RewardCoin.fromMap(json); + case 'badge': + return Badge.fromMap(json); + default: + throw Exception('Unknown reward type'); + } + } + + /// The name of the reward String get name; + /// The type of the reward String get type; + /// The description of the reward String get description; + /// The image of the reward String get image; + /// The points of the reward int get points; + /// The id of the reward int get id; @override List get props => [name, description, image, points, id]; + /// Converts the [Reward] instance to a map Map toMap(); + /// Converts the [Reward] instance to a JSON string String toJson() => json.encode(toMap()); - - factory Reward.fromJson(String source) => Reward.fromMap(json.decode(source)); - - factory Reward.fromMap(Map json) { - switch (json['type'] as String) { - case 'coin': - return RewardCoin.fromMap(json); - case 'badge': - return Badge.fromMap(json); - default: - throw Exception('Unknown reward type'); - } - } } +/// A model representing a coin reward class RewardCoin extends Reward { + /// Creates a [RewardCoin] instance const RewardCoin({ required this.name, required this.description, @@ -47,6 +62,17 @@ class RewardCoin extends Reward { required this.id, }); + /// Creates a [RewardCoin] instance from a map + factory RewardCoin.fromMap(Map map) { + return RewardCoin( + name: map['name'] as String, + description: map['description'] as String, + image: map['image'] as String, + points: map['points'] as int, + id: map['id'] as int, + ); + } + @override final String name; @override @@ -72,9 +98,22 @@ class RewardCoin extends Reward { 'type': type, }; } +} - factory RewardCoin.fromMap(Map map) { - return RewardCoin( +/// A model representing a badge reward +class Badge extends Reward { + /// Creates a [Badge] instance + const Badge({ + required this.name, + required this.description, + required this.image, + required this.points, + required this.id, + }); + + /// Creates a [Badge] instance from a map + factory Badge.fromMap(Map map) { + return Badge( name: map['name'] as String, description: map['description'] as String, image: map['image'] as String, @@ -82,9 +121,7 @@ class RewardCoin extends Reward { id: map['id'] as int, ); } -} -class Badge extends Reward { @override final String name; @override @@ -99,14 +136,6 @@ class Badge extends Reward { @override String get type => 'badge'; - const Badge({ - required this.name, - required this.description, - required this.image, - required this.points, - required this.id, - }); - @override Map toMap() { return { @@ -118,14 +147,4 @@ class Badge extends Reward { 'type': type, }; } - - factory Badge.fromMap(Map map) { - return Badge( - name: map['name'] as String, - description: map['description'] as String, - image: map['image'] as String, - points: map['points'] as int, - id: map['id'] as int, - ); - } } diff --git a/packages/level_data/pubspec.yaml b/packages/level_data/pubspec.yaml index 67595eb..1f71f79 100644 --- a/packages/level_data/pubspec.yaml +++ b/packages/level_data/pubspec.yaml @@ -4,10 +4,11 @@ version: 1.0.0 publish_to: 'none' environment: - sdk: ">=3.1.0 <4.0.0" + sdk: ^3.9.0 dependencies: {equatable: ^2.0.7} dev_dependencies: lints: ^2.0.0 test: ^1.16.0 + very_good_analysis: ^10.0.0 diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/bug_report.md b/packages/level_generator/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..50a4c7b --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug Report +about: Create a report to help us improve +title: "fix: " +labels: bug +--- + +**Description** + +A clear and concise description of what the bug is. + +**Steps To Reproduce** + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected Behavior** + +A clear and concise description of what you expected to happen. + +**Screenshots** + +If applicable, add screenshots to help explain your problem. + +**Additional Context** + +Add any other context about the problem here. diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/build.md b/packages/level_generator/.github/ISSUE_TEMPLATE/build.md new file mode 100644 index 0000000..0cf8e62 --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/build.md @@ -0,0 +1,14 @@ +--- +name: Build System +about: Changes that affect the build system or external dependencies +title: "build: " +labels: build +--- + +**Description** + +Describe what changes need to be done to the build system and why. + +**Requirements** + +- [ ] The build system is passing diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/chore.md b/packages/level_generator/.github/ISSUE_TEMPLATE/chore.md new file mode 100644 index 0000000..498ebfd --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/chore.md @@ -0,0 +1,14 @@ +--- +name: Chore +about: Other changes that don't modify src or test files +title: "chore: " +labels: chore +--- + +**Description** + +Clearly describe what change is needed and why. If this changes code then please use another issue type. + +**Requirements** + +- [ ] No functional changes to the code diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/ci.md b/packages/level_generator/.github/ISSUE_TEMPLATE/ci.md new file mode 100644 index 0000000..fa2dd9e --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/ci.md @@ -0,0 +1,14 @@ +--- +name: Continuous Integration +about: Changes to the CI configuration files and scripts +title: "ci: " +labels: ci +--- + +**Description** + +Describe what changes need to be done to the ci/cd system and why. + +**Requirements** + +- [ ] The ci system is passing diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/config.yml b/packages/level_generator/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..ec4bb38 --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false \ No newline at end of file diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/documentation.md b/packages/level_generator/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 0000000..f494a4d --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,14 @@ +--- +name: Documentation +about: Improve the documentation so all collaborators have a common understanding +title: "docs: " +labels: documentation +--- + +**Description** + +Clearly describe what documentation you are looking to add or improve. + +**Requirements** + +- [ ] Requirements go here diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/feature_request.md b/packages/level_generator/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..ddd2fcc --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,18 @@ +--- +name: Feature Request +about: A new feature to be added to the project +title: "feat: " +labels: feature +--- + +**Description** + +Clearly describe what you are looking to add. The more context the better. + +**Requirements** + +- [ ] Checklist of requirements to be fulfilled + +**Additional Context** + +Add any other context or screenshots about the feature request go here. diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/performance.md b/packages/level_generator/.github/ISSUE_TEMPLATE/performance.md new file mode 100644 index 0000000..699b8d4 --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/performance.md @@ -0,0 +1,14 @@ +--- +name: Performance Update +about: A code change that improves performance +title: "perf: " +labels: performance +--- + +**Description** + +Clearly describe what code needs to be changed and what the performance impact is going to be. Bonus point's if you can tie this directly to user experience. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/refactor.md b/packages/level_generator/.github/ISSUE_TEMPLATE/refactor.md new file mode 100644 index 0000000..1626c57 --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/refactor.md @@ -0,0 +1,14 @@ +--- +name: Refactor +about: A code change that neither fixes a bug nor adds a feature +title: "refactor: " +labels: refactor +--- + +**Description** + +Clearly describe what needs to be refactored and why. Please provide links to related issues (bugs or upcoming features) in order to help prioritize. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/revert.md b/packages/level_generator/.github/ISSUE_TEMPLATE/revert.md new file mode 100644 index 0000000..9d121dc --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/revert.md @@ -0,0 +1,16 @@ +--- +name: Revert Commit +about: Reverts a previous commit +title: "revert: " +labels: revert +--- + +**Description** + +Provide a link to a PR/Commit that you are looking to revert and why. + +**Requirements** + +- [ ] Change has been reverted +- [ ] No change in test coverage has happened +- [ ] A new ticket is created for any follow on work that needs to happen diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/style.md b/packages/level_generator/.github/ISSUE_TEMPLATE/style.md new file mode 100644 index 0000000..02244a7 --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/style.md @@ -0,0 +1,14 @@ +--- +name: Style Changes +about: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc) +title: "style: " +labels: style +--- + +**Description** + +Clearly describe what you are looking to change and why. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/level_generator/.github/ISSUE_TEMPLATE/test.md b/packages/level_generator/.github/ISSUE_TEMPLATE/test.md new file mode 100644 index 0000000..431a7ea --- /dev/null +++ b/packages/level_generator/.github/ISSUE_TEMPLATE/test.md @@ -0,0 +1,14 @@ +--- +name: Test +about: Adding missing tests or correcting existing tests +title: "test: " +labels: test +--- + +**Description** + +List out the tests that need to be added or changed. Please also include any information as to why this was not covered in the past. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/level_generator/.github/PULL_REQUEST_TEMPLATE.md b/packages/level_generator/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..b05836d --- /dev/null +++ b/packages/level_generator/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,28 @@ + + +## Status + +**READY/IN DEVELOPMENT/HOLD** + +## Description + + + +## Type of Change + + + +- [ ] ✨ New feature (non-breaking change which adds functionality) +- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue) +- [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change) +- [ ] 🧹 Code refactor +- [ ] ✅ Build configuration change +- [ ] 📝 Documentation +- [ ] 🗑️ Chore +- [ ] 🧪 Test diff --git a/packages/level_generator/.github/cspell.json b/packages/level_generator/.github/cspell.json new file mode 100644 index 0000000..9a00348 --- /dev/null +++ b/packages/level_generator/.github/cspell.json @@ -0,0 +1,21 @@ +{ + "version": "0.2", + "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", + "dictionaries": ["vgv_allowed", "vgv_forbidden"], + "dictionaryDefinitions": [ + { + "name": "vgv_allowed", + "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/allowed.txt", + "description": "Allowed VGV Spellings" + }, + { + "name": "vgv_forbidden", + "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/forbidden.txt", + "description": "Forbidden VGV Spellings" + } + ], + "useGitignore": true, + "words": [ + "level_generator" + ] +} diff --git a/packages/level_generator/.github/dependabot.yaml b/packages/level_generator/.github/dependabot.yaml new file mode 100644 index 0000000..63b035c --- /dev/null +++ b/packages/level_generator/.github/dependabot.yaml @@ -0,0 +1,11 @@ +version: 2 +enable-beta-ecosystems: true +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "pub" + directory: "/" + schedule: + interval: "daily" diff --git a/packages/level_generator/.github/workflows/main.yaml b/packages/level_generator/.github/workflows/main.yaml new file mode 100644 index 0000000..19b32bd --- /dev/null +++ b/packages/level_generator/.github/workflows/main.yaml @@ -0,0 +1,29 @@ +name: ci + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + semantic_pull_request: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/semantic_pull_request.yml@v1 + + spell-check: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/spell_check.yml@v1 + with: + includes: "**/*.md" + modified_files_only: false + + build: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 + with: + dart_sdk: "3.9.0" + diff --git a/packages/level_generator/.gitignore b/packages/level_generator/.gitignore new file mode 100644 index 0000000..70b21a1 --- /dev/null +++ b/packages/level_generator/.gitignore @@ -0,0 +1,9 @@ +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +pubspec.lock + +*local/ diff --git a/packages/level_generator/README.md b/packages/level_generator/README.md new file mode 100644 index 0000000..1c9dea0 --- /dev/null +++ b/packages/level_generator/README.md @@ -0,0 +1,62 @@ +# Level Generator + +[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] +[![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) +[![License: MIT][license_badge]][license_link] + +The engine that handles level generation logic + +## Installation 💻 + +**❗ In order to start using Level Generator you must have the [Dart SDK][dart_install_link] installed on your machine.** + +Install via `dart pub add`: + +```sh +dart pub add level_generator +``` + +--- + +## Continuous Integration 🤖 + +Level Generator comes with a built-in [GitHub Actions workflow][github_actions_link] powered by [Very Good Workflows][very_good_workflows_link] but you can also add your preferred CI/CD solution. + +Out of the box, on each pull request and push, the CI `formats`, `lints`, and `tests` the code. This ensures the code remains consistent and behaves correctly as you add functionality or make changes. The project uses [Very Good Analysis][very_good_analysis_link] for a strict set of analysis options used by our team. Code coverage is enforced using the [Very Good Workflows][very_good_coverage_link]. + +--- + +## Running Tests 🧪 + +To run all unit tests: + +```sh +dart pub global activate coverage 1.15.0 +dart test --coverage=coverage +dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info +``` + +To view the generated coverage report you can use [lcov](https://github.com/linux-test-project/lcov). + +```sh +# Generate Coverage Report +genhtml coverage/lcov.info -o coverage/ + +# Open Coverage Report +open coverage/index.html +``` + +[dart_install_link]: https://dart.dev/get-dart +[github_actions_link]: https://docs.github.com/en/actions/learn-github-actions +[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license_link]: https://opensource.org/licenses/MIT +[logo_black]: https://raw.githubusercontent.com/VGVentures/very_good_brand/main/styles/README/vgv_logo_black.png#gh-light-mode-only +[logo_white]: https://raw.githubusercontent.com/VGVentures/very_good_brand/main/styles/README/vgv_logo_white.png#gh-dark-mode-only +[mason_link]: https://github.com/felangel/mason +[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg +[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis +[very_good_coverage_link]: https://github.com/marketplace/actions/very-good-coverage +[very_good_ventures_link]: https://verygood.ventures +[very_good_ventures_link_light]: https://verygood.ventures#gh-light-mode-only +[very_good_ventures_link_dark]: https://verygood.ventures#gh-dark-mode-only +[very_good_workflows_link]: https://github.com/VeryGoodOpenSource/very_good_workflows diff --git a/packages/level_generator/analysis_options.yaml b/packages/level_generator/analysis_options.yaml new file mode 100644 index 0000000..9df80aa --- /dev/null +++ b/packages/level_generator/analysis_options.yaml @@ -0,0 +1 @@ +include: package:very_good_analysis/analysis_options.yaml diff --git a/packages/level_generator/assets/words/english.txt b/packages/level_generator/assets/words/english.txt new file mode 100644 index 0000000..da17119 --- /dev/null +++ b/packages/level_generator/assets/words/english.txt @@ -0,0 +1,705 @@ +ACE +ACT +ADD +AGE +AID +AIM +AIR +ALL +AND +ANT +APE +ARC +ARM +ART +ASK +BAD +BAG +BAR +BAT +BAY +BED +BEE +BIG +BIT +BOX +BOY +BUD +BUG +BUS +CAB +CAP +CAR +CAT +COW +CRY +CUP +CUT +DAD +DAY +DEN +DEW +DID +DIG +DIM +DIP +DOG +DOT +DRY +DUG +EAR +EAT +EGG +END +EYE +FAR +FAT +FEW +FIG +FIT +FIX +FLY +FOG +FOR +FOX +FUN +FUR +GAS +GET +GOT +GUM +GUN +HAD +HAM +HAT +HAY +HEN +HER +HID +HIM +HIS +HIT +HOT +HOW +HUG +ICE +INK +JAM +JAR +JET +JOB +JOG +JOY +KEY +KID +LAP +LAW +LAY +LEG +LET +LID +LIE +LIP +LOG +LOT +LOW +MAP +MAT +MAY +MEN +MET +MIX +MOB +MOW +MUD +MUG +NAP +NET +NEW +NIP +NOT +NOW +NUT +OAK +OAR +OAT +ODD +OFF +OIL +OLD +ONE +OWL +OWN +PAD +PAN +PAT +PAW +PAY +PEN +PET +PIE +PIG +PIN +POT +PUP +RAG +RAM +RAN +RAT +RAW +RED +RIB +RID +RIM +RIP +ROD +ROW +RUB +RUG +RUN +SAD +SAG +SAT +SAW +SAY +SEA +SEE +SET +SEW +SHE +SHY +SIN +SIP +SIT +SIX +SKY +SLY +SON +SOW +SPY +SUN +TAB +TAG +TAP +TAR +TAX +TEA +TEN +THE +TIE +TIN +TIP +TOE +TOP +TOY +TRY +TUB +TUG +TWO +USE +VAN +WAR +WAS +WAX +WAY +WET +WHO +WHY +WIG +WIN +WON +YES +YET +YOU +ZIP +ZOO +ABLE +ACID +AGED +ALSO +AREA +ARMY +AWAY +BABY +BACK +BALL +BAND +BANK +BASE +BATH +BEAR +BEAT +BEEN +BEER +BELL +BELT +BEST +BILL +BIRD +BLOW +BLUE +BOAT +BODY +BOMB +BONE +BOOK +BOOM +BORN +BOSS +BOTH +BOWL +BULK +BURN +BUSH +BUSY +CALM +CAME +CAMP +CARD +CARE +CASE +CASH +CAST +CELL +CHAT +CHIP +CITY +CLUB +COAL +COAT +CODE +COLD +COME +COOK +COOL +COPE +COPY +CORE +COST +CREW +CROP +DARK +DATA +DATE +DAWN +DAYS +DEAD +DEAL +DEAN +DEAR +DEBT +DEEP +DENY +DESK +DIAL +DICE +DIED +DIET +DISC +DISK +DOES +DONE +DOOR +DOSE +DOWN +DRAW +DREW +DROP +DRUG +DUAL +DUCK +DULL +DUST +DUTY +EACH +EAST +EASY +EDGE +ELSE +EVEN +EVER +EVIL +EXIT +FACE +FACT +FADE +FAIL +FAIR +FALL +FARM +FAST +FATE +FEAR +FEED +FEEL +FEET +FELL +FELT +FILE +FILL +FILM +FIND +FINE +FIRE +FIRM +FISH +FIVE +FLAG +FLAT +FLOW +FOLK +FOOD +FOOT +FORD +FORM +FORT +FOUR +FREE +FROM +FUEL +FULL +FUND +GAIN +GAME +GATE +GAVE +GEAR +GIFT +GIRL +GIVE +GLAD +GOAL +GOES +GOLD +GOLF +GONE +GOOD +GRAY +GREW +GREY +GROW +GULF +HAIR +HALF +HALL +HAND +HANG +HARD +HARM +HATE +HAVE +HEAD +HEAR +HEAT +HELD +HELL +HELP +HERE +HERO +HIGH +HILL +HIRE +HOLD +HOLE +HOLY +HOME +HOPE +HOST +HOUR +HUGE +HUNG +HUNT +HURT +IDEA +INCH +INTO +IRON +ITEM +JACK +JANE +JEAN +JOHN +JOIN +JUMP +JURY +JUST +KEEN +KEEP +KIND +KING +KNEE +KNEW +KNOW +LACK +LADY +LAID +LAKE +LAND +LANE +LAST +LATE +LEAD +LEFT +LESS +LIFE +LIFT +LIKE +LINE +LINK +LION +LIST +LOAD +LOAN +LOCK +LOGO +LONG +LOOK +LORD +LOSE +LOSS +LOST +LOVE +LUCK +MADE +MAIL +MAIN +MAKE +MALE +MANY +MARK +MASS +MATT +MEAL +MEAN +MEAT +MEET +MENU +MERE +MIKE +MILE +MILK +MILL +MIND +MINE +MISS +MODE +MORE +MOST +MOVE +MUCH +MUST +NAME +NAVY +NEAR +NECK +NEED +NEWS +NEXT +NICE +NICK +NINE +NONE +NOSE +NOTE +OKAY +ONCE +ONLY +ONTO +OPEN +ORAL +OVER +PACE +PACK +PAGE +PAID +PAIN +PAIR +PALM +PANE +PAPA +PARK +PART +PASS +PAST +PATH +PEAK +PICK +PINE +PINK +PIPE +PLAN +PLAY +PLOT +PLUG +PLUS +POLL +POOL +POOR +PORT +POST +PULL +PURE +PUSH +RACE +RAIL +RAIN +RANK +RARE +RATE +READ +REAL +REAR +RELY +RENT +REST +RICE +RICH +RIDE +RING +RISE +RISK +ROAD +ROCK +ROLE +ROLL +ROOF +ROOM +ROOT +ROSE +RULE +RUSH +RUTH +SAFE +SAID +SAKE +SALE +SALT +SAME +SAND +SAVE +SEAT +SEED +SEEK +SEEM +SELF +SELL +SEND +SENT +SEPT +SHIP +SHOP +SHOT +SHOW +SHUT +SICK +SIDE +SIGN +SITE +SIZE +SKIN +SLIP +SLOW +SNOW +SOFT +SOIL +SOLD +SOLE +SOME +SONG +SOON +SORT +SOUL +SPOT +STAR +STAY +STEP +STOP +SUCH +SUIT +SURE +TAKE +TALE +TALK +TALL +TANK +TAPE +TASK +TEAM +TECH +TELL +TENT +TERM +TEST +TEXT +THAN +THAT +THEM +THEN +THEY +THIN +THIS +TIME +TIRE +TONE +TOOK +TOOL +TOUR +TOWN +TREE +TRIP +TRUE +TUNE +TURN +TWIN +TYPE +UNIT +UPON +USED +USER +VARY +VAST +VERY +VIEW +VOTE +WAGE +WAIT +WAKE +WALK +WALL +WANT +WARD +WARM +WASH +WAVE +WAYS +WEAK +WEAR +WEEK +WELL +WENT +WERE +WEST +WHAT +WHEN +WHOM +WIDE +WIFE +WILD +WILL +WIND +WINE +WING +WIRE +WISE +WISH +WITH +WOOD +WORD +WORE +WORK +YARD +YEAH +YEAR +YOUR +ZERO +ZONE \ No newline at end of file diff --git a/packages/level_generator/assets/words/wordlist.txt b/packages/level_generator/assets/words/wordlist.txt new file mode 100644 index 0000000..d81e2a6 --- /dev/null +++ b/packages/level_generator/assets/words/wordlist.txt @@ -0,0 +1,1529 @@ +ABANDON +ABLE +ABOUT +ABOVE +ABROAD +ABSENCE +ABSENT +ABSORB +ABUSE +ACCENT +ACCEPT +ACCESS +ACCUSE +ACHIEVE +ACID +ACROSS +ACT +ACTION +ACTIVE +ACTOR +ACTRESS +ACTUAL +ADAPT +ADD +ADDRESS +ADMIRE +ADMIT +ADOPT +ADULT +AFFAIR +AFRAID +AFTER +AGAIN +AGAINST +AGE +AGED +AGENT +AGO +AGREE +AHEAD +AID +AIM +AIR +ALARM +ALARMED +ALIVE +ALL +ALLOW +ALLY +ALMOST +ALONE +ALONG +ALOUD +ALREADY +ALSO +ALTER +ALWAYS +AMAZE +AMAZED +AMONG +AMOUNT +AMUSE +AMUSED +ANCIENT +AND +ANGER +ANGLE +ANGRY +ANIMAL +ANKLE +ANNOY +ANNUAL +ANOTHER +ANSWER +ANY +ANYONE +APART +APPEAL +APPEAR +APPLE +APPLY +APRIL +AREA +ARGUE +ARISE +ARM +ARMED +ARMS +ARMY +AROUND +ARRANGE +ARREST +ARRIVAL +ARRIVE +ARROW +ART +ARTICLE +ARTIST +ASHAMED +ASIDE +ASK +ASLEEP +ASPECT +ASSIST +ASSUME +ASSURE +ATOM +ATTACH +ATTACK +ATTEMPT +ATTEND +ATTRACT +AUNT +AUTHOR +AVERAGE +AVOID +AWAKE +AWARD +AWARE +AWAY +AWFUL +AWKWARD +BABY +BACK +BAD +BAG +BAKE +BALL +BAN +BAND +BANK +BAR +BASE +BASED +BASIC +BASIC +BASIS +BATH +BATTLE +BAY +BEACH +BEAK +BEAR +BEARD +BEAT +BED +BEEF +BEER +BEFORE +BEGIN +BELL +BELOW +BELT +BEND +BENT +BEST +BET +BIG +BIKE +BILL +BIN +BIRD +BIRTH +BIT +BITE +BLADE +BLAME +BLIND +BLOOD +BLOW +BLUE +BOARD +BOAT +BODY +BOIL +BOMB +BONE +BOOK +BOOT +BORE +BORED +BORN +BOSS +BOTH +BOWL +BOX +BOY +BRAIN +BRAND +BRAVE +BREAD +BREAK +BREAST +BREED +BRIEF +BRING +BROAD +BURN +BURNT +BURST +BURY +BUS +BUSH +BUSY +BUT +BUY +BYE +CABINET +CABLE +CAKE +CALL +CALM +CAMERA +CAMP +CAP +CAR +CARD +CARE +CAREER +CARPET +CARROT +CASE +CASH +CAST +CASTLE +CAT +CATCH +CAUSE +CEASE +CELL +CENT +CENTRAL +CHAIN +CHAIR +CHARGE +CHART +CHASE +CHAT +CHEAP +CHEAT +CHEEK +CHEESE +CHEST +CHEW +CHIEF +CHILD +CHIN +CHIP +CHOOSE +CHOP +CINEMA +CIRCLE +CITY +CIVIL +CLAIM +CLAP +CLASS +CLASSIC +CLEAN +CLEAR +CLERK +CLIENT +CLIMB +CLOSET +CLOTH +CLOUD +CLUB +COACH +COAL +COAST +COAT +CODE +COIN +COLD +COME +COOK +COOL +COPE +COPY +CORE +COST +COULD +COUNT +COURT +COVER +COW +CRAFT +CRASH +CRAZY +CREAM +CREATE +CREDIT +CRIME +CRISP +CROP +CROSS +CROWD +CROWN +CRUEL +CRUSH +CRUSH +CRY +CUP +CURB +CURE +CURL +CUT +CYCLE +DAD +DAILY +DAMAGE +DAMP +DANCE +DARE +DARK +DATA +DATE +DAY +DEAD +DEAF +DEAL +DEAR +DEATH +DEBATE +DEBT +DECADE +DECAY +DECLARE +DEEP +DEGREE +DELAY +DELIVER +DENY +DEPEND +DEPTH +DESERT +DESIRE +DESK +DIARY +DIE +DIET +DIG +DIRT +DIRTY +DISC +DISH +DISK +DOCTOR +DOG +DOLLAR +DOOR +DOT +DOUBLE +DOUBT +DOWN +DOZEN +DRAFT +DRAG +DRAMA +DRAW +DRAWER +DREAM +DRESS +DRINK +DRIVE +DROP +DRUG +DRUM +DRY +DUE +DULL +DUMP +DUST +DUTY +DVD +EACH +EAR +EARLY +EARN +EARTH +EASE +EAST +EASTERN +EASY +EAT +EDGE +EDITION +EDITOR +EDUCATE +EFFORT +EGG +EIGHT +EITHER +ELBOW +ELECT +ELECTRIC +ELEGANT +ELEMENT +ELEVATOR +ELEVEN +ELSE +EMAIL +EMAIL +EMERGE +EMOTION +EMPIRE +EMPTY +ENABLE +END +ENEMY +ENERGY +ENGAGE +ENGINE +ENGINEER +ENJOY +ENOUGH +ENSURE +ENTER +ENTIRE +ENTITLE +ENTRY +EQUAL +ERROR +ESCAPE +ESSAY +ESTATE +ESTIMATE +EURO +EVEN +EVENT +EVER +EVERY +EVIL +EXACT +EXAM +EXIST +EXIT +EXPERT +EXTENT +EXTRA +EXTRA +EYE +FACE +FACT +FAIL +FAINT +FAIR +FAITH +FALL +FALSE +FAME +FAN +FANCY +FAR +FARM +FAST +FAT +FAULT +FEAR +FEDERAL +FEE +FEED +FEEL +FEMALE +FENCE +FETCH +FEVER +FEW +FIELD +FIFTH +FILE +FILL +FILM +FINAL +FIND +FINE +FIRE +FIRM +FIRST +FISH +FIT +FIVE +FIX +FLAG +FLAME +FLASH +FLAT +FLESH +FLOAT +FLOOD +FLOOR +FLOUR +FLOW +FLU +FLY +FOCUS +FOLD +FOOD +FOOT +FOR +FORCE +FOREST +FORK +FORM +FOUR +FRAME +FREE +FRESH +FROM +FRONT +FRUIT +FRY +FUEL +FULL +FUN +FUND +FUR +GAIN +GAME +GAP +GARAGE +GAS +GATE +GEAR +GENERAL +GENTLE +GET +GIANT +GIFT +GIRL +GIVE +GLAD +GLASS +GLOVE +GLUE +GOAL +GOD +GOLD +GOOD +GOODS +GRAB +GRADE +GRAIN +GRAM +GRAND +GRANT +GRASS +GREAT +GREEN +GREY +GROUP +GROW +GUARD +GUESS +GUEST +GUIDE +GUN +GUY +HABIT +HAIR +HALF +HALL +HAND +HANG +HAPPY +HARD +HARM +HAT +HATE +HATRED +HAVE +HEAD +HEADACHE +HEAL +HEAR +HEART +HEAT +HEEL +HELL +HELLO +HELP +HENCE +HER +HERE +HERO +HERS +HIDE +HIGH +HILL +HIM +HIP +HIRE +HIS +HIT +HOLD +HOLE +HOLY +HOME +HONEST +HOOK +HOPE +HORN +HORSE +HOST +HOT +HOTEL +HOUR +HOUSE +HOW +HUGE +HUMAN +HUNT +HURT +ICE +IDEA +IDEAL +IGNORE +ILL +ILLEGAL +IMAGE +IMAGINE +INCH +INCOME +INDEED +INDEX +INDOOR +INDOORS +INITIAL +INK +INNER +INSECT +INSERT +INSIDE +INSIST +INSTEAD +INTEND +INTEREST +INTO +IRON +ISLAND +ISSUE +ITEM +ITS +ITSELF +JAM +JEANS +JOB +JOIN +JOKE +JOY +JUDGE +JUICE +JUMP +JUNE +JUST +KEEN +KEEP +KEY +KICK +KID +KILL +KIND +KING +KISS +KNEE +KNIFE +KNIT +KNOT +KNOW +LAB +LABEL +LACK +LADY +LAKE +LAMP +LAND +LANE +LARGE +LATE +LATER +LATEST +LAW +LAWYER +LAY +LAYER +LAZY +LEADER +LEAF +LEAGUE +LEAN +LEARN +LEAST +LEATHER +LEAVE +LEFT +LEG +LEGAL +LEMON +LEND +LENGTH +LESS +LESSON +LET +LETTER +LEVEL +LICENSE +LID +LIFE +LIFT +LIGHT +LIKE +LIMIT +LINE +LINK +LIP +LIST +LISTEN +LITRE +LITTLE +LOAD +LOAN +LOCAL +LOCATE +LOCK +LOGIC +LONG +LOOK +LOOSE +LORD +LOSE +LOSS +LOST +LOT +LOUD +LOVE +LOVER +LOW +LOYAL +LUCK +LUMP +LUNG +MAD +MAGIC +MAIL +MAIN +MAJOR +MAKE +MALE +MALL +MAN +MANAGE +MANY +MAP +MARCH +MARK +MASS +MASTER +MATCH +MATE +MAY +MAYBE +MAYOR +MEAL +MEAN +MEANS +MEAT +MEDIA +MEET +MELT +MENTAL +MENU +MERE +MESS +METAL +METHOD +METRE +MILD +MILE +MILK +MIND +MINE +MINERAL +MINOR +MIRROR +MISS +MIX +MOBILE +MODEL +MODERN +MOM +MOMENT +MONEY +MONTH +MOOD +MOON +MORAL +MORE +MOST +MOTOR +MOUNT +MOUSE +MOUTH +MOVE +MOVIE +MRS +MUCH +MUD +MUM +MUSIC +MUST +NAIL +NAKED +NAME +NAME +NARROW +NATURAL +NATURE +NAVY +NEAR +NEARBY +NEAT +NECK +NEED +NEEDLE +NERVE +NEST +NET +NEVER +NEW +NEWS +NEXT +NICE +NIECE +NIGHT +NINE +NINETY +NINTH +NOISE +NOISY +NONE +NONSENSE +NOR +NORMAL +NORTH +NOSE +NOT +NOTE +NOTICE +NOVEL +NOW +NURSE +NUT +OBEY +OBSERVE +OBTAIN +OCCUR +OCEAN +ODD +ODDLY +OFF +OFFER +OFTEN +OIL +OLD +ONCE +ONE +ONION +ONLINE +ONLY +ONTO +OPEN +OPERATE +OPINION +OPPOSE +ORANGE +ORDER +ORGAN +ORIGIN +ORIGINAL +OTHER +OUR +OURS +OUT +OUTER +OVEN +OVER +OWE +OWN +OWNER +PACK +PAGE +PAIN +PAINT +PAIR +PALACE +PALE +PANEL +PANTS +PAPER +PARENT +PARK +PART +PARTNER +PARTY +PASS +PAST +PATH +PAUSE +PAY +PEACE +PEAK +PEN +PENCIL +PENNY +PEOPLE +PER +PERSON +PET +PHASE +PHONE +PHOTO +PHRASE +PIANO +PICK +PIECE +PIG +PILE +PILL +PILOT +PIN +PINK +PINT +PIPE +PITCH +PITY +PLACE +PLAIN +PLAN +PLANE +PLANET +PLANT +PLATE +PLAY +PLEASE +PLOT +PLUG +POEM +POINT +POLE +POLICE +POLITE +POOL +POOR +POP +PORT +POSE +POSSESS +POST +POT +POTATO +POUND +POUR +POWER +PRAISE +PRAY +PRAYER +PREFER +PREPARE +PRESENT +PRESS +PRETTY +PRICE +PRIDE +PRIEST +PRINT +PRIOR +PRIZE +PROOF +PROPOSE +PROUD +PROVE +PUB +PULL +PUPIL +PURE +PUSH +PUT +QUEEN +QUIET +QUIT +QUITE +QUOTE +RACE +RADIO +RAIL +RAIN +RAISE +RANGE +RANK +RAPID +RARE +RATE +RAW +REACH +REACT +READ +READER +READY +REAL +REAR +REASON +RECALL +RECENT +RECORD +RED +REFER +REGRET +RELATE +RELATED +RELAX +RELEASE +RELIEF +RELY +REMARK +REMOTE +REMOVE +RENT +REPAIR +REPEAT +REPLY +REPORT +RESCUE +RESEARCH +RESIST +RESORT +RESPECT +RESPONSE +REST +RESTORE +RESULT +RETAIN +RETIRE +REVEAL +REVERSE +REWARD +RICE +RICH +RID +RIDE +RIDER +RIGHT +RISE +RISK +RIVAL +RIVER +ROAD +ROB +ROCK +ROLE +ROLL +ROOF +ROOM +ROOT +ROPE +ROUGH +ROUND +ROUTE +ROUTINE +ROYAL +RUB +RUDE +RUIN +RULE +RULER +RUN +RURAL +RUSH +SACK +SAD +SADLY +SADNESS +SAFE +SAFETY +SAIL +SAILOR +SALAD +SALARY +SALE +SALT +SALT +SALTY +SALTY +SAME +SAMPLE +SAND +SAUCE +SAVE +SAY +SCALE +SCARE +SCARED +SCENE +SCHEME +SCHOOL +SCIENCE +SCORE +SCREAM +SCREEN +SCREW +SEA +SEAL +SEARCH +SEASON +SEAT +SECRET +SECURE +SEE +SEED +SEEK +SEEM +SELECT +SELF +SELL +SENATE +SENATOR +SEND +SENIOR +SENSE +SENTENCE +SEPARATE +SERIES +SERVE +SESSION +SET +SETTLE +SEVEN +SEVERE +SEW +SEX +SHADE +SHADOW +SHAKE +SHALL +SHAME +SHAPE +SHARE +SHARP +SHAVE +SHE +SHEEP +SHEET +SHELF +SHELL +SHELTER +SHIFT +SHINE +SHIP +SHIRT +SHOE +SHOOT +SHOP +SHORT +SHOT +SHOUT +SHOW +SHUT +SHY +SICK +SIDE +SIGHT +SIGN +SIGNAL +SILENCE +SILENT +SILK +SILLY +SIMILAR +SINCE +SINCERE +SING +SINK +SIR +SISTER +SIT +SITE +SIX +SIZE +SKILL +SKIN +SKIRT +SKY +SLEEP +SLEEVE +SLICE +SLIDE +SLIP +SLOPE +SLOW +SMALL +SMART +SMASH +SMELL +SMILE +SMOKE +SMOOTH +SNAKE +SNOW +SOAP +SOCIAL +SOCK +SOFT +SOIL +SOLID +SOLVE +SOME +SOMEONE +SON +SONG +SOON +SORE +SORRY +SORT +SOUL +SOUND +SOUP +SOUR +SOURCE +SOUTH +SPACE +SPARE +SPEAK +SPEECH +SPEED +SPELL +SPEND +SPICE +SPIDER +SPIN +SPIRIT +SPITE +SPLIT +SPOIL +SPOON +SPORT +SPOT +SPRAY +SPREAD +STABLE +STAFF +STAGE +STAIR +STAMP +STAND +STAND +STAR +STAR +STARE +START +STATE +STATUE +STATUS +STAY +STEADY +STEAL +STEAM +STEEL +STEEP +STEER +STEP +STICK +STIFF +STILL +STING +STIR +STOCK +STONE +STOP +STORE +STORM +STORY +STOVE +STRAIN +STRANGE +STREAM +STREET +STRESS +STRESSED +STRETCH +STRICT +STRIKE +STRING +STRIP +STRIPE +STROKE +STRONG +STUDENT +STUDIO +STUDY +STUFF +STYLE +SUCH +SUGAR +SUIT +SUM +SUN +SURE +SWEAR +SWEAT +SWEATER +SWEEP +SWEET +SWELL +SWIM +SWING +SYSTEM +TABLE +TABLET +TAIL +TAKE +TALK +TALL +TANK +TAP +TAPE +TARGET +TASK +TASTE +TAX +TAXI +TEA +TEACH +TEAM +TELL +TEN +TEND +TENT +TENTH +TERM +TEST +TEXT +THAN +THANK +THANKS +THAT +THE +THEIR +THEIRS +THEM +THEME +THEN +THERE +THEY +THIEF +THIN +THING +THINK +THIRD +THIRSTY +THIS +THREAD +THREATEN +THREE +THROW +THUMB +THUS +TIDY +TIE +TIGHT +TILL +TIME +TIN +TINY +TIP +TIRE +TIRED +TITLE +TODAY +TOE +TOMATO +TOMORROW +TON +TONE +TONNE +TOO +TOOL +TOOTH +TOP +TOPIC +TOTAL +TOUR +TOWEL +TOWER +TOWN +TOY +TRACE +TRACK +TRADE +TRAIN +TRAP +TRAVEL +TREAT +TREE +TREND +TRIAL +TRIANGLE +TRICK +TRIP +TRUCK +TRUE +TRULY +TRUST +TRUTH +TRY +TUBE +TUNE +TURN +TWICE +TWIN +TWIST +TWO +TYPE +TYRE +UGLY +UNABLE +UNCLE +UNDER +UNDO +UNION +UNIT +UNITE +UNITED +UNLESS +UNTIL +UPON +UPPER +UPSET +URBAN +URGE +URGENT +USE +USELESS +USER +USUAL +VALID +VALUE +VAN +VARY +VAST +VERY +VIA +VIDEO +VIEW +VIRUS +VISIT +VITAL +VOICE +VOTE +WAGE +WAIST +WAIT +WAKE +WALK +WALL +WANT +WAR +WARM +WARN +WASH +WASTE +WATCH +WATER +WAVE +WAY +WEAK +WEAR +WEB +WEEK +WEIGH +WELL +WEST +WET +WHAT +WHEEL +WHEN +WHERE +WHITE +WHO +WHOLE +WHOM +WHOSE +WHY +WIDE +WIDTH +WIFE +WILD +WILL +WIN +WINE +WING +WIRE +WISE +WISH +WITH +WOMAN +WOOD +WOOL +WORD +WORK +WORLD +WORRY +WORSE +WORST +WRAP +WRIST +WRITE +WRONG +YARD +YAWN +YEAH +YEAR +YES +YET +YOU +YOUNG +YOUR +YOURS +YOUTH +ZERO +ZONE diff --git a/packages/level_generator/coverage_badge.svg b/packages/level_generator/coverage_badge.svg new file mode 100644 index 0000000..499e98c --- /dev/null +++ b/packages/level_generator/coverage_badge.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + coverage + coverage + 100% + 100% + + diff --git a/packages/level_generator/lib/level_generator.dart b/packages/level_generator/lib/level_generator.dart new file mode 100644 index 0000000..8392c06 --- /dev/null +++ b/packages/level_generator/lib/level_generator.dart @@ -0,0 +1,7 @@ +/// The engine that handles level generation logic +library; + +export 'src/app/crossword_generator_compact.dart'; +export 'src/app/level_generator.dart'; +export 'src/app/word_list_service.dart'; +export 'src/services/defintion_fetcher.dart'; diff --git a/packages/level_generator/lib/src/app/crossword_generator.dart b/packages/level_generator/lib/src/app/crossword_generator.dart new file mode 100644 index 0000000..7fe853d --- /dev/null +++ b/packages/level_generator/lib/src/app/crossword_generator.dart @@ -0,0 +1,413 @@ +import 'dart:developer' as dev; +import 'dart:math'; + +import 'package:equatable/equatable.dart'; + +// ###################################################################### +// # Public-Facing Data Structure for the Result +// ###################################################################### + +/// A class to hold the final generated crossword grid. +/// It contains the 2D grid data, width, and height. +class CrosswordGrid { + /// A class to hold the final generated crossword grid. + /// It contains the 2D grid data, width, and height. + const CrosswordGrid({ + required this.gridData, + required this.width, + required this.height, + }); + + /// The 2D representation of the grid, e.g., + /// [ + /// ['W', '', 'S', 'A', 'W'], + /// ['A', '', 'W', '', ''], + /// ... + /// ] + final List> gridData; + + /// The final width of the grid. + final int width; + + /// The final height of the grid. + final int height; + + /// A helper function to print the grid to the console for debugging. + void printGrid() { + dev.log( + 'Grid Dimensions: ${width}w x ${height}h', + name: 'CrosswordGrid.printGrid', + ); + for (final row in gridData) { + // Join cells, replacing empty strings with a dot for readability. + final rowString = row.map((cell) => cell.isEmpty ? '.' : cell).join(' '); + dev.log(rowString, name: 'CrosswordGrid.printGrid'); + } + } + + /// Flattens the 2D [gridData] into the 1D [boardData] format + /// your game expects. + List get flattenedBoardData { + final flatList = []; + gridData.forEach(flatList.addAll); + return flatList; + } +} + +// ###################################################################### +// # The Crossword Generator +// ###################################################################### + +/// Main class that orchestrates the crossword generation. +/// It uses a recursive backtracking algorithm. +class CrosswordGenerator { + /// Generates a crossword grid from a list of words. + /// Returns a [CrosswordGrid] object if a solution is found, + /// otherwise returns null. + @Deprecated( + 'Use the compact version of the crossword generator instead. It' + ' is more complete and robust.', + ) + const CrosswordGenerator({this.shuffle = true}); + + /// Whether to shuffle placements to get different layouts + final bool shuffle; + + /// Generates the crossword grid. + /// [words]: The list of words to place on the grid. + /// + /// Returns a [CrosswordGrid] if successful, or `null` if + /// no valid arrangement could be found. + CrosswordGrid? generate(List words) { + // 1. Sort words from longest to shortest. This is a common + // heuristic to make generation more likely to succeed, + // as it places the most "difficult" words first. + final sortedWords = List.from(words) + ..sort((a, b) => b.length.compareTo(a.length)); + + // 2. Start with an empty grid and place the first (longest) word. + final grid = _Grid(); + final firstWord = sortedWords.first; + final remainingWords = sortedWords.sublist(1); + + // Place the first word horizontally at (0, 0) + grid.placeWord( + firstWord, + _Placement(word: firstWord, x: 0, y: 0, isHorizontal: true), + ); + + // 3. Start the recursive backtracking algorithm + final solvedGrid = _solve(grid, remainingWords); + + // 4. If a solution was found, normalize it into the final + // CrosswordGrid format. + if (solvedGrid != null) { + return _normalizeGrid(solvedGrid); + } + + // 5. No solution found + return null; + } + + /// The core recursive backtracking function. + /// + /// [grid]: The current state of the grid. + /// [wordsToPlace]: The list of words we still need to place. + /// + /// Returns a solved [_Grid] if successful, or `null` if this + /// branch is a dead end. + _Grid? _solve(_Grid grid, List wordsToPlace) { + // BASE CASE: If there are no more words to place, we are done! + if (wordsToPlace.isEmpty) { + return grid; + } + + // RECURSIVE STEP: + final word = wordsToPlace.first; + final remainingWords = wordsToPlace.sublist(1); + + // 1. Find all possible valid placements for the current word. + final placements = _findAllValidPlacements(grid, word); + + // Optional: Shuffle placements to get different grid layouts + // on different runs. + if (shuffle) { + placements.shuffle(); + } + + // 2. Try each placement one by one. + for (final placement in placements) { + // 2a. "Commit" the placement to a *new* grid. + final newGrid = grid.copy()..placeWord(word, placement); + + // 2b. Recursively try to solve for the *rest* of the words. + final solution = _solve(newGrid, remainingWords); + + // 2c. If the recursive call found a solution, pass it up. + if (solution != null) { + return solution; + } + + // 2d. If not, this placement was a dead end. The loop will + // continue to the next placement (i.e., we "backtracked"). + } + + // 3. If we tried all placements and none worked, this branch fails. + return null; + } + + /// Finds all possible valid placements for a new [word] on the + /// existing [grid]. + List<_Placement> _findAllValidPlacements(_Grid grid, String word) { + final validPlacements = <_Placement>[]; + + // Iterate through every word *already on the grid* + for (final placedWord in grid.placedWords) { + final isHorizontal = placedWord.isHorizontal; + final newWordIsHorizontal = !isHorizontal; + + // Iterate through each letter of the new word + for (var i = 0; i < word.length; i++) { + final newWordChar = word[i]; + + // Iterate through each letter of the existing word + for (var j = 0; j < placedWord.word.length; j++) { + final placedWordChar = placedWord.word[j]; + + // Check for an intersection (matching character) + if (newWordChar == placedWordChar) { + // We found a potential intersection! + // Now calculate the (x, y) starting position + // for the new word. + int newX; + int newY; + if (newWordIsHorizontal) { + // New word is horizontal, old word is vertical + newX = placedWord.x - i; + newY = placedWord.y + j; + } else { + // New word is vertical, old word is horizontal + newX = placedWord.x + j; + newY = placedWord.y - i; + } + + final placement = _Placement( + word: word, + x: newX, + y: newY, + isHorizontal: newWordIsHorizontal, + ); + + // Check if this placement is *actually* valid + // (i.e., doesn't collide or create bad words) + if (_isValidPlacement(grid, placement)) { + validPlacements.add(placement); + } + } + } + } + } + return validPlacements; + } + + /// This is the most complex logic. + /// Checks if a [placement] is valid on the [grid]. + /// + /// A placement is valid if: + /// 1. It doesn't collide with existing letters (unless + /// it's an intersection point). + /// 2. It doesn't create new "accidental" words by + /// running parallel to an existing word. + /// 3. The cells before the start and after the end are empty. + bool _isValidPlacement(_Grid grid, _Placement placement) { + final word = placement.word; + + // We must intersect with at least one word. + // (This check is implicitly handled by _findAllValidPlacements, + // but we can add a counter if we want to be explicit) + var intersections = 0; + + for (var k = 0; k < word.length; k++) { + final letter = word[k]; + final coord = placement.getCoordinate(k); + + final cell = grid.cells[coord]; + + if (cell != null) { + // Cell is NOT empty + if (cell != letter) { + // 1. COLLISION: Cell has a *different* letter. Invalid. + return false; + } else { + // 1b. INTERSECTION: Cell has the *same* letter. This is + // our intersection point. This is fine. + intersections++; + } + } else { + // Cell IS empty. + // 2. ADJACENCY CHECK: Check for "accidental" parallel words. + _Coordinate adjacent1; + _Coordinate adjacent2; + if (placement.isHorizontal) { + // Check cells above (y-1) and below (y+1) + adjacent1 = coord.copy(y: coord.y - 1); + adjacent2 = coord.copy(y: coord.y + 1); + } else { + // Check cells left (x-1) and right (x+1) + adjacent1 = coord.copy(x: coord.x - 1); + adjacent2 = coord.copy(x: coord.x + 1); + } + + if (grid.cells.containsKey(adjacent1) || + grid.cells.containsKey(adjacent2)) { + // This empty cell is adjacent to another word it's + // not intersecting with. This is invalid. + return false; + } + } + } + + // 3. END-CAP CHECK: Check before the start and after the end + // of the word. These cells MUST be empty. + _Coordinate before; + _Coordinate after; + if (placement.isHorizontal) { + before = _Coordinate(x: placement.x - 1, y: placement.y); + after = _Coordinate(x: placement.x + word.length, y: placement.y); + } else { + before = _Coordinate(x: placement.x, y: placement.y - 1); + after = _Coordinate(x: placement.x, y: placement.y + word.length); + } + + if (grid.cells.containsKey(before) || grid.cells.containsKey(after)) { + return false; + } + + // If we've passed all checks, it's a valid placement. + return true; + } + + /// Converts the internal [_Grid] (sparse map) into the + /// final [CrosswordGrid] (dense 2D list). + CrosswordGrid _normalizeGrid(_Grid grid) { + if (grid.cells.isEmpty) { + return const CrosswordGrid(gridData: [], width: 0, height: 0); + } + + // 1. Find the bounds of the sparse grid. + var minX = 0; + var maxX = 0; + var minY = 0; + var maxY = 0; + for (final coord in grid.cells.keys) { + minX = min(minX, coord.x); + maxX = max(maxX, coord.x); + minY = min(minY, coord.y); + maxY = max(maxY, coord.y); + } + + // 2. Calculate final width and height + final width = maxX - minX + 1; + final height = maxY - minY + 1; + + // 3. Create the 2D "dense" list, filled with empty strings. + final denseGrid = List>.generate( + height, + (_) => List.filled(width, ''), + ); + + // 4. Copy data from the sparse grid to the dense grid, + // normalizing coordinates. + for (final entry in grid.cells.entries) { + final coord = entry.key; + final letter = entry.value; + + // Normalize coordinates + final row = coord.y - minY; + final col = coord.x - minX; + + denseGrid[row][col] = letter; + } + + return CrosswordGrid(gridData: denseGrid, width: width, height: height); + } +} + +// ###################################################################### +// # Internal Helper Classes +// ###################################################################### + +/// Represents a 2D coordinate. +/// Using a class makes it usable as a Map key. +class _Coordinate extends Equatable { + const _Coordinate({required this.x, required this.y}); + + final int x; + final int y; + + _Coordinate copy({int? x, int? y}) => + _Coordinate(x: x ?? this.x, y: y ?? this.y); + + @override + String toString() => '($x, $y)'; + + @override + List get props => [x, y]; +} + +/// Represents a word placed on the grid. +class _Placement { + _Placement({ + required this.word, + required this.x, + required this.y, + required this.isHorizontal, + }); + + final String word; + + /// Starting x coordinate + final int x; + + /// Starting y coordinate + final int y; + final bool isHorizontal; + + /// Gets the coordinate for the k-th letter of the word. + _Coordinate getCoordinate(int k) { + return isHorizontal + ? _Coordinate(x: x + k, y: y) + : _Coordinate(x: x, y: y + k); + } +} + +/// Internal representation of the grid. +/// Uses a "sparse" map of Coordinates to letters, so it +/// can grow infinitely in any direction. +class _Grid { + // A map of coordinates to the letter at that spot + final Map<_Coordinate, String> cells = {}; + + // A list of all words placed so far + final List<_Placement> placedWords = []; + + /// Creates a deep copy of the grid. + /// This is crucial for backtracking. + _Grid copy() { + final newGrid = _Grid(); + newGrid.cells.addAll(cells); + newGrid.placedWords.addAll(placedWords); + return newGrid; + } + + /// "Commits" a word to the grid by adding its letters + /// to the [cells] map and adding the [placement] to + /// the [placedWords] list. + void placeWord(String word, _Placement placement) { + placedWords.add(placement); + for (var k = 0; k < word.length; k++) { + final coord = placement.getCoordinate(k); + cells[coord] = word[k]; + } + } +} diff --git a/packages/level_generator/lib/src/app/crossword_generator_compact.dart b/packages/level_generator/lib/src/app/crossword_generator_compact.dart new file mode 100644 index 0000000..35db168 --- /dev/null +++ b/packages/level_generator/lib/src/app/crossword_generator_compact.dart @@ -0,0 +1,442 @@ +import 'dart:math'; + +import 'package:equatable/equatable.dart'; +import 'package:level_generator/src/models/crossword_grid.dart'; +import 'package:level_generator/src/models/word_placement.dart'; + +/// Main class that orchestrates the crossword generation. +/// It uses a recursive backtracking algorithm. +class CrosswordGenerator { + /// Stores the best grid found so far during the search. + _Grid? _bestSolution; + + /// Stores the area of the best grid found so far. + /// -1 indicates no solution has been found yet. + int _minArea = -1; + + /// Generates a crossword grid from a list of words. + /// Returns a [CrosswordGrid] object if a solution is found, + /// otherwise returns null. + CrosswordGrid? generate(List words) { + // 0. Reset state for a new generation + _bestSolution = null; + _minArea = -1; + + // 1. Sort words from longest to shortest. This is a common + // heuristic to make generation more likely to succeed, + // as it places the most "difficult" words first. + final sortedWords = List.from(words) + ..sort((a, b) => b.length.compareTo(a.length)); + + // 2. Start with an empty grid and place the first (longest) word. + // We must try starting both horizontally AND vertically to find + // the true most compact solution. + final firstWord = sortedWords.first; + final remainingWords = sortedWords.sublist(1); + + // --- Try 1: Start with the first word placed horizontally --- + final gridH = _Grid() + ..placeWord( + firstWord, + _Placement(word: firstWord, x: 0, y: 0, isHorizontal: true), + ); + // 3. Start the recursive backtracking algorithm + _solve(gridH, remainingWords); + + // --- Try 2: Start with the first word placed vertically --- + final gridV = _Grid() + ..placeWord( + firstWord, + _Placement(word: firstWord, x: 0, y: 0, isHorizontal: false), + ); + // 3. Start the recursive backtracking algorithm again + _solve(gridV, remainingWords); + + // 4. After all searches are complete, _bestSolution holds the + // most compact grid found. Normalize it. + if (_bestSolution != null) { + return _normalizeGrid(_bestSolution!); + } + + // 5. No solution found + return null; + } + + /// The core recursive backtracking function. + /// + /// [grid]: The current state of the grid. + /// [wordsToPlace]: The list of words we still need to place. + /// + /// This function now has a `void` return. It explores all valid + /// solution paths and updates the class members `_bestSolution` + /// and `_minArea` when a new, better solution is found. + void _solve(_Grid grid, List wordsToPlace) { + // BASE CASE: If there are no more words to place, we found a + // complete solution. + if (wordsToPlace.isEmpty) { + final bounds = grid.getBounds(); + final currentArea = bounds.area; + + // Check if this solution is better than our current best. + if (_bestSolution == null || currentArea < _minArea) { + _minArea = currentArea; + _bestSolution = grid.copy(); + } + return; + } + + // --- PRUNING STEP --- + // If the grid we're building is *already* bigger than our + // best-known solution, there's no point continuing. + // This is the "bound" in "branch and bound". + if (_minArea != -1) { + final currentBounds = grid.getBounds(); + if (currentBounds.area >= _minArea) { + return; // Prune this branch + } + } + + // RECURSIVE STEP: + final word = wordsToPlace.first; + final remainingWords = wordsToPlace.sublist(1); + + // 1. Find all possible valid placements for the current word. + final placements = _findAllValidPlacements(grid, word) + // Optional: Shuffle placements to get different grid layouts + // on different runs. + ..shuffle(); + + // 2. Try each placement one by one. + for (final placement in placements) { + // 2a. "Commit" the placement to a *new* grid. + final newGrid = grid.copy()..placeWord(word, placement); + + // 2b. Recursively try to solve for the *rest* of the words. + _solve(newGrid, remainingWords); + + // 2c. After the recursive call, we just continue to the + // next placement. We don't return here, because we + // need to check ALL possible branches. + } + + // 3. If we tried all placements, this branch is done. + // (No return null, as the function is void) + } + + /// Finds all possible valid placements for a new [word] on the + /// existing [grid]. + List<_Placement> _findAllValidPlacements(_Grid grid, String word) { + final validPlacements = <_Placement>[]; + + // Iterate through every word *already on the grid* + for (final placedWord in grid.placedWords) { + final isHorizontal = placedWord.isHorizontal; + final newWordIsHorizontal = !isHorizontal; + + // Iterate through each letter of the new word + for (var i = 0; i < word.length; i++) { + final newWordChar = word[i]; + + // Iterate through each letter of the existing word + for (var j = 0; j < placedWord.word.length; j++) { + final placedWordChar = placedWord.word[j]; + + // Check for an intersection (matching character) + if (newWordChar == placedWordChar) { + // We found a potential intersection! + // Now calculate the (x, y) starting position + // for the new word. + int newX; + int newY; + if (newWordIsHorizontal) { + // New word is horizontal, old word is vertical + newX = placedWord.x - i; + newY = placedWord.y + j; + } else { + // New word is vertical, old word is horizontal + newX = placedWord.x + j; + newY = placedWord.y - i; + } + + final placement = _Placement( + word: word, + x: newX, + y: newY, + isHorizontal: newWordIsHorizontal, + ); + + // Check if this placement is *actually* valid + // (i.e., doesn't collide or create bad words) + if (_isValidPlacement(grid, placement)) { + validPlacements.add(placement); + } + } + } + } + } + return validPlacements; + } + + /// This is the most complex logic. + /// Checks if a [placement] is valid on the [grid]. + /// + /// A placement is valid if: + /// 1. It doesn't collide with existing letters (unless + /// it's an intersection point). + /// 2. It doesn't create new "accidental" words by + /// running parallel to an existing word. + /// 3. The cells before the start and after the end are empty. + bool _isValidPlacement(_Grid grid, _Placement placement) { + final word = placement.word; + + for (var k = 0; k < word.length; k++) { + final letter = word[k]; + final coord = placement.getCoordinate(k); + + final cell = grid.cells[coord]; + + if (cell != null) { + // Cell is NOT empty + if (cell != letter) { + // 1. COLLISION: Cell has a *different* letter. Invalid. + return false; + } else { + // 1b. INTERSECTION: Cell has the *same* letter. This is + // our intersection point. This is fine. + // (Removed redundant 'intersections++') + } + } else { + // Cell IS empty. + // 2. ADJACENCY CHECK: Check for "accidental" parallel words. + _Coordinate adjacent1; + _Coordinate adjacent2; + if (placement.isHorizontal) { + // Check cells above (y-1) and below (y+1) + adjacent1 = coord.copy(y: coord.y - 1); + adjacent2 = coord.copy(y: coord.y + 1); + } else { + // Check cells left (x-1) and right (x+1) + adjacent1 = coord.copy(x: coord.x - 1); + adjacent2 = coord.copy(x: coord.x + 1); + } + + if (grid.cells.containsKey(adjacent1) || + grid.cells.containsKey(adjacent2)) { + // This empty cell is adjacent to another word it's + // not intersecting with. This is invalid. + return false; + } + } + } + + // 3. END-CAP CHECK: Check before the start and after the end + // of the word. These cells MUST be empty. + _Coordinate before; + _Coordinate after; + if (placement.isHorizontal) { + before = _Coordinate(x: placement.x - 1, y: placement.y); + after = _Coordinate(x: placement.x + word.length, y: placement.y); + } else { + before = _Coordinate(x: placement.x, y: placement.y - 1); + after = _Coordinate(x: placement.x, y: placement.y + word.length); + } + + if (grid.cells.containsKey(before) || grid.cells.containsKey(after)) { + return false; + } + + // If we've passed all checks, it's a valid placement. + return true; + } + + /// Converts the internal [_Grid] (sparse map) into the + /// final [CrosswordGrid] (dense 2D list). + CrosswordGrid _normalizeGrid(_Grid grid) { + if (grid.cells.isEmpty) { + return const CrosswordGrid( + gridData: [], + width: 0, + height: 0, + wordPlacements: [], + ); + } + + // 1. Find the bounds of the sparse grid. + final bounds = grid.getBounds(); + final width = bounds.width; + final height = bounds.height; + + if (width <= 0 || height <= 0) { + return const CrosswordGrid( + gridData: [], + width: 0, + height: 0, + wordPlacements: [], + ); + } + + // 3. Create the 2D "dense" list, filled with empty strings. + final denseGrid = List>.generate( + height, + (_) => List.filled(width, ''), + ); + + // 4. Copy data from the sparse grid to the dense grid, + // normalizing coordinates. + for (final entry in grid.cells.entries) { + final coord = entry.key; + final letter = entry.value; + + // Normalize coordinates + final row = coord.y - bounds.minY; + final col = coord.x - bounds.minX; + + denseGrid[row][col] = letter; + } + + // 5. Convert internal placements to public WordPlacement objects, + // normalizing their coordinates as well. + final wordPlacements = grid.placedWords.map(( + placement, + ) { + return WordPlacement( + word: placement.word, + x: placement.x - bounds.minX, + y: placement.y - bounds.minY, + isHorizontal: placement.isHorizontal, + ); + }).toList(); + + return CrosswordGrid( + gridData: denseGrid, + width: width, + height: height, + wordPlacements: wordPlacements, + ); + } +} + +// ###################################################################### +// # Internal Helper Classes +// ###################################################################### + +/// Represents the min/max bounds of the grid. +class _Bounds { + _Bounds(this.minX, this.maxX, this.minY, this.maxY); + + final int minX; + final int maxX; + final int minY; + final int maxY; + + /// Calculates the width of the bounding box. + int get width => (maxX - minX) + 1; + + /// Calculates the height of the bounding box. + int get height => (maxY - minY) + 1; + + /// Calculates the total area of the bounding box. + int get area => width * height; +} + +/// Represents a 2D coordinate. +/// Using a class makes it usable as a Map key. +class _Coordinate extends Equatable { + const _Coordinate({required this.x, required this.y}); + + final int x; + final int y; + + _Coordinate copy({int? x, int? y}) => + _Coordinate(x: x ?? this.x, y: y ?? this.y); + + @override + String toString() => '($x, $y)'; + + @override + List get props => [x, y]; +} + +/// Represents a word placed on the grid. +class _Placement { + _Placement({ + required this.word, + required this.x, + required this.y, + required this.isHorizontal, + }); + + final String word; + + /// Starting x coordinate + final int x; + + /// Starting y coordinate + final int y; + final bool isHorizontal; + + /// Gets the coordinate for the k-th letter of the word. + _Coordinate getCoordinate(int k) { + return isHorizontal + ? _Coordinate(x: x + k, y: y) + : _Coordinate(x: x, y: y + k); + } +} + +/// Internal representation of the grid. +/// Uses a "sparse" map of Coordinates to letters, so it +/// can grow infinitely in any direction. +class _Grid { + // A map of coordinates to the letter at that spot + final Map<_Coordinate, String> cells = {}; + + // A list of all words placed so far + final List<_Placement> placedWords = []; + + /// Creates a deep copy of the grid. + /// This is crucial for backtracking. + _Grid copy() { + final newGrid = _Grid(); + newGrid.cells.addAll(cells); + newGrid.placedWords.addAll(placedWords); + return newGrid; + } + + /// "Commits" a word to the grid by adding its letters + /// to the [cells] map and adding the [placement] to + /// the [placedWords] list. + void placeWord(String word, _Placement placement) { + placedWords.add(placement); + for (var k = 0; k < word.length; k++) { + final coord = placement.getCoordinate(k); + cells[coord] = word[k]; + } + } + + /// Calculates the current bounding box of the grid. + _Bounds getBounds() { + if (cells.isEmpty) { + return _Bounds(0, 0, 0, 0); + } + + var minX = 0; + var maxX = 0; + var minY = 0; + var maxY = 0; + var first = true; + + for (final coord in cells.keys) { + if (first) { + minX = maxX = coord.x; + minY = maxY = coord.y; + first = false; + } else { + minX = min(minX, coord.x); + maxX = max(maxX, coord.x); + minY = min(minY, coord.y); + maxY = max(maxY, coord.y); + } + } + return _Bounds(minX, maxX, minY, maxY); + } +} diff --git a/packages/level_generator/lib/src/app/level_generator.dart b/packages/level_generator/lib/src/app/level_generator.dart new file mode 100644 index 0000000..f13241e --- /dev/null +++ b/packages/level_generator/lib/src/app/level_generator.dart @@ -0,0 +1,168 @@ +import 'dart:developer'; +import 'dart:math' as math; + +import 'package:level_data/level_data.dart'; +import 'package:level_generator/src/app/crossword_generator_compact.dart'; +import 'package:level_generator/src/app/word_list_service.dart'; +import 'package:level_generator/src/models/difficulty_config.dart'; +import 'package:level_generator/src/models/word_placement.dart'; +import 'package:level_generator/src/services/defintion_fetcher.dart'; + +/// Main class responsible for generating levels. +class LevelGenerator { + /// The engine that generates everything needed for a crossword level. + const LevelGenerator({ + required CrosswordGenerator crosswordGenerator, + required WordListService wordListService, + required DefinitionFetcher definitionFetcher, + }) : _crosswordGenerator = crosswordGenerator, + _wordListService = wordListService, + _definitionFetcher = definitionFetcher; + + final CrosswordGenerator _crosswordGenerator; + final WordListService _wordListService; + final DefinitionFetcher _definitionFetcher; + + /// Generates a level based on the given level number. + //// + /// This includes selecting words, generating the crossword grid, + /// and fetching definitions. + Future generateLevel({required int level}) async { + log('Generating level $level', name: 'LevelGenerator.generateLevel'); + if (_wordListService.words.isEmpty) { + await _wordListService.loadWords(); + } + + log( + 'Word list loaded with ${_wordListService.words.length} words', + name: 'LevelGenerator.generateLevel', + ); + + log( + 'Calculating difficulty for level $level', + name: 'LevelGenerator.generateLevel', + ); + final difficulty = _calculateDifficulty(level); + + log( + 'Difficulty for level $level: ${difficulty.difficulty}', + name: 'LevelGenerator.generateLevel', + ); + + final levelWords = _wordListService.getWordsForLevel( + levelNumber: level, + count: difficulty.maxWordLength, + minLength: difficulty.minWordLength, + maxLength: difficulty.maxWordLength, + ); + + log( + 'Selected ${levelWords.length} words for level $level: $levelWords', + name: 'LevelGenerator.generateLevel', + ); + + final grid = _crosswordGenerator.generate(levelWords); + + if (grid == null) { + log( + 'Invalid grid generated for level $level', + name: 'LevelGenerator.generateLevel', + ); + return generateLevel(level: level); + } + + log( + 'Generated grid for level $level: ${grid.width}x${grid.height}', + name: 'LevelGenerator.generateLevel', + ); + + final wordDefinitionMap = await _definitionFetcher.fetchDefinitions( + levelWords, + ); + + // Create Crossword objects from word placements + final crosswords = _createCrosswordsFromPlacements( + grid.wordPlacements, + wordDefinitionMap, + ); + + return LevelData( + levelId: level, + words: levelWords, + boardWidth: grid.height, + boardHeight: grid.width, + boardData: grid.flattenedBoardData, + crosswords: crosswords, + ); + } + + /// Creates a map of Crossword objects from word placements. + /// + /// The directionIndex is assigned sequentially for each direction + /// (across and down separately), starting from 1. + Map _createCrosswordsFromPlacements( + List placements, + Map definitionMap, + ) { + final crosswords = {}; + + // Separate placements by direction and sort by position + final acrossWords = placements.where((p) => p.isHorizontal).toList() + ..sort((a, b) { + // Sort by row (y), then by column (x) + final yCompare = a.y.compareTo(b.y); + return yCompare != 0 ? yCompare : a.x.compareTo(b.x); + }); + + final downWords = placements.where((p) => !p.isHorizontal).toList() + ..sort((a, b) { + // Sort by column (x), then by row (y) + final xCompare = a.x.compareTo(b.x); + return xCompare != 0 ? xCompare : a.y.compareTo(b.y); + }); + + // Assign directionIndex for across words + for (var i = 0; i < acrossWords.length; i++) { + final placement = acrossWords[i]; + final word = placement.word.toUpperCase(); + crosswords[word] = Crossword( + word: word, + direction: CrossWordDirection.across, + directionIndex: i + 1, + definition: definitionMap[word], + ); + } + + // Assign directionIndex for down words + for (var i = 0; i < downWords.length; i++) { + final placement = downWords[i]; + final word = placement.word.toUpperCase(); + crosswords[word] = Crossword( + word: word, + direction: CrossWordDirection.down, + directionIndex: i + 1, + definition: definitionMap[word], + ); + } + + return crosswords; + } + + DifficultyConfig _calculateDifficulty(int levelNumber) { + if (levelNumber <= 5) { + return DifficultyConfig.easy(); + } + if (levelNumber <= 15) { + return DifficultyConfig.medium(); + } + + final base = DifficultyConfig.hard(); + final extraWords = (levelNumber - 15) ~/ 3; + final timeReduction = (levelNumber - 15) * 5; + + return base.copyWith( + maxWordsPerLevel: base.maxWordsPerLevel + extraWords, + timeLimit: math.max(60, base.timeLimit - timeReduction), + ); + } +} diff --git a/packages/level_generator/lib/src/app/word_list_service.dart b/packages/level_generator/lib/src/app/word_list_service.dart new file mode 100644 index 0000000..361104f --- /dev/null +++ b/packages/level_generator/lib/src/app/word_list_service.dart @@ -0,0 +1,175 @@ +import 'dart:collection'; +import 'dart:developer' as dev; +import 'dart:io'; +import 'dart:math'; + +// import 'package:flutter/services.dart'; + +/// Service for managing word lists and selecting appropriate words for levels. +class WordListService { + /// Service for managing word lists and selecting appropriate words for + /// levels. + WordListService({ + String? wordListPath, + Random? random, + }) : _wordListPath = wordListPath ?? 'assets/words/wordlist.txt', + _random = random ?? Random(); + + final String _wordListPath; + final Random _random; + + List _words = []; + + int _loadAttempts = 0; + + /// Get an unmodifiable view of the full word list. + UnmodifiableListView get words => UnmodifiableListView(_words); + + /// Get words for a level with specific constraints. + List getWordsForLevel({ + /// The current level number. + required int levelNumber, + + /// The number of words to select. + required int count, + + /// Minimum word length. + int? minLength, + + /// Maximum word length. + int? maxLength, + }) { + // As level increases, allow longer words + final effectiveMinLength = minLength ?? 3; + final effectiveMaxLength = maxLength ?? _calculateMaxLength(levelNumber); + final candidates = _words.where((word) { + final length = word.length; + return length >= effectiveMinLength && length <= effectiveMaxLength; + }).toList(); + + if (candidates.isEmpty) { + dev.log( + 'No candidate words found for level $levelNumber ' + 'with lengths between $effectiveMinLength and $effectiveMaxLength', + name: 'WordListService.getWordsForLevel', + ); + throw StateError( + 'No words available matching constraints: ' + 'min=$effectiveMinLength, max=$effectiveMaxLength', + ); + } + + dev.log( + 'Found ${candidates.length} candidate words for level $levelNumber ' + 'with lengths between $effectiveMinLength and $effectiveMaxLength', + name: 'WordListService.getWordsForLevel', + ); + + List selectedWords; + const maxAttempts = 50; // Safety break for finding a connected list + var attempts = 0; + + do { + dev.log( + 'Attempt ${attempts + 1} to select connected ' + 'words for level $levelNumber', + name: 'WordListService.getWordsForLevel', + ); + if (attempts >= maxAttempts) { + // If we fail to find a connected list after 50 attempts, + // we return the best-effort list and rely on the + // CrosswordGenerator to filter it out (though this is rare). + dev.log( + 'Warning: Failed to find a connected word list ' + 'after $maxAttempts attempts.', + name: 'WordListService.getWordsForLevel', + ); + selectedWords = candidates.take(count).toList(); + break; + } + + // 1. Shuffle and take the first n words + candidates.shuffle(_random); + selectedWords = candidates.take(count).toList(); + attempts++; + + // 2. Repeat if the selected list is not connected + } while (!_isConnected(selectedWords)); + + return selectedWords; + } + + /// Checks if all words in a list share at least one letter connection + /// to form a single "connected graph" (i.e., no island words). + bool _isConnected(List words) { + if (words.isEmpty) return true; + if (words.length == 1) return true; + + // We use a Breadth-First Search (BFS) approach. + final visitedWords = {}; + final queue = Queue() + // 1. Start traversal with the first word + ..add(words.first); + visitedWords.add(words.first); + + // 2. Process words in the queue + while (queue.isNotEmpty) { + final currentWord = queue.removeFirst(); + + // Check all unvisited words to see if they connect to the current word + for (final nextWord in words) { + if (!visitedWords.contains(nextWord) && + _shareAnyLetter(currentWord, nextWord)) { + visitedWords.add(nextWord); + queue.add(nextWord); + } + } + } + + // If the number of visited words equals the total number of words, + // the graph is connected, and there are no island words. + return visitedWords.length == words.length; + } + + /// Helper to check if two words share at least one common character. + bool _shareAnyLetter(String wordA, String wordB) { + // Convert the shorter word to a Set for O(1) lookup + final lettersA = wordA.split('').toSet(); + + // Check if any letter in wordB is present in lettersA + for (final charB in wordB.split('')) { + if (lettersA.contains(charB)) { + return true; + } + } + return false; + } + + int _calculateMaxLength(int levelNumber) { + // Every 5 levels, allow one letter longer words + // Starting with 4 letters at level 1 + // Level 1-5: 4 letters + // Level 6-10: 5 letters + // Level 11-15: 6 letters + // etc. + return 3 + ((levelNumber - 1) ~/ 5) + 1; + } + + /// Loads the word list from the specified file. + Future loadWords() async { + try { + if (_loadAttempts < 10 && _words.isNotEmpty) { + _loadAttempts++; + return; + } + final wordList = await File(_wordListPath).readAsString(); + _words = wordList + .split('\n') + .where((w) => w.trim().isNotEmpty) + .map((w) => w.trim().toUpperCase()) + .toList(); + } on Exception catch (_) { + _words = []; + } + } +} diff --git a/packages/level_generator/lib/src/models/crossword_grid.dart b/packages/level_generator/lib/src/models/crossword_grid.dart new file mode 100644 index 0000000..36db60b --- /dev/null +++ b/packages/level_generator/lib/src/models/crossword_grid.dart @@ -0,0 +1,65 @@ +import 'dart:developer' as dev; + +import 'package:level_generator/src/models/word_placement.dart'; + +/// A class to hold the final generated crossword grid. +/// It contains the 2D grid data, width, height, and word placements. +class CrosswordGrid { + /// A class to hold the final generated crossword grid. + /// It contains the 2D grid data, width, height, and word placements. + const CrosswordGrid({ + required this.gridData, + required this.width, + required this.height, + required this.wordPlacements, + }); + + @override + String toString() { + return 'CrosswordGrid{' + 'gridData: ${gridData.take(5)}..., ' + 'width: $width, ' + 'height:$height, ' + 'words: ${wordPlacements.length}' + '}'; + } + + /// The 2D representation of the grid, e.g., + /// [ + /// ['W', '', 'S', 'A', 'W'], + /// ['A', '', 'W', '', ''], + /// ... + /// ] + final List> gridData; + + /// The final width of the grid. + final int width; + + /// The final height of the grid. + final int height; + + /// List of all word placements in the grid with their positions and + /// directions. + final List wordPlacements; + + /// A helper function to print the grid to the console for debugging. + void printGrid() { + dev.log( + 'Grid Dimensions: ${width}w x ${height}h', + name: 'CrosswordGrid.printGrid', + ); + for (final row in gridData) { + // Join cells, replacing empty strings with a dot for readability. + final rowString = row.map((cell) => cell.isEmpty ? '.' : cell).join(' '); + dev.log(rowString, name: 'CrosswordGrid.printGrid'); + } + } + + /// Flattens the 2D [gridData] into the 1D [boardData] format + /// your game expects. + List get flattenedBoardData { + final flatList = []; + gridData.forEach(flatList.addAll); + return flatList; + } +} diff --git a/packages/level_generator/lib/src/models/difficulty_config.dart b/packages/level_generator/lib/src/models/difficulty_config.dart new file mode 100644 index 0000000..7c18e68 --- /dev/null +++ b/packages/level_generator/lib/src/models/difficulty_config.dart @@ -0,0 +1,116 @@ +/// Configuration for the game difficulty +class DifficultyConfig { + const DifficultyConfig({ + required this.minWordLength, + required this.maxWordLength, + required this.minWordsPerLevel, + required this.maxWordsPerLevel, + required this.minDifficulty, + required this.maxDifficulty, + this.timeLimit = 0, + this.pointsPerWord = 100, + this.baseGridSize = 8, + }) : difficulty = minWordLength <= 3 + ? 'easy' + : minWordLength <= 4 + ? 'medium' + : 'hard'; + + /// Create a config for easy difficulty + factory DifficultyConfig.easy() { + return const DifficultyConfig( + minWordLength: 3, + maxWordLength: 5, + minWordsPerLevel: 3, + maxWordsPerLevel: 5, + minDifficulty: 0, + maxDifficulty: 2, + baseGridSize: 6, + ); + } + + /// Create a config for medium difficulty + factory DifficultyConfig.medium() { + return const DifficultyConfig( + minWordLength: 4, + maxWordLength: 6, + minWordsPerLevel: 4, + maxWordsPerLevel: 7, + minDifficulty: 1, + maxDifficulty: 3, + timeLimit: 300, + // 5 minutes + pointsPerWord: 150, + ); + } + + /// Create a config for hard difficulty + factory DifficultyConfig.hard() { + return const DifficultyConfig( + minWordLength: 5, + maxWordLength: 8, + minWordsPerLevel: 5, + maxWordsPerLevel: 8, + minDifficulty: 2, + maxDifficulty: 5, + timeLimit: 180, + // 3 minutes + baseGridSize: 10, + pointsPerWord: 200, + ); + } + + /// The minimum length of words to use + final int minWordLength; + + /// The maximum length of words to use + final int maxWordLength; + + /// The minimum number of words per level + final int minWordsPerLevel; + + /// The maximum number of words per level + final int maxWordsPerLevel; + + /// The minimum difficulty of words (0-5) + final int minDifficulty; + + /// The maximum difficulty of words (0-5) + final int maxDifficulty; + + /// Time limit in seconds (0 means no limit) + final int timeLimit; + + /// Points awarded per word found + final int pointsPerWord; + + /// Base size of the grid (width and height) + final int baseGridSize; + + final String difficulty; + + /// Create a copy with some fields replaced + DifficultyConfig copyWith({ + int? minWordLength, + int? maxWordLength, + int? minWordsPerLevel, + int? maxWordsPerLevel, + int? minDifficulty, + int? maxDifficulty, + int? timeLimit, + int? pointsPerWord, + int? baseGridSize, + }) { + return DifficultyConfig( + minWordLength: minWordLength ?? this.minWordLength, + maxWordLength: maxWordLength ?? this.maxWordLength, + minWordsPerLevel: minWordsPerLevel ?? this.minWordsPerLevel, + maxWordsPerLevel: maxWordsPerLevel ?? this.maxWordsPerLevel, + minDifficulty: minDifficulty ?? this.minDifficulty, + maxDifficulty: maxDifficulty ?? this.maxDifficulty, + timeLimit: timeLimit ?? this.timeLimit, + pointsPerWord: pointsPerWord ?? this.pointsPerWord, + baseGridSize: baseGridSize ?? this.baseGridSize, + ); + } +} diff --git a/packages/level_generator/lib/src/models/word_placement.dart b/packages/level_generator/lib/src/models/word_placement.dart new file mode 100644 index 0000000..2e3ef16 --- /dev/null +++ b/packages/level_generator/lib/src/models/word_placement.dart @@ -0,0 +1,34 @@ +/// Represents the placement of a word in the crossword grid. +/// Contains the word text, its starting position, and direction. +class WordPlacement { + /// Represents the placement of a word in the crossword grid. + /// Contains the word text, its starting position, and direction. + const WordPlacement({ + required this.word, + required this.x, + required this.y, + required this.isHorizontal, + }); + + /// The word text + final String word; + + /// Starting x coordinate (column) in the normalized grid + final int x; + + /// Starting y coordinate (row) in the normalized grid + final int y; + + /// Whether the word is placed horizontally (true) or vertically (false) + final bool isHorizontal; + + @override + String toString() { + return 'WordPlacement{' + 'word: $word, ' + 'x: $x, ' + 'y: $y, ' + '${isHorizontal ? 'horizontal' : 'vertical'}' + '}'; + } +} diff --git a/packages/level_generator/lib/src/services/defintion_fetcher.dart b/packages/level_generator/lib/src/services/defintion_fetcher.dart new file mode 100644 index 0000000..fd0a617 --- /dev/null +++ b/packages/level_generator/lib/src/services/defintion_fetcher.dart @@ -0,0 +1,196 @@ +import 'dart:convert'; +import 'dart:developer' as dev; +import 'dart:math'; + +import 'package:free_dictionary_api_v2/free_dictionary_api_v2.dart'; +import 'package:http/http.dart' as http; + +// You will need to replace this with your actual API key handling. +// For the context of this environment, we will use a placeholder API key. +const String _apiKey = ''; +const String _apiModel = 'gemini-2.5-flash-preview-09-2025'; +const String _apiUrlBase = + 'https://generativelanguage.googleapis.com/' + 'v1beta/models/$_apiModel:generateContent'; + +/// Fetches definitions for a list of words using the Gemini API +/// with Google Search Grounding. +class DefinitionFetcher { + /// Fetches definitions for multiple words concurrently. + /// + /// Returns a Map where the key is the word and the value is its definition. + Future> fetchDefinitions(List words) async { + final futures = >>[]; + + for (final word in words) { + futures.add(_fetchSingleDefinition(word)); + } + + // Wait for all definition fetches to complete concurrently + final results = await Future.wait(futures); + + // Convert the list of MapEntries back into a single Map + return Map.fromEntries(results); + } + + /// Fetches a single word's definition with exponential backoff for + /// resilience. + Future> _fetchSingleAIDefinition( + String word, { + int attempt = 0, + }) async { + final uri = Uri.parse('$_apiUrlBase?key=$_apiKey'); + + // System instruction to guide the model's output + const systemPrompt = + 'You are a concise dictionary assistant. For the given word, ' + 'provide a single, brief definition, omitting any ' + "introductory phrase like 'The definition is...'."; + final userQuery = "What is the primary definition of the word '$word'?"; + + final payload = { + 'contents': [ + { + 'parts': [ + {'text': userQuery}, + ], + }, + ], + // Use Google Search to ensure grounded, accurate definitions + 'tools': [ + {'google_search': {}}, + ], + 'systemInstruction': { + 'parts': [ + {'text': systemPrompt}, + ], + }, + }; + + try { + final response = await http.post( + uri, + headers: {'Content-Type': 'application/json'}, + body: json.encode(payload), + ); + + if (response.statusCode == 200) { + final jsonResponse = json.decode(response.body) as Map; + final candidates = jsonResponse['candidates'] as List?; + final content = + (candidates?.first as Map)['content'] + as Map?; + final parts = content?['parts'] as List?; + final definition = + ((parts?.first as Map)['text'] as String?) ?? + 'Definition not found.'; + + // I'm using a [MapEntry] here because it's easy to merge later + return MapEntry(word, definition.trim()); + } else if (response.statusCode == 429 && attempt < 5) { + // Handle Rate Limit (Too Many Requests) with Exponential Backoff + final delay = pow(2, attempt) * 1000; // 1s, 2s, 4s, 8s, 16s + await Future.delayed(Duration(milliseconds: delay.toInt())); + dev.log( + 'Rate limit hit for "$word". ' + 'Retrying in ${delay.toInt()}ms...', + name: 'DefinitionFetcher._fetchSingleAIDefinition', + ); + return _fetchSingleAIDefinition(word, attempt: attempt + 1); + } else { + // Handle other errors (e.g., 400, 500) + dev.log( + 'API Error for "$word": ${response.statusCode} - ${response.body}', + name: 'DefinitionFetcher._fetchSingleAIDefinition', + ); + return MapEntry(word, 'Error fetching definition.'); + } + } on Exception catch (e, s) { + // Handle network errors + dev.log( + 'Network or parsing error for "$word"', + name: 'DefinitionFetcher._fetchSingleAIDefinition', + error: e, + stackTrace: s, + ); + return MapEntry(word, 'Network error.'); + } + } + + /// Fetches a single word's definition from the Free Dictionary API. + /// + /// Optimization: Single-pass algorithm that prioritizes: + /// 1. Noun definitions that don't contain the word itself + /// 2. Other definitions that don't contain the word itself + /// 3. Any available definition as fallback + /// + /// Time Complexity: O(m*d) where m=meanings, d=definitions per meaning + /// Space Complexity: O(1) - no additional data structures + Future> _fetchSingleDefinition(String word) async { + try { + final dictionary = FreeDictionaryApiV2(); + final responses = await dictionary.getDefinition(word); + + if (responses.isEmpty) { + return MapEntry(word, null); + } + + final wordLower = word.toLowerCase(); + String? bestDefinition; + String? nounDefinitionWithWord; + String? anyDefinitionWithWord; + + // Single pass through all meanings and definitions + for (final response in responses) { + final meanings = response.meanings; + if (meanings == null || meanings.isEmpty) continue; + + for (final meaning in meanings) { + final definitions = meaning.definitions; + if (definitions == null || definitions.isEmpty) continue; + + final isNoun = meaning.partOfSpeech == 'noun'; + + for (final definition in definitions) { + final defText = definition.definition; + if (defText == null || defText.isEmpty) continue; + + final containsWord = defText.toLowerCase().contains(wordLower); + + // Priority 1: Noun definition without the word + if (isNoun && !containsWord) { + return MapEntry(word, defText); + } + + // Priority 2: Any definition without the word + if (!containsWord && bestDefinition == null) { + bestDefinition = defText; + } + + // Fallback 1: Noun definition (even with word) + if (isNoun && nounDefinitionWithWord == null) { + nounDefinitionWithWord = defText; + } + + // Fallback 2: Any definition + anyDefinitionWithWord ??= defText; + } + } + } + + // Return best available definition in priority order + return MapEntry( + word, + bestDefinition ?? nounDefinitionWithWord ?? anyDefinitionWithWord, + ); + } on Exception catch (e, s) { + dev.log( + 'Error fetching definition for "$word"', + name: 'DefinitionFetcher._fetchSingleDefinition', + error: e, + stackTrace: s, + ); + return MapEntry(word, null); + } + } +} diff --git a/packages/level_generator/pubspec.yaml b/packages/level_generator/pubspec.yaml new file mode 100644 index 0000000..5784780 --- /dev/null +++ b/packages/level_generator/pubspec.yaml @@ -0,0 +1,20 @@ +name: level_generator +description: The engine that handles level generation logic +version: 0.1.0+1 +publish_to: none + +environment: + sdk: ^3.9.0 + +dependencies: + equatable: ^2.0.7 + free_dictionary_api_v2: ^1.0.3 + http: ^1.5.0 + level_data: + path: ../level_data + + +dev_dependencies: + mocktail: ^1.0.4 + test: ^1.26.3 + very_good_analysis: ^10.0.0 diff --git a/packages/level_generator/test/src/app/crossword_generator_test.dart b/packages/level_generator/test/src/app/crossword_generator_test.dart new file mode 100644 index 0000000..b928d73 --- /dev/null +++ b/packages/level_generator/test/src/app/crossword_generator_test.dart @@ -0,0 +1,147 @@ +import 'package:level_generator/src/app/crossword_generator.dart'; +import 'package:test/test.dart'; + +void main() { + late CrosswordGenerator generator; + late CrosswordGrid? grid; + + setUpAll(() { + generator = const CrosswordGenerator(shuffle: false); + final tWords = [ + 'RIFLE', + 'FLIRT', + 'FIRE', + 'LEFT', + 'TIRE', + 'REFIT', + 'FILTER', + 'RELIT', + 'TIER', + ]; + grid = generator.generate(tWords); + }); + + final tFirstViableBoardData = [ + '', + '', + '', + '', + 'T', + 'I', + 'R', + 'E', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'E', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'F', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'I', + '', + '', + '', + '', + '', + '', + '', + '', + 'F', + 'I', + 'L', + 'T', + 'E', + 'R', + '', + '', + '', + '', + '', + '', + 'L', + '', + 'E', + '', + '', + 'I', + '', + '', + '', + '', + '', + '', + 'I', + '', + 'F', + '', + '', + 'F', + 'I', + 'R', + 'E', + 'T', + 'I', + 'E', + 'R', + '', + 'T', + '', + '', + 'L', + '', + '', + '', + '', + '', + '', + 'T', + '', + '', + '', + 'R', + 'E', + 'L', + 'I', + 'T', + ]; + + test('should return the first viable board grid', () { + expect(grid!.flattenedBoardData, equals(tFirstViableBoardData)); + expect(grid!.flattenedBoardData.length, equals(108)); + expect(grid!.width, equals(12)); + expect(grid!.height, equals(9)); + }); + + test('should return null if no board can be generated', () { + final result = generator.generate(['A', 'B', 'C']); + + expect(result, isNull); + }); +} diff --git a/packages/level_generator/test/src/level_generator_test.dart b/packages/level_generator/test/src/level_generator_test.dart new file mode 100644 index 0000000..0cdd095 --- /dev/null +++ b/packages/level_generator/test/src/level_generator_test.dart @@ -0,0 +1,16 @@ +// Not required for test files +import 'package:level_generator/level_generator.dart'; +import 'package:test/test.dart'; + +void main() { + group('LevelGenerator', () { + test('can be instantiated', () { + final generator = LevelGenerator( + crosswordGenerator: CrosswordGenerator(), + wordListService: WordListService(), + definitionFetcher: DefinitionFetcher(), + ); + expect(generator, isNotNull); + }); + }); +} diff --git a/pubspec.lock b/pubspec.lock index b9735cb..b332a50 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -293,6 +293,14 @@ packages: description: flutter source: sdk version: "0.0.0" + free_dictionary_api_v2: + dependency: transitive + description: + name: free_dictionary_api_v2 + sha256: "3a2e186388fe6f47570d15c26dd711198c8186b0046630a4b482f436d15fb4cb" + url: "https://pub.dev" + source: hosted + version: "1.0.3" freezed_annotation: dependency: transitive description: @@ -445,6 +453,13 @@ packages: relative: true source: path version: "1.0.0" + level_generator: + dependency: "direct main" + description: + path: "packages/level_generator" + relative: true + source: path + version: "0.1.0+1" localstore: dependency: "direct main" description: @@ -931,5 +946,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.8.0 <4.0.0" + dart: ">=3.9.0 <4.0.0" flutter: ">=3.32.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8bb65e6..41ac566 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,6 +29,8 @@ dependencies: intl: ^0.20.2 level_data: path: packages/level_data + level_generator: + path: packages/level_generator localstore: ^1.4.0 path_provider: ^2.1.5 rive: ^0.14.0-dev.11 diff --git a/test/src/apploader/application/apploader_repository_test.dart b/test/src/apploader/application/apploader_repository_test.dart index b8184a3..fe224b5 100644 --- a/test/src/apploader/application/apploader_repository_test.dart +++ b/test/src/apploader/application/apploader_repository_test.dart @@ -1,4 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; +import 'package:level_data/level_data.dart'; import 'package:mocktail/mocktail.dart'; import 'package:sozzle/src/apploader/application/apploader_repository.dart'; import 'package:sozzle/src/level/domain/i_level_repository.dart'; @@ -22,9 +23,10 @@ void main() { group('Apploader', () { /// System Under Test late MockApploaderRepository sut; + late ILevelRepository levelRepo; setUp(() { - final levelRepo = MockLevelRepo(); + levelRepo = MockLevelRepo(); final userStatsRepo = MockUserStatsRepo(); final settingsRepo = MockSettingsRepo(); sut = MockApploaderRepository( @@ -39,6 +41,12 @@ void main() { }); test('getLevels should return LevelList', () async { + final tLevelData = [ + const LevelData.empty().copyWith(levelId: 1), + const LevelData.empty().copyWith(levelId: 2), + ]; + + when(() => levelRepo.getLevels()).thenAnswer((_) async => tLevelData); final result = await sut.getLevels(); expect(result, isA()); }); diff --git a/test/src/game_play/bloc/game_play_bloc_test.dart b/test/src/game_play/bloc/game_play_bloc_test.dart index 8395708..2686872 100644 --- a/test/src/game_play/bloc/game_play_bloc_test.dart +++ b/test/src/game_play/bloc/game_play_bloc_test.dart @@ -48,6 +48,7 @@ EXIST boardHeight: 5, levelId: 1, words: const ['EXIST', 'TEST'], + crosswords: const {}, ); setUp(() { bloc = GamePlayBloc( @@ -156,6 +157,7 @@ R D boardHeight: 4, levelId: 2, words: const ['LOWR', 'WORD', 'OLD', 'LOW', 'OWL', 'WORLD'], + crosswords: const {}, ); setUp(() { bloc = GamePlayBloc( diff --git a/test/src/game_play/view/components/game_play_board_test.dart b/test/src/game_play/view/components/game_play_board_test.dart index 85a77a0..465c43b 100644 --- a/test/src/game_play/view/components/game_play_board_test.dart +++ b/test/src/game_play/view/components/game_play_board_test.dart @@ -22,6 +22,7 @@ void main() { boardHeight: 4, levelId: 2, words: const ['LOWR', 'WORD', 'OLD', 'LOW', 'OWL', 'WORLD'], + crosswords: const {}, ); group('GamePlayBoard', () { late MockUserStatsCubit userStatsCubit; diff --git a/test/src/game_play/view/components/game_play_letters_test.dart b/test/src/game_play/view/components/game_play_letters_test.dart index 65cd81c..851ce53 100644 --- a/test/src/game_play/view/components/game_play_letters_test.dart +++ b/test/src/game_play/view/components/game_play_letters_test.dart @@ -11,7 +11,7 @@ void main() { (tester) async { await tester.pumpApp( GamePlayLetters( - LevelData.empty().copyWith(boardData: ['A', 'B', 'C']), + const LevelData.empty().copyWith(boardData: ['A', 'B', 'C']), ), );