diff --git a/CHANGELOG.md b/CHANGELOG.md index 7428f30..5412d86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,22 @@ Here I will update any noteworthy changes to the TetraVex project. ## [Unreleased] +## [0.1.3] - 2019-07-23 +### Added +- CocoaPods support. +- Icon for app. +- Basic test for UI. +- Greek and latin characters. + +### Changed +- Better graphics +- Using Swift 4. +- Upgraded project to target macOS 10.13+. +- Refactored views. + +### Fixed +- Menus get autodisabled when it is expected. + ## [0.1.2] - 2017-08-30 ### Added - Game timer. @@ -24,4 +40,4 @@ Here I will update any noteworthy changes to the TetraVex project. - Game allows for board sizes from 2x2 to 6x6. - You can select the set of digits from 6 to 10. - You can play without timer or score, but the board will only let you place pieces -correctly. \ No newline at end of file +correctly. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a357df2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Contributing + +I'm very glad that you are interested in helping! First than all please bear in mind that I'm not a professional macOS app. developer, so the code might seem suboptimal to you. My personal intention in this project is to learn, so please let me know about anything that could improve. + +## How to contribute + +If you want to do something: + +1.- Add an issue in the tracker for something you intend to do. Also you could check if there is an already opened issue you could help with. +2.- Do a fork and work on it. Be sure that you are working from the **develop** branch. Also reference it in the original issue. +3.- Submit a pull request. diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..ce112c9 --- /dev/null +++ b/Podfile @@ -0,0 +1,16 @@ +platform :osx, '10.10' + +# Used iina Podfile as a template + +target 'TetraVex' do + + use_frameworks! + + # Pods for TetraVex + +# target 'TetraVex' do +# inherit! :search_paths +# # Pods for testing +# end + +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..902ad2b --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,3 @@ +PODFILE CHECKSUM: b68152751600f324bec1b7e537ed4b31cf8f8309 + +COCOAPODS: 1.7.0.beta.3 diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock new file mode 100644 index 0000000..902ad2b --- /dev/null +++ b/Pods/Manifest.lock @@ -0,0 +1,3 @@ +PODFILE CHECKSUM: b68152751600f324bec1b7e537ed4b31cf8f8309 + +COCOAPODS: 1.7.0.beta.3 diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f65b1c0 --- /dev/null +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,399 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 04C8CDF14B1745A5C92A7A687EA400BE /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F940C819049CFF8741C0F5E3E075E607 /* Cocoa.framework */; }; + 0A28AF04A5039863390BD596DCFBE299 /* Pods-TetraVex-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A2C8B1AF07C862ED52F80EAA6D3AB3E /* Pods-TetraVex-dummy.m */; }; + E86DBE8775B7E448CF97DB41FD15DB08 /* Pods-TetraVex-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 93874899CCDEEEEF42CE5482693F1BAD /* Pods-TetraVex-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 166E987D28554EBEA10EB597E5B766F3 /* Pods-TetraVex.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-TetraVex.debug.xcconfig"; sourceTree = ""; }; + 38B2DB8695706CF7537D03DD245F02D0 /* Pods-TetraVex-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-TetraVex-Info.plist"; sourceTree = ""; }; + 3C54D5A0C35114EF0E740773E0CD11D6 /* Pods-TetraVex-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-TetraVex-acknowledgements.plist"; sourceTree = ""; }; + 58920E4D18E45C656E976BB2B9A9464A /* Pods-TetraVex.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-TetraVex.modulemap"; sourceTree = ""; }; + 7A2C8B1AF07C862ED52F80EAA6D3AB3E /* Pods-TetraVex-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-TetraVex-dummy.m"; sourceTree = ""; }; + 7FB3F5AD3AC59CA736139969506751D1 /* Pods-TetraVex.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-TetraVex.release.xcconfig"; sourceTree = ""; }; + 93874899CCDEEEEF42CE5482693F1BAD /* Pods-TetraVex-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-TetraVex-umbrella.h"; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + A7EDA8723D01015D2DE48DA7B4F634CF /* Pods-TetraVex-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-TetraVex-acknowledgements.markdown"; sourceTree = ""; }; + EA75B77E102363EB6AE989CBF1BF187F /* Pods_TetraVex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_TetraVex.framework; path = "Pods-TetraVex.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + F940C819049CFF8741C0F5E3E075E607 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1C0B23BBB50C3C9ED3076DB79356BD01 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 04C8CDF14B1745A5C92A7A687EA400BE /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 48C49D309053A000D145B9FEC5F71866 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 9E6B9E5A5389EBAC66BBED83A2613F97 /* Pods-TetraVex */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 9E6B9E5A5389EBAC66BBED83A2613F97 /* Pods-TetraVex */ = { + isa = PBXGroup; + children = ( + 58920E4D18E45C656E976BB2B9A9464A /* Pods-TetraVex.modulemap */, + A7EDA8723D01015D2DE48DA7B4F634CF /* Pods-TetraVex-acknowledgements.markdown */, + 3C54D5A0C35114EF0E740773E0CD11D6 /* Pods-TetraVex-acknowledgements.plist */, + 7A2C8B1AF07C862ED52F80EAA6D3AB3E /* Pods-TetraVex-dummy.m */, + 38B2DB8695706CF7537D03DD245F02D0 /* Pods-TetraVex-Info.plist */, + 93874899CCDEEEEF42CE5482693F1BAD /* Pods-TetraVex-umbrella.h */, + 166E987D28554EBEA10EB597E5B766F3 /* Pods-TetraVex.debug.xcconfig */, + 7FB3F5AD3AC59CA736139969506751D1 /* Pods-TetraVex.release.xcconfig */, + ); + name = "Pods-TetraVex"; + path = "Target Support Files/Pods-TetraVex"; + sourceTree = ""; + }; + A400721C7CD1DCEA96AAA1858B9C6B53 /* Products */ = { + isa = PBXGroup; + children = ( + EA75B77E102363EB6AE989CBF1BF187F /* Pods_TetraVex.framework */, + ); + name = Products; + sourceTree = ""; + }; + CBD43E0947D94E318A0ED1350CFF29ED /* OS X */ = { + isa = PBXGroup; + children = ( + F940C819049CFF8741C0F5E3E075E607 /* Cocoa.framework */, + ); + name = "OS X"; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + E0A1E60606E0BF6E2E10F1F01350DFE8 /* Frameworks */, + A400721C7CD1DCEA96AAA1858B9C6B53 /* Products */, + 48C49D309053A000D145B9FEC5F71866 /* Targets Support Files */, + ); + sourceTree = ""; + }; + E0A1E60606E0BF6E2E10F1F01350DFE8 /* Frameworks */ = { + isa = PBXGroup; + children = ( + CBD43E0947D94E318A0ED1350CFF29ED /* OS X */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 02ABD98CC3351ED940CA6BE0B3D2EF24 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E86DBE8775B7E448CF97DB41FD15DB08 /* Pods-TetraVex-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + ACD2E0A8EB9BF0276B8A9E01F61D6266 /* Pods-TetraVex */ = { + isa = PBXNativeTarget; + buildConfigurationList = 78D09135A52BF7889959D92D2FCFA32C /* Build configuration list for PBXNativeTarget "Pods-TetraVex" */; + buildPhases = ( + 02ABD98CC3351ED940CA6BE0B3D2EF24 /* Headers */, + 12959E9F107D937F5C017026D9939C78 /* Sources */, + 1C0B23BBB50C3C9ED3076DB79356BD01 /* Frameworks */, + A9F118E911EB762763D7BB02BB8E879B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Pods-TetraVex"; + productName = "Pods-TetraVex"; + productReference = EA75B77E102363EB6AE989CBF1BF187F /* Pods_TetraVex.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0930; + LastUpgradeCheck = 0930; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + productRefGroup = A400721C7CD1DCEA96AAA1858B9C6B53 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + ACD2E0A8EB9BF0276B8A9E01F61D6266 /* Pods-TetraVex */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + A9F118E911EB762763D7BB02BB8E879B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 12959E9F107D937F5C017026D9939C78 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0A28AF04A5039863390BD596DCFBE299 /* Pods-TetraVex-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 088948B48B19BFDE9ABA9633A147F63C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7FB3F5AD3AC59CA736139969506751D1 /* Pods-TetraVex.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "Target Support Files/Pods-TetraVex/Pods-TetraVex-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MODULEMAP_FILE = "Target Support Files/Pods-TetraVex/Pods-TetraVex.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 23BDB97D8BD5369DDF59C36EEBA76E8F /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 166E987D28554EBEA10EB597E5B766F3 /* Pods-TetraVex.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "Target Support Files/Pods-TetraVex/Pods-TetraVex-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MODULEMAP_FILE = "Target Support Files/Pods-TetraVex/Pods-TetraVex.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7AEF910A53385514FB037088386E649D /* Debug */ = { + isa = XCBuildConfiguration; + 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_ENABLE_OBJC_WEAK = 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_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_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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + 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 = ( + "POD_CONFIGURATION_DEBUG=1", + "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; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + AB39E9DAA3FB7A60D3F76D07BB1684A5 /* Release */ = { + isa = XCBuildConfiguration; + 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_ENABLE_OBJC_WEAK = 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_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_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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + 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_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=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; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 4.2; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7AEF910A53385514FB037088386E649D /* Debug */, + AB39E9DAA3FB7A60D3F76D07BB1684A5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 78D09135A52BF7889959D92D2FCFA32C /* Build configuration list for PBXNativeTarget "Pods-TetraVex" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23BDB97D8BD5369DDF59C36EEBA76E8F /* Debug */, + 088948B48B19BFDE9ABA9633A147F63C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/Pods/Target Support Files/Pods-TetraVex/Info.plist b/Pods/Target Support Files/Pods-TetraVex/Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-Info.plist b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-acknowledgements.markdown b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-acknowledgements.markdown new file mode 100644 index 0000000..102af75 --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-acknowledgements.markdown @@ -0,0 +1,3 @@ +# Acknowledgements +This application makes use of the following third party libraries: +Generated by CocoaPods - https://cocoapods.org diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-acknowledgements.plist b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-acknowledgements.plist new file mode 100644 index 0000000..7acbad1 --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-acknowledgements.plist @@ -0,0 +1,29 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-dummy.m b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-dummy.m new file mode 100644 index 0000000..e6e5e87 --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_TetraVex : NSObject +@end +@implementation PodsDummy_Pods_TetraVex +@end diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-frameworks.sh b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-frameworks.sh new file mode 100755 index 0000000..08e3eaa --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-frameworks.sh @@ -0,0 +1,146 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} + +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + if [ -r "$source" ]; then + # Copy the dSYM into a the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .framework.dSYM "$source")" + binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then + strip_invalid_archs "$binary" + fi + + if [[ $STRIP_BINARY_RETVAL == 1 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" + fi + fi +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identitiy + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + STRIP_BINARY_RETVAL=0 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=1 +} + +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-resources.sh b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-resources.sh new file mode 100755 index 0000000..345301f --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-resources.sh @@ -0,0 +1,118 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then + # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy + # resources to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +case "${TARGETED_DEVICE_FAMILY:-}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + 3) + TARGET_DEVICE_ARGS="--target-device tv" + ;; + 4) + TARGET_DEVICE_ARGS="--target-device watch" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; +esac + +install_resource() +{ + if [[ "$1" = /* ]] ; then + RESOURCE_PATH="$1" + else + RESOURCE_PATH="${PODS_ROOT}/$1" + fi + if [[ ! -e "$RESOURCE_PATH" ]] ; then + cat << EOM +error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. +EOM + exit 1 + fi + case $RESOURCE_PATH in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.framework) + echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true + mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true + xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + *) + echo "$RESOURCE_PATH" || true + echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" + ;; + esac +} + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] +then + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "${PODS_ROOT}*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + else + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" + fi +fi diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-umbrella.h b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-umbrella.h new file mode 100644 index 0000000..4f7eff8 --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_TetraVexVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_TetraVexVersionString[]; + diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.debug.xcconfig b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.debug.xcconfig new file mode 100644 index 0000000..521bc0e --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.debug.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.modulemap b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.modulemap new file mode 100644 index 0000000..e1c4dad --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.modulemap @@ -0,0 +1,6 @@ +framework module Pods_TetraVex { + umbrella header "Pods-TetraVex-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.release.xcconfig b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.release.xcconfig new file mode 100644 index 0000000..521bc0e --- /dev/null +++ b/Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.release.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods diff --git a/README.md b/README.md index e2c4b08..b245e0f 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,47 @@ -# TetraVex -A TetraVex port for Mac. +

+ +

-Intention +

TetraVex

+

A TetraVex port for macOS

+ +🙌 Introduction --------- -My goal is to clone - kind of - the TetraVex game for the Windows 3.1 OS, now -for macOS using **only** the Cocoa API - this includes the view drawing, no -external graphic files. I don't know if the original game used only the Win16 API -but still this seems like a fun thing to do. +The goal is to port the TetraVex game for the Windows 3.1 OS - famously included in the [Microsoft Best of Entertainment Pack](https://www.youtube.com/watch?v=HRxfAJqoSgk) - now for macOS using the Cocoa API. To keep the original game graphic style, native draw calls are used to draw the board and buttons, leading to a refreshed style while paying homage to the original game. -Target +⚙️ Build ------ -This project is written in Swift 3, so the app. target is macOS 10.12. +1.- Install CocoaPods: + +**gem** +``` +sudo gem install cocoapods +``` +**homebrew** +``` +brew install cocoapods +``` + +2. Run pod install in project root directory. +``` +pod install +``` -Contribute +3. Open the `TetraVex.xcworkspace` file. + +💭 Contribute ---------- -Please do pull request from the *develop* branch. +Please check the [CONTRIBUTING](CONTRIBUTING.md) file. -License +📔 License ------- This code is licensed by the GNU GPL v3.0. + +🎉 Acknowledgments +-------- + +The code base organization and readme file uses inspiration from the awesome [IINA macOS app](https://lhc70000.github.io/iina/). diff --git a/TetraVex.xcodeproj/project.pbxproj b/TetraVex.xcodeproj/project.pbxproj index e2b8951..72cbf63 100644 --- a/TetraVex.xcodeproj/project.pbxproj +++ b/TetraVex.xcodeproj/project.pbxproj @@ -7,8 +7,9 @@ objects = { /* Begin PBXBuildFile section */ - 71AD93E41F39B17F005F009F /* HighScores.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71AD93E21F39B17F005F009F /* HighScores.swift */; }; - 71AD93E51F39B17F005F009F /* HighScoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71AD93E31F39B17F005F009F /* HighScoreViewController.swift */; }; + B63C3CDD1C4A5FA50CDBA0B4 /* Pods_TetraVex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 793CB3FE200D88AB7C2DE7AB /* Pods_TetraVex.framework */; }; + FF19DA2F20E00945000BA72E /* TVHighScores.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF19DA2E20E00945000BA72E /* TVHighScores.swift */; }; + FF19DA3820E0170E000BA72E /* TVHighScoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF19DA3720E0170E000BA72E /* TVHighScoreViewController.swift */; }; FF57E9071D13B5CB004D2AE1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF57E9061D13B5CB004D2AE1 /* AppDelegate.swift */; }; FF57E9091D13B5CB004D2AE1 /* TVGameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF57E9081D13B5CB004D2AE1 /* TVGameViewController.swift */; }; FF57E90B1D13B5CB004D2AE1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FF57E90A1D13B5CB004D2AE1 /* Assets.xcassets */; }; @@ -73,8 +74,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 71AD93E21F39B17F005F009F /* HighScores.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighScores.swift; sourceTree = ""; }; - 71AD93E31F39B17F005F009F /* HighScoreViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighScoreViewController.swift; sourceTree = ""; }; + 62C8FA656BD72B20F4C098A1 /* Pods-TetraVex.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TetraVex.debug.xcconfig"; path = "Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.debug.xcconfig"; sourceTree = ""; }; + 793CB3FE200D88AB7C2DE7AB /* Pods_TetraVex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TetraVex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A293B03C03439EF66EB292D6 /* Pods-TetraVex.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TetraVex.release.xcconfig"; path = "Pods/Target Support Files/Pods-TetraVex/Pods-TetraVex.release.xcconfig"; sourceTree = ""; }; + FF19DA2E20E00945000BA72E /* TVHighScores.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVHighScores.swift; sourceTree = ""; }; + FF19DA3620E0111C000BA72E /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = ""; }; + FF19DA3720E0170E000BA72E /* TVHighScoreViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVHighScoreViewController.swift; sourceTree = ""; }; FF57E9031D13B5CB004D2AE1 /* TetraVex.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TetraVex.app; sourceTree = BUILT_PRODUCTS_DIR; }; FF57E9061D13B5CB004D2AE1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; FF57E9081D13B5CB004D2AE1 /* TVGameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = TVGameViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -106,6 +111,7 @@ buildActionMask = 2147483647; files = ( FF57E93D1D13B5E0004D2AE1 /* TetraVexKit.framework in Frameworks */, + B63C3CDD1C4A5FA50CDBA0B4 /* Pods_TetraVex.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -134,16 +140,129 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 3B0B9714F530243BBAB200A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 793CB3FE200D88AB7C2DE7AB /* Pods_TetraVex.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + D5B4CEE5D0FC1F487E2BFB9B /* Pods */ = { + isa = PBXGroup; + children = ( + 62C8FA656BD72B20F4C098A1 /* Pods-TetraVex.debug.xcconfig */, + A293B03C03439EF66EB292D6 /* Pods-TetraVex.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + FF19DA2720E006AD000BA72E /* Assets */ = { + isa = PBXGroup; + children = ( + FF57E90F1D13B5CB004D2AE1 /* Info.plist */, + FF57E90A1D13B5CB004D2AE1 /* Assets.xcassets */, + ); + name = Assets; + sourceTree = ""; + }; + FF19DA2920E006EB000BA72E /* Controllers */ = { + isa = PBXGroup; + children = ( + FF57E9061D13B5CB004D2AE1 /* AppDelegate.swift */, + FF57E9081D13B5CB004D2AE1 /* TVGameViewController.swift */, + FF19DA3720E0170E000BA72E /* TVHighScoreViewController.swift */, + ); + name = Controllers; + sourceTree = ""; + }; + FF19DA2A20E0070C000BA72E /* Data */ = { + isa = PBXGroup; + children = ( + FF19DA2E20E00945000BA72E /* TVHighScores.swift */, + ); + name = Data; + sourceTree = ""; + }; + FF19DA2B20E00740000BA72E /* Models */ = { + isa = PBXGroup; + children = ( + ); + name = Models; + sourceTree = ""; + }; + FF19DA2C20E0075E000BA72E /* Menu */ = { + isa = PBXGroup; + children = ( + ); + name = Menu; + sourceTree = ""; + }; + FF19DA2D20E00772000BA72E /* Views */ = { + isa = PBXGroup; + children = ( + FF57E90C1D13B5CB004D2AE1 /* Main.storyboard */, + FFE8A2F11DAC1E4400D4EB95 /* TVBoardView.swift */, + FFCEB9A61D91C19E00C3514D /* TVPieceView.swift */, + ); + name = Views; + sourceTree = ""; + }; + FF19DA3020E00996000BA72E /* Models */ = { + isa = PBXGroup; + children = ( + FF57E9461D13B943004D2AE1 /* TVPieceModel.swift */, + FF57E94A1D1447F9004D2AE1 /* TVBoardModel.swift */, + FFFBBB251D9983D70089C4EF /* TVGameModel.swift */, + ); + name = Models; + sourceTree = ""; + }; + FF19DA3120E009A7000BA72E /* Includes */ = { + isa = PBXGroup; + children = ( + FF57E92A1D13B5E0004D2AE1 /* TetraVexKit.h */, + ); + name = Includes; + sourceTree = ""; + }; + FF19DA3220E009B4000BA72E /* Assets */ = { + isa = PBXGroup; + children = ( + FF57E92C1D13B5E0004D2AE1 /* Info.plist */, + ); + name = Assets; + sourceTree = ""; + }; + FF19DA3320E009BB000BA72E /* Utils */ = { + isa = PBXGroup; + children = ( + FF57E94C1D14B411004D2AE1 /* TVPuzzleGenerator.swift */, + ); + name = Utils; + sourceTree = ""; + }; + FF19DA3520E009F7000BA72E /* Tests */ = { + isa = PBXGroup; + children = ( + FF57E9171D13B5CB004D2AE1 /* TetraVexUITests */, + FF57E9371D13B5E0004D2AE1 /* TetraVexKitTests */, + ); + name = Tests; + sourceTree = ""; + }; FF57E8FA1D13B5CB004D2AE1 = { isa = PBXGroup; children = ( FFE8A2EF1DAAB11F00D4EB95 /* CHANGELOG.md */, FFE8A2ED1DAAB0E600D4EB95 /* README.md */, + FF19DA3620E0111C000BA72E /* CONTRIBUTING.md */, FF57E9051D13B5CB004D2AE1 /* TetraVex */, - FF57E9171D13B5CB004D2AE1 /* TetraVexUITests */, FF57E9291D13B5E0004D2AE1 /* TetraVexKit */, - FF57E9371D13B5E0004D2AE1 /* TetraVexKitTests */, + FF19DA3520E009F7000BA72E /* Tests */, FF57E9041D13B5CB004D2AE1 /* Products */, + D5B4CEE5D0FC1F487E2BFB9B /* Pods */, + 3B0B9714F530243BBAB200A0 /* Frameworks */, ); sourceTree = ""; }; @@ -161,18 +280,15 @@ FF57E9051D13B5CB004D2AE1 /* TetraVex */ = { isa = PBXGroup; children = ( - 71AD93E21F39B17F005F009F /* HighScores.swift */, - 71AD93E31F39B17F005F009F /* HighScoreViewController.swift */, - FF57E9061D13B5CB004D2AE1 /* AppDelegate.swift */, - FF57E9081D13B5CB004D2AE1 /* TVGameViewController.swift */, - FFCEB9A61D91C19E00C3514D /* TVPieceView.swift */, - FFE8A2F11DAC1E4400D4EB95 /* TVBoardView.swift */, - FF57E90A1D13B5CB004D2AE1 /* Assets.xcassets */, - FF57E90C1D13B5CB004D2AE1 /* Main.storyboard */, - FF57E90F1D13B5CB004D2AE1 /* Info.plist */, + FF19DA2720E006AD000BA72E /* Assets */, + FF19DA2920E006EB000BA72E /* Controllers */, + FF19DA2A20E0070C000BA72E /* Data */, + FF19DA2B20E00740000BA72E /* Models */, + FF19DA2C20E0075E000BA72E /* Menu */, + FF19DA2D20E00772000BA72E /* Views */, ); path = TetraVex; - sourceTree = ""; + sourceTree = SOURCE_ROOT; }; FF57E9171D13B5CB004D2AE1 /* TetraVexUITests */ = { isa = PBXGroup; @@ -186,12 +302,10 @@ FF57E9291D13B5E0004D2AE1 /* TetraVexKit */ = { isa = PBXGroup; children = ( - FF57E92A1D13B5E0004D2AE1 /* TetraVexKit.h */, - FF57E9461D13B943004D2AE1 /* TVPieceModel.swift */, - FF57E94A1D1447F9004D2AE1 /* TVBoardModel.swift */, - FFFBBB251D9983D70089C4EF /* TVGameModel.swift */, - FF57E94C1D14B411004D2AE1 /* TVPuzzleGenerator.swift */, - FF57E92C1D13B5E0004D2AE1 /* Info.plist */, + FF19DA3220E009B4000BA72E /* Assets */, + FF19DA3120E009A7000BA72E /* Includes */, + FF19DA3020E00996000BA72E /* Models */, + FF19DA3320E009BB000BA72E /* Utils */, ); path = TetraVexKit; sourceTree = ""; @@ -223,6 +337,7 @@ isa = PBXNativeTarget; buildConfigurationList = FF57E91D1D13B5CB004D2AE1 /* Build configuration list for PBXNativeTarget "TetraVex" */; buildPhases = ( + B1FE67E522F7AF3AADD5076C /* [CP] Check Pods Manifest.lock */, FF57E8FF1D13B5CB004D2AE1 /* Sources */, FF57E9001D13B5CB004D2AE1 /* Frameworks */, FF57E9011D13B5CB004D2AE1 /* Resources */, @@ -300,25 +415,27 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0920; ORGANIZATIONNAME = "Marco Benzi Tobar"; TargetAttributes = { FF57E9021D13B5CB004D2AE1 = { CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0800; + DevelopmentTeam = 3F7SUY6C44; + LastSwiftMigration = 1020; + ProvisioningStyle = Automatic; }; FF57E9131D13B5CB004D2AE1 = { CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0800; + LastSwiftMigration = 1020; TestTargetID = FF57E9021D13B5CB004D2AE1; }; FF57E9271D13B5E0004D2AE1 = { CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0800; + LastSwiftMigration = 1020; }; FF57E9301D13B5E0004D2AE1 = { CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0800; + LastSwiftMigration = 1020; TestTargetID = FF57E9021D13B5CB004D2AE1; }; }; @@ -328,6 +445,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -377,14 +495,35 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + B1FE67E522F7AF3AADD5076C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-TetraVex-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ FF57E8FF1D13B5CB004D2AE1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( FFCEB9A71D91C19E00C3514D /* TVPieceView.swift in Sources */, - 71AD93E41F39B17F005F009F /* HighScores.swift in Sources */, - 71AD93E51F39B17F005F009F /* HighScoreViewController.swift in Sources */, + FF19DA3820E0170E000BA72E /* TVHighScoreViewController.swift in Sources */, + FF19DA2F20E00945000BA72E /* TVHighScores.swift in Sources */, FF57E9091D13B5CB004D2AE1 /* TVGameViewController.swift in Sources */, FFE8A2F21DAC1E4400D4EB95 /* TVBoardView.swift in Sources */, FF57E9071D13B5CB004D2AE1 /* AppDelegate.swift in Sources */, @@ -464,14 +603,20 @@ 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_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_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; @@ -494,7 +639,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -511,14 +656,20 @@ 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_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_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; @@ -535,7 +686,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -544,31 +695,41 @@ }; FF57E91E1D13B5CB004D2AE1 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 62C8FA656BD72B20F4C098A1 /* Pods-TetraVex.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 3F7SUY6C44; INFOPLIST_FILE = TetraVex/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = lisergishnu.TetraVex; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; }; name = Debug; }; FF57E91F1D13B5CB004D2AE1 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = A293B03C03439EF66EB292D6 /* Pods-TetraVex.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 3F7SUY6C44; INFOPLIST_FILE = TetraVex/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = lisergishnu.TetraVex; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -580,7 +741,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = lisergishnu.TetraVexUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = TetraVex; }; name = Debug; @@ -593,7 +754,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = lisergishnu.TetraVexUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = TetraVex; }; name = Release; @@ -617,7 +778,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -641,7 +802,7 @@ PRODUCT_BUNDLE_IDENTIFIER = lisergishnu.TetraVexKit; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -655,7 +816,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = lisergishnu.TetraVexKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TetraVex.app/Contents/MacOS/TetraVex"; }; name = Debug; @@ -668,7 +829,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = lisergishnu.TetraVexKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TetraVex.app/Contents/MacOS/TetraVex"; }; name = Release; diff --git a/TetraVex.xcodeproj/xcshareddata/xcschemes/TetraVex.xcscheme b/TetraVex.xcodeproj/xcshareddata/xcschemes/TetraVex.xcscheme index 920c968..90826a4 100644 --- a/TetraVex.xcodeproj/xcshareddata/xcschemes/TetraVex.xcscheme +++ b/TetraVex.xcodeproj/xcshareddata/xcschemes/TetraVex.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/TetraVex.xcworkspace/contents.xcworkspacedata b/TetraVex.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..33059cd --- /dev/null +++ b/TetraVex.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/TetraVex.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/TetraVex.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/TetraVex.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/TetraVex.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/TetraVex.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/TetraVex.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/TetraVex/AppDelegate.swift b/TetraVex/AppDelegate.swift index da5a979..f6dd928 100644 --- a/TetraVex/AppDelegate.swift +++ b/TetraVex/AppDelegate.swift @@ -11,145 +11,193 @@ import TetraVexKit @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - - var currentGameModel : TVGameModel = TVGameModel() - var currentGamePieces : [[TVPieceModel]]? - - //MARK: - Resizing board - func setBoardSize(width: Int, height: Int) { - currentGameModel.boardWidth = width - currentGameModel.boardHeight = height - } - - func setBoardTo2x2(sender: Any?) { - setBoardSize(width: 2, height: 2) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Size")?.submenu - sm?.item(withTitle: "2x2")?.state = 1 - sm?.item(withTitle: "3x3")?.state = 0 - sm?.item(withTitle: "4x4")?.state = 0 - sm?.item(withTitle: "5x5")?.state = 0 - sm?.item(withTitle: "6x6")?.state = 0 - } - - func setBoardTo3x3(sender: Any?) { - setBoardSize(width: 3, height: 3) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Size")?.submenu - sm?.item(withTitle: "2x2")?.state = 0 - sm?.item(withTitle: "3x3")?.state = 1 - sm?.item(withTitle: "4x4")?.state = 0 - sm?.item(withTitle: "5x5")?.state = 0 - sm?.item(withTitle: "6x6")?.state = 0 - } - - func setBoardTo4x4(sender: Any?) { - setBoardSize(width: 4, height: 4) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Size")?.submenu - sm?.item(withTitle: "2x2")?.state = 0 - sm?.item(withTitle: "3x3")?.state = 0 - sm?.item(withTitle: "4x4")?.state = 1 - sm?.item(withTitle: "5x5")?.state = 0 - sm?.item(withTitle: "6x6")?.state = 0 - } - - func setBoardTo5x5(sender: Any?) { - setBoardSize(width: 5, height: 5) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Size")?.submenu - sm?.item(withTitle: "2x2")?.state = 0 - sm?.item(withTitle: "3x3")?.state = 0 - sm?.item(withTitle: "4x4")?.state = 0 - sm?.item(withTitle: "5x5")?.state = 1 - sm?.item(withTitle: "6x6")?.state = 0 - } - - func setBoardTo6x6(sender: Any?) { - setBoardSize(width: 6, height: 6) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Size")?.submenu - sm?.item(withTitle: "2x2")?.state = 0 - sm?.item(withTitle: "3x3")?.state = 0 - sm?.item(withTitle: "4x4")?.state = 0 - sm?.item(withTitle: "5x5")?.state = 0 - sm?.item(withTitle: "6x6")?.state = 1 - } - - //MARK: - Changing range of digits - func setNumberOfDigits(num :Int) { - currentGameModel.currentNumberDigits = num - } - - func setNumberOfDigitsTo6(sender: Any?) { - setNumberOfDigits(num: 5) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Digits")?.submenu - sm?.item(withTitle: "6")?.state = 1 - sm?.item(withTitle: "7")?.state = 0 - sm?.item(withTitle: "8")?.state = 0 - sm?.item(withTitle: "9")?.state = 0 - sm?.item(withTitle: "10")?.state = 0 - } - - func setNumberOfDigitsTo7(sender: Any?) { - setNumberOfDigits(num: 6) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Digits")?.submenu - sm?.item(withTitle: "6")?.state = 0 - sm?.item(withTitle: "7")?.state = 1 - sm?.item(withTitle: "8")?.state = 0 - sm?.item(withTitle: "9")?.state = 0 - sm?.item(withTitle: "10")?.state = 0 - } - - func setNumberOfDigitsTo8(sender: Any?) { - setNumberOfDigits(num: 7) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Digits")?.submenu - sm?.item(withTitle: "6")?.state = 0 - sm?.item(withTitle: "7")?.state = 0 - sm?.item(withTitle: "8")?.state = 1 - sm?.item(withTitle: "9")?.state = 0 - sm?.item(withTitle: "10")?.state = 0 + + var currentGameModel : TVGameModel = TVGameModel() + var currentGamePieces : [[TVPieceModel]]? + var gameStarted: Bool = false + + var optionMenu: NSMenuItem? { + return NSApplication.shared.mainMenu? + .item(withTitle: "Options") + } + + //MARK: - Resizing board + func setBoardSize(width: Int, height: Int) { + currentGameModel.boardWidth = width + currentGameModel.boardHeight = height + } + + // MARK: Board size menu manipulation + var sizeSubMenu: NSMenuItem? { + return optionMenu?.submenu?.item(withTitle: "Size") + } + + @IBAction func setBoardTo2x2(sender: Any?) { + setBoardSize(width: 2, height: 2) + let sm = sizeSubMenu?.submenu + sm?.item(withTitle: "2x2")?.state = NSControl.StateValue(rawValue: 1) + sm?.item(withTitle: "3x3")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "4x4")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "5x5")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "6x6")?.state = NSControl.StateValue(rawValue: 0) + } + + @IBAction func setBoardTo3x3(sender: Any?) { + setBoardSize(width: 3, height: 3) + let sm = sizeSubMenu?.submenu + sm?.item(withTitle: "2x2")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "3x3")?.state = NSControl.StateValue(rawValue: 1) + sm?.item(withTitle: "4x4")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "5x5")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "6x6")?.state = NSControl.StateValue(rawValue: 0) + } + + @IBAction func setBoardTo4x4(sender: Any?) { + setBoardSize(width: 4, height: 4) + let sm = sizeSubMenu?.submenu + sm?.item(withTitle: "2x2")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "3x3")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "4x4")?.state = NSControl.StateValue(rawValue: 1) + sm?.item(withTitle: "5x5")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "6x6")?.state = NSControl.StateValue(rawValue: 0) + } + + @IBAction func setBoardTo5x5(sender: Any?) { + setBoardSize(width: 5, height: 5) + let sm = sizeSubMenu?.submenu + sm?.item(withTitle: "2x2")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "3x3")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "4x4")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "5x5")?.state = NSControl.StateValue(rawValue: 1) + sm?.item(withTitle: "6x6")?.state = NSControl.StateValue(rawValue: 0) + } + + @IBAction func setBoardTo6x6(sender: Any?) { + setBoardSize(width: 6, height: 6) + let sm = sizeSubMenu?.submenu + sm?.item(withTitle: "2x2")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "3x3")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "4x4")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "5x5")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "6x6")?.state = NSControl.StateValue(rawValue: 1) + } + + + //MARK: - Changing range of digits + func setNumberOfDigits(num :Int) { + currentGameModel.currentNumberDigits = num + } + + // MARK: Number of digits menu manipulation + var numberOfDigitsSubMenu: NSMenuItem? { + return optionMenu?.submenu?.item(withTitle: "Digits") + } + @IBAction func setNumberOfDigitsTo6(sender: Any?) { + setNumberOfDigits(num: 5) + let sm = numberOfDigitsSubMenu?.submenu + sm?.item(withTitle: "6")?.state = NSControl.StateValue(rawValue: 1) + sm?.item(withTitle: "7")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "8")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "9")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "10")?.state = NSControl.StateValue(rawValue: 0) + } + + @IBAction func setNumberOfDigitsTo7(sender: Any?) { + setNumberOfDigits(num: 6) + let sm = numberOfDigitsSubMenu?.submenu + sm?.item(withTitle: "6")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "7")?.state = NSControl.StateValue(rawValue: 1) + sm?.item(withTitle: "8")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "9")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "10")?.state = NSControl.StateValue(rawValue: 0) + } + + @IBAction func setNumberOfDigitsTo8(sender: Any?) { + setNumberOfDigits(num: 7) + let sm = numberOfDigitsSubMenu?.submenu + sm?.item(withTitle: "6")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "7")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "8")?.state = NSControl.StateValue(rawValue: 1) + sm?.item(withTitle: "9")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "10")?.state = NSControl.StateValue(rawValue: 0) + } + + @IBAction func setNumberOfDigitsTo9(sender: Any?) { + setNumberOfDigits(num: 8) + let sm = numberOfDigitsSubMenu?.submenu + sm?.item(withTitle: "6")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "7")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "8")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "9")?.state = NSControl.StateValue(rawValue: 1) + sm?.item(withTitle: "10")?.state = NSControl.StateValue(rawValue: 0) + } + + @IBAction func setNumberOfDigitsTo10(sender: Any?) { + setNumberOfDigits(num: 9) + let sm = numberOfDigitsSubMenu?.submenu + sm?.item(withTitle: "6")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "7")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "8")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "9")?.state = NSControl.StateValue(rawValue: 0) + sm?.item(withTitle: "10")?.state = NSControl.StateValue(rawValue: 1) + } + + + @IBAction func setTextStyleToDigits(sender: Any?) { + guard let controller = NSApplication.shared.mainWindow?.contentViewController as? TVGameViewController else { + return } - - func setNumberOfDigitsTo9(sender: Any?) { - setNumberOfDigits(num: 8) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Digits")?.submenu - sm?.item(withTitle: "6")?.state = 0 - sm?.item(withTitle: "7")?.state = 0 - sm?.item(withTitle: "8")?.state = 0 - sm?.item(withTitle: "9")?.state = 1 - sm?.item(withTitle: "10")?.state = 0 + + optionMenu?.submenu?.item(withTitle: "Numbers")?.state = .on + optionMenu?.submenu?.item(withTitle: "Letters")?.state = .off + optionMenu?.submenu?.item(withTitle: "Greek")?.state = .off + + controller.setTextStyle(to: .digits) + } + + @IBAction func setTextStyleToLetters(sender: Any?) { + guard let controller = NSApplication.shared.mainWindow?.contentViewController as? TVGameViewController else { + return } - - func setNumberOfDigitsTo10(sender: Any?) { - setNumberOfDigits(num: 9) - let sm = NSApplication.shared().mainMenu? - .item(withTitle: "Options")?.submenu?.item(withTitle: "Digits")?.submenu - sm?.item(withTitle: "6")?.state = 0 - sm?.item(withTitle: "7")?.state = 0 - sm?.item(withTitle: "8")?.state = 0 - sm?.item(withTitle: "9")?.state = 0 - sm?.item(withTitle: "10")?.state = 1 + + optionMenu?.submenu?.item(withTitle: "Numbers")?.state = .off + optionMenu?.submenu?.item(withTitle: "Letters")?.state = .on + optionMenu?.submenu?.item(withTitle: "Greek")?.state = .off + + controller.setTextStyle(to: .letters) + } + @IBAction func setTextStyleToGreekSymbols(sender: Any?) { + guard let controller = NSApplication.shared.mainWindow?.contentViewController as? TVGameViewController else { + return } - - //MARK: - Game actions - /* - * Friendly reminder, First Responder actions in Xcode 8, Swift 3 - * have to be described as: - * functionNameWithSender: - * in the Interface Builder. - */ - func newGame(sender: Any?) { - let pg = TVPuzzleGenerator(width: currentGameModel.boardWidth, height: currentGameModel.boardHeight, rangeOfNumbers: 0...currentGameModel.currentNumberDigits) - currentGamePieces = pg.solvedBoard - let pv : TVGameViewController = NSApplication.shared().mainWindow?.contentViewController as! TVGameViewController - pv.solvedBoard = currentGamePieces - pv.newBoard(currentGameModel.boardWidth, height: currentGameModel.boardHeight) - + + optionMenu?.submenu?.item(withTitle: "Numbers")?.state = .off + optionMenu?.submenu?.item(withTitle: "Letters")?.state = .off + optionMenu?.submenu?.item(withTitle: "Greek")?.state = .on + + controller.setTextStyle(to: .greekSymbols) + } + + //MARK: - Game actions + @IBAction func newGame(sender: Any?) { + let pg = TVPuzzleGenerator(width: currentGameModel.boardWidth, height: currentGameModel.boardHeight, rangeOfNumbers: 0...currentGameModel.currentNumberDigits) + currentGamePieces = pg.solvedBoard + let pv : TVGameViewController = NSApplication.shared.mainWindow?.contentViewController as! TVGameViewController + pv.solvedBoard = currentGamePieces + pv.newBoard(currentGameModel.boardWidth, height: currentGameModel.boardHeight) + + gameStarted = true + } +} + +//MARK: - Menu validation +extension AppDelegate: NSMenuItemValidation { + func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + if !gameStarted { + if 10...36 ~= menuItem.tag { + return false + } } - + return true + } } diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Contents.json b/TetraVex/Assets.xcassets/AppIcon.appiconset/Contents.json index 2db2b1c..83b1372 100644 --- a/TetraVex/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/TetraVex/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,53 +1,63 @@ { "images" : [ { - "idiom" : "mac", "size" : "16x16", + "idiom" : "mac", + "filename" : "Icon-16.png", "scale" : "1x" }, { - "idiom" : "mac", "size" : "16x16", + "idiom" : "mac", + "filename" : "Icon-33.png", "scale" : "2x" }, { - "idiom" : "mac", "size" : "32x32", + "idiom" : "mac", + "filename" : "Icon-32.png", "scale" : "1x" }, { - "idiom" : "mac", "size" : "32x32", + "idiom" : "mac", + "filename" : "Icon-32@2x.png", "scale" : "2x" }, { - "idiom" : "mac", "size" : "128x128", + "idiom" : "mac", + "filename" : "Icon-128.png", "scale" : "1x" }, { - "idiom" : "mac", "size" : "128x128", + "idiom" : "mac", + "filename" : "Icon-257.png", "scale" : "2x" }, { - "idiom" : "mac", "size" : "256x256", + "idiom" : "mac", + "filename" : "Icon-256.png", "scale" : "1x" }, { - "idiom" : "mac", "size" : "256x256", + "idiom" : "mac", + "filename" : "Icon-513.png", "scale" : "2x" }, { - "idiom" : "mac", "size" : "512x512", + "idiom" : "mac", + "filename" : "Icon-512.png", "scale" : "1x" }, { - "idiom" : "mac", "size" : "512x512", + "idiom" : "mac", + "filename" : "Icon-512@2x.png", "scale" : "2x" } ], diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-128.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-128.png new file mode 100644 index 0000000..3013efc Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-128.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-16.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-16.png new file mode 100644 index 0000000..4e43e70 Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-16.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-256.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-256.png new file mode 100644 index 0000000..7e19cf7 Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-256.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-257.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-257.png new file mode 100644 index 0000000..7e19cf7 Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-257.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-32.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-32.png new file mode 100644 index 0000000..86b5c61 Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-32.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-32@2x.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-32@2x.png new file mode 100644 index 0000000..158f6df Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-32@2x.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-33.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-33.png new file mode 100644 index 0000000..4302b93 Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-33.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-512.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-512.png new file mode 100644 index 0000000..2405ad4 Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-512.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-512@2x.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-512@2x.png new file mode 100644 index 0000000..d4e9dd4 Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-512@2x.png differ diff --git a/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-513.png b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-513.png new file mode 100644 index 0000000..2405ad4 Binary files /dev/null and b/TetraVex/Assets.xcassets/AppIcon.appiconset/Icon-513.png differ diff --git a/TetraVex/Assets.xcassets/Board Background Color.colorset/Contents.json b/TetraVex/Assets.xcassets/Board Background Color.colorset/Contents.json new file mode 100644 index 0000000..386c6ef --- /dev/null +++ b/TetraVex/Assets.xcassets/Board Background Color.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.748", + "alpha" : "1.000", + "blue" : "0.748", + "green" : "0.748" + } + } + } + ] +} \ No newline at end of file diff --git a/TetraVex/Assets.xcassets/Contents.json b/TetraVex/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/TetraVex/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TetraVex/Assets.xcassets/Piece Inner Stroke Color.colorset/Contents.json b/TetraVex/Assets.xcassets/Piece Inner Stroke Color.colorset/Contents.json new file mode 100644 index 0000000..c6e5d3d --- /dev/null +++ b/TetraVex/Assets.xcassets/Piece Inner Stroke Color.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "1.000", + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000" + } + } + } + ] +} \ No newline at end of file diff --git a/TetraVex/Assets.xcassets/Piece Outer Stroke Color.colorset/Contents.json b/TetraVex/Assets.xcassets/Piece Outer Stroke Color.colorset/Contents.json new file mode 100644 index 0000000..c60cc7c --- /dev/null +++ b/TetraVex/Assets.xcassets/Piece Outer Stroke Color.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.000", + "alpha" : "1.000", + "blue" : "0.000", + "green" : "0.000" + } + } + } + ] +} \ No newline at end of file diff --git a/TetraVex/Assets.xcassets/Piece Text Color.colorset/Contents.json b/TetraVex/Assets.xcassets/Piece Text Color.colorset/Contents.json new file mode 100644 index 0000000..c6e5d3d --- /dev/null +++ b/TetraVex/Assets.xcassets/Piece Text Color.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "1.000", + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000" + } + } + } + ] +} \ No newline at end of file diff --git a/TetraVex/Base.lproj/Main.storyboard b/TetraVex/Base.lproj/Main.storyboard index 65a3d34..da4bc3d 100644 --- a/TetraVex/Base.lproj/Main.storyboard +++ b/TetraVex/Base.lproj/Main.storyboard @@ -1,8 +1,9 @@ - + - - + + + @@ -61,8 +62,9 @@ + - + @@ -74,7 +76,11 @@ - + + + + + @@ -93,31 +99,31 @@ - + - + - + - + - + @@ -130,31 +136,31 @@ - + - + - + - + - + @@ -164,14 +170,23 @@ - + + + + - + + + + - + + + + @@ -197,17 +212,20 @@ - + - + + + + @@ -221,11 +239,14 @@ - + + + + @@ -233,12 +254,12 @@ - + - + @@ -287,12 +308,12 @@ - - + @@ -353,39 +374,119 @@ - - - - - - - - - - + + + + + + + - + + + - + + + + + + + + + + + + diff --git a/TetraVex/HighScoreViewController.swift b/TetraVex/HighScoreViewController.swift deleted file mode 100644 index 7ea5a71..0000000 --- a/TetraVex/HighScoreViewController.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// HighScoreViewController.swift -// TetraVex -// -// Created by Alessandro Vinciguerra on 08/08/2017. -// -// Copyright © 2017 Arc676/Alessandro Vinciguerra -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation (version 3) -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -import Cocoa - -class HighScoreViewController : NSViewController, NSTableViewDelegate, NSTableViewDataSource { - - @IBOutlet weak var tableView: NSTableView! - - var selectedSize: String = "2x2" - var scores: HighScores? - var dates: [NSDate]? - - var dateFmt: DateFormatter? - - override func viewDidLoad() { - scores = HighScores.read() - reload() - - dateFmt = DateFormatter() - dateFmt?.timeZone = TimeZone.current - dateFmt?.dateFormat = "yyyy-MM-dd HH:mm:ss" - - tableView.delegate = self - tableView.dataSource = self - } - - func reload() { - dates = Array((scores?.scores![selectedSize]!.keys)!).sorted(by: { date1, date2 in - return scores!.scores![selectedSize]![date1]! < scores!.scores![selectedSize]![date2]! - }) - tableView.reloadData() - } - - func numberOfRows(in tableView: NSTableView) -> Int { - return dates!.count - } - - func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { - if tableColumn?.identifier == "Date-Time" { - return dateFmt?.string(from: dates![row] as Date) - } else { - return HighScores.timeToString(scores!.scores![selectedSize]![dates![row]]!) - } - } - - @IBAction func deleteScores(_ sender: Any) { - let alert = NSAlert() - alert.messageText = "Are you sure you want to delete your high scores? This cannot be undone." - alert.addButton(withTitle: "No") - alert.addButton(withTitle: "Yes") - if alert.runModal() == NSAlertSecondButtonReturn { - scores?.scores = HighScores.emptyScores - scores?.save() - reload() - } - } - - @IBAction func sizeChooser(_ sender: NSPopUpButton) { - selectedSize = sender.titleOfSelectedItem! - reload() - } - -} diff --git a/TetraVex/HighScores.swift b/TetraVex/HighScores.swift deleted file mode 100644 index 152c870..0000000 --- a/TetraVex/HighScores.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// HighScores.swift -// TetraVex -// -// Created by Alessandro Vinciguerra on 08/08/2017. -// -// Copyright © 2017 Arc676/Alessandro Vinciguerra -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation (version 3) -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -import Foundation - -class HighScores: NSObject, NSCoding { - - static let emptyScores: [String: [NSDate : Int]] = [ - "2x2":[:], - "3x3":[:], - "4x4":[:], - "5x5":[:], - "6x6":[:] - ] - var scores: [String: [NSDate : Int]]? - - init(_ scores: [String: [NSDate : Int]]) { - self.scores = scores - } - - static func timeToString(_ secondsPassed: Int) -> String { - let minutes = secondsPassed / 60 - let seconds: String = "00\(secondsPassed - minutes * 60)" - return "\(minutes):\(seconds.substring(from: seconds.index(seconds.endIndex, offsetBy: -2)))" - } - - //MARK: - En/Decoding - func encode(with aCoder: NSCoder) { - aCoder.encode(scores) - } - - required convenience init?(coder aDecoder: NSCoder) { - guard let scores = aDecoder.decodeObject() as? [String: [NSDate : Int]] else { - return nil - } - self.init(scores) - } - - //MARK: - Saving/Reading - func save() { - let data = NSKeyedArchiver.archivedData(withRootObject: self) - UserDefaults.standard.set(data, forKey: "HighScore") - } - - static func read() -> HighScores { - guard let data = UserDefaults.standard.object(forKey: "HighScore") as? Data else { - return HighScores(HighScores.emptyScores) - } - return NSKeyedUnarchiver.unarchiveObject(with: data) as! HighScores - } - -} diff --git a/TetraVex/Info.plist b/TetraVex/Info.plist index 34f998b..ca0c533 100644 --- a/TetraVex/Info.plist +++ b/TetraVex/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.1.2 + 0.1.3 CFBundleSignature ???? CFBundleVersion - 1 + 2 LSApplicationCategoryType public.app-category.puzzle-games LSMinimumSystemVersion diff --git a/TetraVex/TVBoardView.swift b/TetraVex/TVBoardView.swift index b5ce0ee..0b614ff 100644 --- a/TetraVex/TVBoardView.swift +++ b/TetraVex/TVBoardView.swift @@ -8,10 +8,114 @@ import Foundation import Cocoa +import TetraVexKit -class TVBoardView: NSBox { - - override func mouseUp(with event: NSEvent) { - +@IBDesignable +class TVBoardView: NSView { + + @IBInspectable var pieceWidth : CGFloat = 90 + @IBInspectable var pieceHeight : CGFloat = 90 + @IBInspectable var insetStrokeLineWidth : CGFloat = 3 + + var model : TVBoardModel? = nil { + didSet { + guard let model = model else { + return + } + prepareBoard(with: model) + } + } + + + override func mouseUp(with event: NSEvent) { + + } + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + + let path = NSBezierPath(roundedRect: self.bounds, xRadius: 3, yRadius: 3) + + NSColor.lightGray.setFill() + NSColor.black.setStroke() + + path.fill() + + + guard let model = model else { + return + } + + let pathSquare = NSRect( + x: 0, + y: 0, + width: pieceWidth, + height: pieceHeight) + + for i in 0.. Bool { + if boardModel!.removePieceFromBoard(p.pieceModel!) { + p.pieceModel!.isOnBoard = false + return true + } + return false + } + + func checkPiece(with pv:TVPieceView,at dropOffPosition:NSPoint) { + /* Determine the position of view inside the grid */ + if boardAreaBox.frame.contains(dropOffPosition) { + let i : Int = Int((dropOffPosition.x - boardAreaBox.frame.origin.x) / pv.frame.width) + let j : Int = Int((dropOffPosition.y - boardAreaBox.frame.origin.y) / pv.frame.height) + + if boardModel!.addPieceToBoard(pv.pieceModel!, x: i, y: j) { + pv.frame.origin.x = CGFloat(i)*pv.frame.width + boardAreaBox.frame.origin.x + pv.frame.origin.y = CGFloat(j)*pv.frame.height + boardAreaBox.frame.origin.y + pv.pieceModel?.isOnBoard = true + if boardModel!.isCompleted() { + timer?.invalidate() + timer = nil + + let size = "\(boardModel!.boardWidth)x\(boardModel!.boardHeight)" + scores?.scores?[size]?[NSDate()] = secondsPassed + scores?.save() + } + } else { + let randomSource = GKARC4RandomSource() + var newOrigin = templatePieceView.frame.origin + newOrigin.x += CGFloat(Int.random(0...100,randomSource: randomSource)) + newOrigin.y -= CGFloat(Int.random(0...100,randomSource: randomSource)) + pv.animator().setFrameOrigin(newOrigin) + } + } + } + + //MARK: - Timing + @objc func tick() { + secondsPassed += 1 + timerLabel.stringValue = TVHighScores.timeToString(secondsPassed) + } + + // MARK: Changing the piece text style + var visiblePieces : [TVPieceView]? + + func setTextStyle(to style:TVPieceModel.TextStyle) { + guard let pieces = visiblePieces else { + return + } + textStyle(for: pieces, style) + } + + func textStyle(for pieces:[TVPieceView],_ style: TVPieceModel.TextStyle) { + for piece in pieces { + guard var model = piece.pieceModel else { + continue + } + model.textStyle = style + piece.pieceModel = model + piece.needsDisplay = true + } + } + +} -class TVGameViewController: NSViewController { - - var solvedBoard : [[TVPieceModel]]? = nil - @IBOutlet weak var boardAreaBox: TVBoardView! - @IBOutlet weak var templatePieceView: TVPieceView! - var currentPiecesOnBoard : [TVPieceView] = [] - var boardModel: TVBoardModel? - var delegate : AppDelegate? - - //timing - var timer: Timer? - var secondsPassed: Int = 0 - @IBOutlet weak var timerLabel: NSTextField! - - //scores - var scores: HighScores? - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - delegate = NSApplication.shared().delegate as? AppDelegate - scores = HighScores.read() - } - - override var representedObject: Any? { - didSet { - // Update the view, if already loaded. - } - } - - func newBoard(_ width: Int, height: Int) { - /* Resize board outline */ - let pw = templatePieceView.frame.width - let ph = templatePieceView.frame.height - let topY = boardAreaBox.frame.origin.y + boardAreaBox.frame.height - - let newBox = CGRect(x: boardAreaBox.frame.origin.x, - y: topY - (ph)*CGFloat(height), - width: pw*CGFloat(width), - height: ph*CGFloat(height)) - boardAreaBox.frame = newBox - boardAreaBox.bounds = NSRect(x: 0, y: 0, width: boardAreaBox.frame.width, height: boardAreaBox.frame.height) - - boardModel = TVBoardModel(width: width, height: height) - - /* Generate and shuffle new pieces */ - /* Also delete previous pieces */ - for pv in currentPiecesOnBoard { - pv.removeFromSuperview() - } - if ((solvedBoard) != nil) { - for i in 0.. Bool { - if boardModel!.removePieceFromBoard(p.pieceModel!) { - p.pieceModel!.isOnBoard = false - return true - } - return false - } - - func checkPiece(with pv:TVPieceView,at dropOffPosition:NSPoint) { - /* Determine the position of view inside the grid */ - if boardAreaBox.frame.contains(dropOffPosition) { - let i : Int = Int((dropOffPosition.x - boardAreaBox.frame.origin.x) / pv.frame.width) - let j : Int = Int((dropOffPosition.y - boardAreaBox.frame.origin.y) / pv.frame.height) - - if boardModel!.addPieceToBoard(pv.pieceModel!, x: i, y: j) { - pv.frame.origin.x = CGFloat(i)*pv.frame.width + boardAreaBox.frame.origin.x - pv.frame.origin.y = CGFloat(j)*pv.frame.height + boardAreaBox.frame.origin.y - pv.pieceModel?.isOnBoard = true - if boardModel!.isCompleted() { - timer?.invalidate() - timer = nil - - let size = "\(boardModel!.boardWidth)x\(boardModel!.boardHeight)" - scores?.scores?[size]?[NSDate()] = secondsPassed - scores?.save() - } - } else { - pv.frame.origin.x = templatePieceView.frame.origin.x + CGFloat(Int.random(0...100)) - pv.frame.origin.y = templatePieceView.frame.origin.y - CGFloat(Int.random(0...100)) - } - } - } - - //MARK: - Timing - @objc func tick() { - secondsPassed += 1 - timerLabel.stringValue = HighScores.timeToString(secondsPassed) - } - +extension TVGameViewController : TVPieceViewDelegate { + func wasLiftedFromBoard(piece: TVPieceView) { + removeFromBoard(piece: piece) + guard let layer = piece.layer else { + return + } + layer.shadowColor = NSColor.black.cgColor + layer.shadowOpacity = 0.75 + layer.shadowOffset = CGSize(width: 5,height: 10) + layer.shadowRadius = 10 + } + + func wasDropped(piece: TVPieceView, at: NSPoint) { + checkPiece(with: piece, at: at) + guard let layer = piece.layer else { + return + } + layer.shadowOpacity = 0.0 + } } diff --git a/TetraVex/TVHighScoreViewController.swift b/TetraVex/TVHighScoreViewController.swift new file mode 100644 index 0000000..87942c6 --- /dev/null +++ b/TetraVex/TVHighScoreViewController.swift @@ -0,0 +1,81 @@ +// +// TVHighScoreViewController.swift +// TetraVex +// +// Created by Alessandro Vinciguerra on 08/08/2017. +// +// Copyright © 2017 Arc676/Alessandro Vinciguerra +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation (version 3) +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import Cocoa + +class TVHighScoreViewController : NSViewController, NSTableViewDelegate, NSTableViewDataSource { + + @IBOutlet weak var tableView: NSTableView! + + var selectedSize: String = "2x2" + var scores: TVHighScores? + var dates: [NSDate]? + + var dateFmt: DateFormatter? + + override func viewDidLoad() { + scores = TVHighScores.read() + reload() + + dateFmt = DateFormatter() + dateFmt?.timeZone = TimeZone.current + dateFmt?.dateFormat = "yyyy-MM-dd HH:mm:ss" + + tableView.delegate = self + tableView.dataSource = self + } + + func reload() { + dates = Array((scores?.scores![selectedSize]!.keys)!).sorted(by: { date1, date2 in + return scores!.scores![selectedSize]![date1]! < scores!.scores![selectedSize]![date2]! + }) + tableView.reloadData() + } + + func numberOfRows(in tableView: NSTableView) -> Int { + return dates!.count + } + + func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { + if (tableColumn?.identifier)!.rawValue == "Date-Time" { + return dateFmt?.string(from: dates![row] as Date) + } else { + return TVHighScores.timeToString(scores!.scores![selectedSize]![dates![row]]!) + } + } + + @IBAction func deleteScores(_ sender: Any) { + let alert = NSAlert() + alert.messageText = "Are you sure you want to delete your high scores? This cannot be undone." + alert.addButton(withTitle: "No") + alert.addButton(withTitle: "Yes") + if alert.runModal() == NSApplication.ModalResponse.alertSecondButtonReturn { + scores?.scores = TVHighScores.emptyScores + scores?.save() + reload() + } + } + + @IBAction func sizeChooser(_ sender: NSPopUpButton) { + selectedSize = sender.titleOfSelectedItem! + reload() + } + +} diff --git a/TetraVex/TVHighScores.swift b/TetraVex/TVHighScores.swift new file mode 100644 index 0000000..f7cb02c --- /dev/null +++ b/TetraVex/TVHighScores.swift @@ -0,0 +1,69 @@ +// +// TVHighScores.swift +// TetraVex +// +// Created by Alessandro Vinciguerra on 08/08/2017. +// +// Copyright © 2017 Arc676/Alessandro Vinciguerra +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation (version 3) +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import Foundation + +class TVHighScores: NSObject, NSCoding { + + static let emptyScores: [String: [NSDate : Int]] = [ + "2x2":[:], + "3x3":[:], + "4x4":[:], + "5x5":[:], + "6x6":[:] + ] + var scores: [String: [NSDate : Int]]? + + init(_ scores: [String: [NSDate : Int]]) { + self.scores = scores + } + + static func timeToString(_ secondsPassed: Int) -> String { + let minutes = secondsPassed / 60 + let seconds: String = "00\(secondsPassed - minutes * 60)" + return "\(minutes):\(seconds.suffix(2))" + } + + //MARK: - En/Decoding + func encode(with aCoder: NSCoder) { + aCoder.encode(scores) + } + + required convenience init?(coder aDecoder: NSCoder) { + guard let scores = aDecoder.decodeObject() as? [String: [NSDate : Int]] else { + return nil + } + self.init(scores) + } + + //MARK: - Saving/Reading + func save() { + let data = NSKeyedArchiver.archivedData(withRootObject: self) + UserDefaults.standard.set(data, forKey: "TVHighScore") + } + + static func read() -> TVHighScores { + guard let data = UserDefaults.standard.object(forKey: "TVHighScore") as? Data else { + return TVHighScores(TVHighScores.emptyScores) + } + return NSKeyedUnarchiver.unarchiveObject(with: data) as! TVHighScores + } + +} diff --git a/TetraVex/TVPieceView.swift b/TetraVex/TVPieceView.swift index a4d7069..336f0a8 100644 --- a/TetraVex/TVPieceView.swift +++ b/TetraVex/TVPieceView.swift @@ -9,137 +9,291 @@ import Cocoa import TetraVexKit -class TVPieceView : NSView { - var pieceModel :TVPieceModel? - var isBeingDragged : Bool = false - var lastDraggedPosition : NSPoint = NSPoint() - var controller : TVGameViewController? - - // MARK: - Dragging operations - override func mouseDown(with event: NSEvent) { - if (pieceModel?.boltedInPlace)! == false { - isBeingDragged = true - lastDraggedPosition = self.convert(event.locationInWindow, to: self) - let i = superview?.subviews.index(of: self) - var svs = superview!.subviews - if (i != svs.count-1) { - swap(&svs[i!],&svs[svs.count-1]) - superview?.subviews = svs - } - if pieceModel!.isOnBoard { - controller?.removeFromBoard(piece: self) - } - NSCursor.closedHand().push() - self.needsDisplay = true - } +protocol TVPieceViewDelegate { + func wasLiftedFromBoard(piece:TVPieceView) + func wasDropped(piece:TVPieceView, at: NSPoint) +} + +@IBDesignable +class TVPieceView : NSView, NSAccessibilityButton { + var pieceModel :TVPieceModel? { + didSet{ + guard let model = pieceModel else { + return + } + bufferImage = drawTetraVex(with: model) } - - func offsetLocation(by dx:CGFloat, dy:CGFloat) { - self.setNeedsDisplay(self.bounds); - let invertDeltaY : CGFloat = self.isFlipped ? -1.0 : 1.0; - self.frame = self.frame.offsetBy(dx: dx, dy: dy*invertDeltaY) - self.setNeedsDisplay(self.bounds) + } + var isBeingDragged : Bool = false + var lastDraggedPosition : NSPoint = NSPoint() + + @IBInspectable var backgroundColor : NSColor = #colorLiteral(red: 0.7480000257, green: 0.7480000257, blue: 0.7480000257, alpha: 1) + @IBInspectable var roundedRectRadius : CGFloat = 0 + @IBInspectable var insetStrokeColor : NSColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) + @IBInspectable var insetStrokeLineWidth : CGFloat = 3 + @IBInspectable var insetOffset: CGFloat = 3 + @IBInspectable var insetShadowColor: NSColor = .gray + @IBInspectable var outerStrokeColor : NSColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) + + @IBInspectable var textColor : NSColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) + @IBInspectable var fontSize : CGFloat = 24 + + var bufferImage : NSImage? = nil + var delegate : TVPieceViewDelegate? = nil + + // MARK: - Dragging operations + override func mouseDown(with event: NSEvent) { + guard let pieceModel = pieceModel else { + return } - - override func mouseDragged(with event: NSEvent) { - if (isBeingDragged) { - let p : NSPoint = self.convert(event.locationInWindow, to: self) - offsetLocation(by: p.x - lastDraggedPosition.x, dy: p.y - lastDraggedPosition.y) - lastDraggedPosition = p - self.autoscroll(with: event) - } + + if pieceModel.boltedInPlace == false { + isBeingDragged = true + lastDraggedPosition = self.convert(event.locationInWindow, to: self) + let i = superview?.subviews.firstIndex(of: self) + var svs = superview!.subviews + if (i != svs.count-1) { + svs.swapAt(i!, svs.count-1) + superview?.subviews = svs + } + if pieceModel.isOnBoard { + delegate?.wasLiftedFromBoard(piece: self) + } + NSCursor.closedHand.push() + self.needsDisplay = true } - - override func mouseUp(with event: NSEvent) { - if isBeingDragged { - let dropPosition : NSPoint = superview!.convert(event.locationInWindow, to: nil) - controller?.checkPiece(with: self, at: dropPosition) - isBeingDragged = false - NSCursor.pop() - self.needsDisplay = true - } + } + + func offsetLocation(by dx:CGFloat, dy:CGFloat) { + self.setNeedsDisplay(self.bounds); + let invertDeltaY : CGFloat = self.isFlipped ? -1.0 : 1.0; + self.frame = self.frame.offsetBy(dx: dx, dy: dy*invertDeltaY) + self.setNeedsDisplay(self.bounds) + } + + override func mouseDragged(with event: NSEvent) { + if (isBeingDragged) { + let p : NSPoint = self.convert(event.locationInWindow, to: self) + offsetLocation(by: p.x - lastDraggedPosition.x, dy: p.y - lastDraggedPosition.y) + lastDraggedPosition = p + self.autoscroll(with: event) } - - // MARK: - Drawing operations - - func drawStringCenteredAt(_ center: NSPoint, str: NSString, attribs: [String: AnyObject]?) { - let b = str.boundingRect(with: NSSize(width: 300,height: 300), options: NSStringDrawingOptions.oneShot, attributes: attribs) - var dCenter = center - dCenter.x = center.x - b.width/2 - dCenter.y = center.y - b.height/2 - str.draw(at: dCenter, withAttributes: attribs) + } + + override func mouseUp(with event: NSEvent) { + if isBeingDragged { + let dropPosition : NSPoint = superview!.convert(event.locationInWindow, to: nil) + delegate?.wasDropped(piece: self, at: dropPosition) + isBeingDragged = false + NSCursor.pop() + self.needsDisplay = true + } + } + + // MARK: - Accessibility functions + override func accessibilityLabel() -> String? { + return "TetraVex Piece" + } + + // MARK: - Drawing operations + var textStyle: TVPieceModel.TextStyle { + return pieceModel?.textStyle ?? TVPieceModel.TextStyle.digits + } + + func convert(_ str: String, with style:TVPieceModel.TextStyle) -> NSString { + switch style { + case .digits: + return NSString(string: str) + case .greekSymbols: + let nstr: String + switch (str) { + case "0": + nstr = "α" + case "1": + nstr = "β" + case "2": + nstr = "γ" + case "3": + nstr = "δ" + case "4": + nstr = "ϵ" + case "5": + nstr = "ζ" + case "6": + nstr = "η" + case "7": + nstr = "θ" + case "8": + nstr = "ι" + case "9": + nstr = "κ" + default: + nstr = "ω" + } + return NSString(string: nstr) + case .letters: + let nstr: String + switch (str) { + case "0": + nstr = "A" + case "1": + nstr = "B" + case "2": + nstr = "C" + case "3": + nstr = "D" + case "4": + nstr = "E" + case "5": + nstr = "F" + case "6": + nstr = "G" + case "7": + nstr = "H" + case "8": + nstr = "I" + case "9": + nstr = "J" + default: + nstr = "X" + } + return NSString(string: nstr) } - - override func draw(_ dirtyRect: NSRect) { - if (pieceModel != nil) { - let pathRect = NSInsetRect(self.bounds, 5, 5) - let path = NSBezierPath(roundedRect: pathRect, xRadius: 2, yRadius: 2) - path.lineWidth = 2 - - let shadow = NSShadow() - shadow.shadowBlurRadius = 1 - - if isBeingDragged { - shadow.shadowColor = NSColor.secondarySelectedControlColor - shadow.shadowOffset = NSSize(width: 5, height: -5) - shadow.set() - } - - - NSColor.windowBackgroundColor.setFill() - NSColor.windowFrameTextColor.setStroke(); - path.fill() - - NSGraphicsContext.saveGraphicsState() - NSColor.windowFrameColor.setStroke() - NSBezierPath.strokeLine( - from: pathRect.origin, - to: NSPoint(x: pathRect.maxX, y: pathRect.maxY) - ) - NSBezierPath.strokeLine( - from: NSPoint(x:pathRect.minX,y:pathRect.maxY), - to: NSPoint(x: pathRect.maxX, y: pathRect.minY) - ) - - NSGraphicsContext.restoreGraphicsState() - - path.stroke() - - let paragraphStyle : NSMutableParagraphStyle = NSMutableParagraphStyle() - paragraphStyle.alignment = NSCenterTextAlignment - - if #available(OSX 10.10, *) { - shadow.shadowColor = NSColor.tertiaryLabelColor - } else { - // Fallback on earlier versions - } - shadow.shadowOffset = NSSize(width: 1.5, height: -1.5) - shadow.shadowBlurRadius = 1 - - let font = NSFont(name: "Helvetica", size: 18*(pathRect.height/80.0)) - - let ptop = NSPoint(x: pathRect.width*0.5 + pathRect.minX, - y: pathRect.height*0.80 + pathRect.minY) - let pbot = NSPoint(x: pathRect.width*0.5 + pathRect.minX, - y: pathRect.height*0.20 + pathRect.minY) - let pleft = NSPoint(x: pathRect.width*0.20 + pathRect.minX, - y: pathRect.height*0.5 + pathRect.minY) - let pright = NSPoint(x: pathRect.width*0.80 + pathRect.minX, - y: pathRect.height*0.5 + pathRect.minY) - - let attribs : [String:AnyObject] = - [NSShadowAttributeName:shadow, - NSFontAttributeName:font!, - NSStrokeColorAttributeName:NSColor.labelColor, - NSParagraphStyleAttributeName:paragraphStyle] - var s = NSString(format: "%d", pieceModel!.topValue) - drawStringCenteredAt(ptop, str: s, attribs: attribs) - s = NSString(format: "%d", pieceModel!.bottomValue) - drawStringCenteredAt(pbot, str: s, attribs: attribs) - s = NSString(format: "%d", pieceModel!.leftValue) - drawStringCenteredAt(pleft, str: s, attribs: attribs) - s = NSString(format: "%d", pieceModel!.rightValue) - drawStringCenteredAt(pright, str: s, attribs: attribs) - } + } + + func drawStringCenteredAt(_ center: NSPoint, str: String, attribs: [NSAttributedString.Key: Any]?) { + let nsstr = convert(str, with: textStyle) + let b = nsstr.boundingRect(with: NSSize(width: 300,height: 300), options: NSString.DrawingOptions.usesFontLeading, attributes: attribs) + var dCenter = center + dCenter.x = center.x - b.width/2 + dCenter.y = center.y - b.height/2 + nsstr.draw(at: dCenter, withAttributes: attribs) + } + + override func draw(_ dirtyRect: NSRect) { + guard let image = bufferImage else { + return } + image.draw(in: self.bounds) + } + + func drawTetraVex(with pieceModel: TVPieceModel) -> NSImage { + let image = NSImage(size: self.bounds.size) + image.lockFocus() + let pathRect = self.bounds + let path = NSBezierPath(roundedRect: pathRect, + xRadius: roundedRectRadius, + yRadius: roundedRectRadius) + + // Background Fill + backgroundColor.setFill() + path.fill() + + // Inner X lines + NSGraphicsContext.saveGraphicsState() + + drawInsetLine(NSPoint(x:pathRect.origin.x, + y:pathRect.origin.y+insetOffset), + to: NSPoint(x: pathRect.maxX, + y: pathRect.maxY+insetOffset), + color: insetShadowColor, + lineWidth: insetStrokeLineWidth) + drawInsetLine(NSPoint(x:pathRect.minX - insetOffset, + y:pathRect.maxY), + to: NSPoint(x: pathRect.maxX - insetOffset, + y: pathRect.minY), + color: insetShadowColor, + lineWidth: insetStrokeLineWidth) + + drawInsetLine(pathRect.origin, + to: NSPoint(x: pathRect.maxX, y: pathRect.maxY), + color: insetStrokeColor, + lineWidth: insetStrokeLineWidth) + drawInsetLine(NSPoint(x:pathRect.minX,y:pathRect.maxY), + to: NSPoint(x: pathRect.maxX, y: pathRect.minY), + color: insetStrokeColor, + lineWidth: insetStrokeLineWidth) + + NSGraphicsContext.restoreGraphicsState() + + // Outer stroke + let outerStrokeLineWidth : CGFloat = 10 + let outerStrokeOffset : CGFloat = 2 + + drawInsetLine(NSPoint(x:pathRect.maxX - outerStrokeOffset, + y:pathRect.minY + outerStrokeOffset), + to: NSPoint(x: pathRect.maxX - outerStrokeOffset, + y: pathRect.maxY + outerStrokeOffset), + color: .gray, + lineWidth: outerStrokeLineWidth) + drawInsetLine(NSPoint(x:pathRect.minX + outerStrokeOffset, + y:pathRect.minY - outerStrokeOffset), + to: NSPoint(x: pathRect.minX + outerStrokeOffset, + y: pathRect.maxY + outerStrokeOffset), + color: .white, + lineWidth: outerStrokeLineWidth) + drawInsetLine(NSPoint(x:pathRect.minX - outerStrokeOffset, + y:pathRect.maxY - outerStrokeOffset), + to: NSPoint(x: pathRect.maxX + outerStrokeOffset, + y: pathRect.maxY - outerStrokeOffset), + color: .white, + lineWidth: outerStrokeLineWidth) + drawInsetLine(NSPoint(x:pathRect.minX + outerStrokeOffset, + y:pathRect.minY + outerStrokeOffset), + to: NSPoint(x: pathRect.maxX - outerStrokeOffset, + y: pathRect.minY + outerStrokeOffset), + color: .gray, + lineWidth: outerStrokeLineWidth) + + + path.lineWidth = 1 + outerStrokeColor.setStroke() + path.stroke() + + + // Text + let paragraphStyle : NSMutableParagraphStyle = NSMutableParagraphStyle() + paragraphStyle.alignment = NSTextAlignment.center + let font = NSFont(name: "Helvetica-Bold", size: fontSize*(pathRect.height/80.0)) ?? NSFont.systemFont(ofSize: fontSize*(pathRect.height/80.0)) + let shadow = NSShadow() + shadow.shadowColor = .white + shadow.shadowOffset = NSSize(width: -1, height: 1) + shadow.shadowBlurRadius = 1 + let attribs : [NSAttributedString.Key:Any] = + [NSAttributedString.Key.font:font, + NSAttributedString.Key.strokeColor: textColor, + NSAttributedString.Key.shadow: shadow, + NSAttributedString.Key.paragraphStyle: + paragraphStyle] + + + let ptop = NSPoint(x: pathRect.width*0.5 + pathRect.minX, + y: pathRect.height*0.80 + pathRect.minY) + let pbot = NSPoint(x: pathRect.width*0.5 + pathRect.minX, + y: pathRect.height*0.20 + pathRect.minY) + let pleft = NSPoint(x: pathRect.width*0.20 + pathRect.minX, + y: pathRect.height*0.5 + pathRect.minY) + let pright = NSPoint(x: pathRect.width*0.80 + pathRect.minX, + y: pathRect.height*0.5 + pathRect.minY) + + drawStringCenteredAt(ptop, str: "\(pieceModel.topValue)", attribs: attribs) + drawStringCenteredAt(pbot, str: "\(pieceModel.bottomValue)", attribs: attribs) + drawStringCenteredAt(pleft, str: "\(pieceModel.leftValue)", attribs: attribs) + drawStringCenteredAt(pright, str: "\(pieceModel.rightValue)", attribs: attribs) + image.unlockFocus() + return image + } + + func drawInsetLine(_ from: CGPoint, to: CGPoint, color: NSColor, lineWidth:CGFloat = 1) { + let innerPath = NSBezierPath() + innerPath.lineWidth = insetStrokeLineWidth + innerPath.move(to: from) + innerPath.line(to: to) + color.setStroke() + innerPath.stroke() + } + + override func prepareForInterfaceBuilder() { + pieceModel = TVPieceModel(top: 1, left: 2, bottom: 3, right: 4) + } } diff --git a/TetraVexKit/TVBoardModel.swift b/TetraVexKit/TVBoardModel.swift index 5d5b053..bf5acc1 100644 --- a/TetraVexKit/TVBoardModel.swift +++ b/TetraVexKit/TVBoardModel.swift @@ -9,90 +9,90 @@ import Foundation open class TVBoardModel { + + // MARK: - Properties + open var board : [[TVPieceModel?]] + open var boardWidth : Int = 0 + open var boardHeight : Int = 0 + open var startedPlaying : Bool = false + + // MARK: - Initializer + public init(width: Int, height: Int) { + board = Array(repeating: Array(repeating: nil, count: height), count: width) + boardWidth = width + boardHeight = height + } + + // MARK: - Board manipulation + open func addPieceToBoard(_ piece: TVPieceModel, x: Int, y: Int) -> Bool { + if !(0 ... board.count-1 ~= x && 0 ... board[0].count-1 ~= y) { + return false + } - // MARK: - Properties - open var board : [[TVPieceModel?]] - open var boardWidth : Int = 0 - open var boardHeight : Int = 0 - open var startedPlaying : Bool = false + if board[x][y] != nil { + return false + } - // MARK: - Initializer - public init(width: Int, height: Int) { - board = Array(repeating: Array(repeating: nil, count: height), count: width) - boardWidth = width - boardHeight = height + var leftP :TVPieceModel? = nil + if 0 ... board.count-1 ~= x-1 && 0 ... board[0].count-1 ~= y { + leftP = board[x-1][y] + } + var rightP :TVPieceModel? = nil + if 0 ... board.count-1 ~= x+1 && 0 ... board[0].count-1 ~= y { + rightP = board[x+1][y] + } + var topP :TVPieceModel? = nil + if 0 ... board.count-1 ~= x && 0 ... board[0].count-1 ~= y+1 { + topP = board[x][y+1] + } + var botP :TVPieceModel? = nil + if 0 ... board.count-1 ~= x && 0 ... board[0].count-1 ~= y-1 { + botP = board[x][y-1] } - // MARK: - Board manipulation - open func addPieceToBoard(_ piece: TVPieceModel, x: Int, y: Int) -> Bool { - if !(0 ... board.count-1 ~= x && 0 ... board[0].count-1 ~= y) { - return false - } - - if board[x][y] != nil { - return false - } - - var leftP :TVPieceModel? = nil - if 0 ... board.count-1 ~= x-1 && 0 ... board[0].count-1 ~= y { - leftP = board[x-1][y] - } - var rightP :TVPieceModel? = nil - if 0 ... board.count-1 ~= x+1 && 0 ... board[0].count-1 ~= y { - rightP = board[x+1][y] - } - var topP :TVPieceModel? = nil - if 0 ... board.count-1 ~= x && 0 ... board[0].count-1 ~= y+1 { - topP = board[x][y+1] - } - var botP :TVPieceModel? = nil - if 0 ... board.count-1 ~= x && 0 ... board[0].count-1 ~= y-1 { - botP = board[x][y-1] - } - - if leftP != nil && leftP?.rightValue != piece.leftValue { - return false - } - - if rightP != nil && rightP?.leftValue != piece.rightValue { - return false - } - - if topP != nil && topP?.bottomValue != piece.topValue { - return false - } - - if botP != nil && botP?.topValue != piece.bottomValue { - return false - } - - board[x][y] = piece - if startedPlaying == false { - startedPlaying = true - } - return true + if leftP != nil && leftP?.rightValue != piece.leftValue { + return false } - open func removePieceFromBoard(_ piece:TVPieceModel) -> Bool { - for i in 0.. Bool { - for a in board { - for p in a { - if p == nil { - return false - } - } + board[x][y] = piece + if startedPlaying == false { + startedPlaying = true + } + return true + } + + open func removePieceFromBoard(_ piece:TVPieceModel) -> Bool { + for i in 0.. Bool { + for a in board { + for p in a { + if p == nil { + return false } - return true + } } + return true + } } diff --git a/TetraVexKit/TVGameModel.swift b/TetraVexKit/TVGameModel.swift index 3696ef5..1f08927 100644 --- a/TetraVexKit/TVGameModel.swift +++ b/TetraVexKit/TVGameModel.swift @@ -9,13 +9,13 @@ import Foundation public struct TVGameModel { - public var currentTime = 0 - public var score = 0 - public var currentNumberDigits = 10 - public var boardWidth = 2 - public var boardHeight = 2 + public var currentTime = 0 + public var score = 0 + public var currentNumberDigits = 10 + public var boardWidth = 2 + public var boardHeight = 2 + + public init() { - public init() { - - } + } } diff --git a/TetraVexKit/TVPieceModel.swift b/TetraVexKit/TVPieceModel.swift index bfb6ed7..fdee07c 100644 --- a/TetraVexKit/TVPieceModel.swift +++ b/TetraVexKit/TVPieceModel.swift @@ -9,32 +9,41 @@ import Foundation public struct TVPieceModel { - - // MARK: - Properties - public var topValue : Int - public var leftValue : Int - public var bottomValue : Int - public var rightValue : Int - public var boltedInPlace : Bool = false - public var isOnBoard : Bool = false - - // MARK: - Initializer - public init(top: Int, left: Int, bottom: Int, right: Int) { - topValue = top - leftValue = left - bottomValue = bottom - rightValue = right - } - - // MARK: - Operations - public static func == (left: TVPieceModel, right: TVPieceModel) -> Bool { - return (left.topValue == right.topValue) && - (left.bottomValue == right.bottomValue) && - (left.leftValue == right.leftValue) && - (left.rightValue == right.rightValue) - } - - public static func != (left: TVPieceModel, right: TVPieceModel) -> Bool { - return !(left == right) - } + + // MARK: - Properties + public var topValue : Int + public var leftValue : Int + public var bottomValue : Int + public var rightValue : Int + public var boltedInPlace : Bool = false + public var isOnBoard : Bool = false + + // MARK: - Setting a different piece letter style + public enum TextStyle { + case digits + case letters + case greekSymbols + } + + public var textStyle : TextStyle = .digits + + // MARK: - Initializer + public init(top: Int, left: Int, bottom: Int, right: Int) { + topValue = top + leftValue = left + bottomValue = bottom + rightValue = right + } + + // MARK: - Operations + public static func == (left: TVPieceModel, right: TVPieceModel) -> Bool { + return (left.topValue == right.topValue) && + (left.bottomValue == right.bottomValue) && + (left.leftValue == right.leftValue) && + (left.rightValue == right.rightValue) + } + + public static func != (left: TVPieceModel, right: TVPieceModel) -> Bool { + return !(left == right) + } } diff --git a/TetraVexKit/TVPuzzleGenerator.swift b/TetraVexKit/TVPuzzleGenerator.swift index 030d546..f66afeb 100644 --- a/TetraVexKit/TVPuzzleGenerator.swift +++ b/TetraVexKit/TVPuzzleGenerator.swift @@ -7,50 +7,57 @@ // import Foundation +import GameplayKit extension Int { - public static func random(_ range: ClosedRange ) -> Int + public static func random(_ range: ClosedRange, randomSource: GKRandomSource ) -> Int + { + var offset = 0 + + if range.lowerBound < 0 // allow negative ranges { - var offset = 0 - - if range.lowerBound < 0 // allow negative ranges - { - offset = abs(range.lowerBound) - } - - let mini = UInt32(range.lowerBound + offset) - let maxi = UInt32(range.upperBound + offset) - - return Int(mini + arc4random_uniform(maxi - mini)) - offset + offset = abs(range.lowerBound) } + + let mini = Int(range.lowerBound + offset) + let maxi = Int(range.upperBound + offset) + + return Int(mini + randomSource.nextInt(upperBound: maxi - mini)) - offset + } } open class TVPuzzleGenerator { - - // MARK: - Properties - open var solvedBoard : [[TVPieceModel]] - - // MARK: - Initialization - public init(width: Int, height: Int, rangeOfNumbers: ClosedRange) { - solvedBoard = Array(repeating: Array(repeating:TVPieceModel(top: 0, left: 0, bottom: 0, right: 0), count: width), count: width) - for i in 0.. 0 { - p.bottomValue = (solvedBoard[i][j-1]).topValue - } else { - p.bottomValue = Int.random(rangeOfNumbers) - } - if i > 0 { - p.leftValue = (solvedBoard[i-1][j]).rightValue - } else { - p.leftValue = Int.random(rangeOfNumbers) - } - p.rightValue = Int.random(rangeOfNumbers) - p.topValue = Int.random(rangeOfNumbers) - solvedBoard[i][j] = p - } + + // MARK: - Properties + open var solvedBoard : [[TVPieceModel]] + var source : GKARC4RandomSource + + // MARK: - Initialization + public init(width: Int, height: Int, rangeOfNumbers: ClosedRange, seed: Data? = nil){ + if seed == nil { + self.source = GKARC4RandomSource() + } else { + self.source = GKARC4RandomSource(seed: seed!) + } + solvedBoard = Array(repeating: Array(repeating:TVPieceModel(top: 0, left: 0, bottom: 0, right: 0), count: width), count: width) + for i in 0.. 0 { + p.bottomValue = (solvedBoard[i][j-1]).topValue + } else { + p.bottomValue = Int.random(rangeOfNumbers, randomSource: source) + } + if i > 0 { + p.leftValue = (solvedBoard[i-1][j]).rightValue + } else { + p.leftValue = Int.random(rangeOfNumbers, randomSource: source) } + p.rightValue = Int.random(rangeOfNumbers, randomSource: source) + p.topValue = Int.random(rangeOfNumbers, randomSource: source) + solvedBoard[i][j] = p + } } + } } diff --git a/TetraVexKitTests/TetraVexKitTests.swift b/TetraVexKitTests/TetraVexKitTests.swift index f810a29..a4baf98 100644 --- a/TetraVexKitTests/TetraVexKitTests.swift +++ b/TetraVexKitTests/TetraVexKitTests.swift @@ -10,82 +10,101 @@ import XCTest @testable import TetraVexKit class TetraVexKitTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testPuzzleGeneration() { + let puzzle = TVPuzzleGenerator(width: 2, height: 2, rangeOfNumbers: 0...9) + let board = TVBoardModel(width: 2, height: 2) - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } + let a = puzzle.solvedBoard[0][0] + let b = puzzle.solvedBoard[0][1] + let c = puzzle.solvedBoard[1][0] + let d = puzzle.solvedBoard[1][1] - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } + XCTAssert(board.startedPlaying == false) + XCTAssert(a != b && a != c && a != d && b != c && b != d && c != d) - func testPuzzleGeneration() { - let puzzle = TVPuzzleGenerator(width: 2, height: 2, rangeOfNumbers: 0...9) - let board = TVBoardModel(width: 2, height: 2) - - let a = puzzle.solvedBoard[0][0] - let b = puzzle.solvedBoard[0][1] - let c = puzzle.solvedBoard[1][0] - let d = puzzle.solvedBoard[1][1] - - XCTAssert(board.startedPlaying == false) - XCTAssert(a != b && a != c && a != d && b != c && b != d && c != d) - - board.addPieceToBoard(a, x: 0, y: 0) - var r = board.addPieceToBoard(b, x: 0, y: 1) - XCTAssert(r == true) - r = board.addPieceToBoard(c, x: 1, y: 0) - XCTAssert(r == true) - r = board.addPieceToBoard(d, x: 1, y: 1) - XCTAssert(r == true) - XCTAssert(board.isCompleted()) - XCTAssert(board.startedPlaying == true) - } + var r = board.addPieceToBoard(a, x: 0, y: 0) + XCTAssert(r == true) + r = board.addPieceToBoard(b, x: 0, y: 1) + XCTAssert(r == true) + r = board.addPieceToBoard(c, x: 1, y: 0) + XCTAssert(r == true) + r = board.addPieceToBoard(d, x: 1, y: 1) + XCTAssert(r == true) + XCTAssert(board.isCompleted()) + XCTAssert(board.startedPlaying == true) + } + + func testPiecePlacement() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. - func testPiecePlacement() { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - - /* A | B - C | D */ - - let a = TVPieceModel(top: 1, left: 2, bottom: 3, right: 4) - let b = TVPieceModel(top: 3, left: 4, bottom: 2, right: 1) - let c = TVPieceModel(top: 3, left: 1, bottom: 4, right: 2) - let d = TVPieceModel(top: 2, left: 2, bottom: 1, right: 1) - - - let board = TVBoardModel(width: 2, height: 2) - var r = board.removePieceFromBoard(a) - XCTAssert(r == false) - r = board.addPieceToBoard(a, x: 1, y: 1) - XCTAssert(r == true) - r = board.removePieceFromBoard(a) - XCTAssert(r == true) - r = board.addPieceToBoard(a, x: 0, y: 1) - XCTAssert(r == true) - r = board.addPieceToBoard(b, x: 0, y: 1) - XCTAssert(r == false) - r = board.addPieceToBoard(b, x: 1, y: 1) - XCTAssert(r == true) - r = board.addPieceToBoard(c, x: 1, y: 0) - XCTAssert(r == false) - r = board.addPieceToBoard(d, x: 1, y: 0) - XCTAssert(r == true) - XCTAssert(!board.isCompleted()) - r = board.addPieceToBoard(c, x: 0, y: 0) - XCTAssert(r == true) - - XCTAssert(board.isCompleted()) - } + /* A | B + C | D */ + + let a = TVPieceModel(top: 1, left: 2, bottom: 3, right: 4) + let b = TVPieceModel(top: 3, left: 4, bottom: 2, right: 1) + let c = TVPieceModel(top: 3, left: 1, bottom: 4, right: 2) + let d = TVPieceModel(top: 2, left: 2, bottom: 1, right: 1) + + + let board = TVBoardModel(width: 2, height: 2) + var r = board.removePieceFromBoard(a) + XCTAssert(r == false) + r = board.addPieceToBoard(a, x: 1, y: 1) + XCTAssert(r == true) + r = board.removePieceFromBoard(a) + XCTAssert(r == true) + r = board.addPieceToBoard(a, x: 0, y: 1) + XCTAssert(r == true) + r = board.addPieceToBoard(b, x: 0, y: 1) + XCTAssert(r == false) + r = board.addPieceToBoard(b, x: 1, y: 1) + XCTAssert(r == true) + r = board.addPieceToBoard(c, x: 1, y: 0) + XCTAssert(r == false) + r = board.addPieceToBoard(d, x: 1, y: 0) + XCTAssert(r == true) + XCTAssert(!board.isCompleted()) + r = board.addPieceToBoard(c, x: 0, y: 0) + XCTAssert(r == true) - func testPerformanceExample() { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } + XCTAssert(board.isCompleted()) + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. } + } + + func testBoardSeed() { + let seed = Data(repeating: 1, count: 1) + let puzzle = TVPuzzleGenerator(width: 2, height: 2, rangeOfNumbers: 0...9, seed: seed) + /* Check consistency */ + let expectedA = TVPieceModel(top: 6, left: 3, bottom: 6, right: 1) + let a = puzzle.solvedBoard[0][0] + XCTAssert(expectedA == a) + let expectedB = TVPieceModel(top: 5, left: 3, bottom: 6, right: 1) + let b = puzzle.solvedBoard[0][1] + XCTAssert(expectedB == b) + let expectedC = TVPieceModel(top: 1, left: 1, bottom: 8, right: 0) + let c = puzzle.solvedBoard[1][0] + XCTAssert(expectedC == c) + let expectedD = TVPieceModel(top: 3, left: 1, bottom: 1, right: 8) + let d = puzzle.solvedBoard[1][1] + XCTAssert(expectedD == d) + } } diff --git a/TetraVexUITests/TetraVexUITests.swift b/TetraVexUITests/TetraVexUITests.swift index a424668..d96bdba 100644 --- a/TetraVexUITests/TetraVexUITests.swift +++ b/TetraVexUITests/TetraVexUITests.swift @@ -9,32 +9,43 @@ import XCTest class TetraVexUITests: XCTestCase { - - override func setUp() { - super.setUp() - - // Put setup code here. This method is called before the invocation of each test method in the class. - - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false - // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. - if #available(OSX 10.11, *) { - XCUIApplication().launch() - } else { - // Fallback on earlier versions - } - - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. - } + + override func setUp() { + super.setUp() - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } + // Put setup code here. This method is called before the invocation of each test method in the class. - func testExample() { - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + if #available(OSX 10.11, *) { + XCUIApplication().launch() + } else { + // Fallback on earlier versions } + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + /// Tests the proper creation of a board from scratch + func testNewGame() { + + let app = XCUIApplication() + let menuBarsQuery = app.menuBars + menuBarsQuery.menuBarItems["Game"].click() + menuBarsQuery/*@START_MENU_TOKEN@*/.menuItems["New Game"]/*[[".menuBarItems[\"Game\"]",".menus.menuItems[\"New Game\"]",".menuItems[\"New Game\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.click() + + let tetravexWindow = app.windows["TetraVex"] + let tetravexPieceButton = tetravexWindow.children(matching: .button).matching(identifier: "TetraVex Piece").element(boundBy: 0) + tetravexPieceButton.click() + tetravexWindow.children(matching: .button).matching(identifier: "TetraVex Piece").element(boundBy: 2).click() + tetravexWindow.children(matching: .button).matching(identifier: "TetraVex Piece").element(boundBy: 1).click() + tetravexWindow.children(matching: .button).matching(identifier: "TetraVex Piece").element(boundBy: 3).click() + + } }