From 8004614ddfe1b66fe5c3b489a101b44c00bf79e2 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Wed, 24 Jun 2020 20:56:08 -0700 Subject: [PATCH 01/30] Update GitIgnore --- .gitignore | 163 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 145 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 7e4c35d1b..17211fba2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,149 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. -# dependencies -**/node_modules +# Created by https://www.gitignore.io/api/macos,python,visualstudiocode +# Edit at https://www.gitignore.io/?templates=macos,python,visualstudiocode -# testing -/coverage +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride -# production -/build +# Icon must end with two \r +Icon -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -**npm-debug.log* -**yarn-debug.log* -**yarn-error.log* -**yarn.lock +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +# End of https://www.gitignore.io/api/macos,python,visualstudiocode \ No newline at end of file From 13d16ec4e305da1887469a24c67ba5ab48daee11 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Wed, 24 Jun 2020 21:12:22 -0700 Subject: [PATCH 02/30] Swift to iOS gitignore --- .gitignore | 245 ++++++++++++++++++++++++++++------------------------- 1 file changed, 128 insertions(+), 117 deletions(-) diff --git a/.gitignore b/.gitignore index 17211fba2..c5aedda4e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,38 @@ -# Created by https://www.gitignore.io/api/macos,python,visualstudiocode -# Edit at https://www.gitignore.io/?templates=macos,python,visualstudiocode + +# Created by https://www.gitignore.io/api/swift,linux,xcode,macos,carthage,cocoapods +# Edit at https://www.gitignore.io/?templates=swift,linux,xcode,macos,carthage,cocoapods + +### Carthage ### +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +### CocoaPods ### +## CocoaPods GitIgnore Template + +# CocoaPods - Only use to conserve bandwidth / Save time on Pushing +# - Also handy if you have a large number of dependant pods +# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE +Pods/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* ### macOS ### # General @@ -30,120 +62,99 @@ Network Trash Folder Temporary Items .apdisk -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so +### Swift ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore -# Distribution / packaging -.Python +## Build generated build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# pyenv -.python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -### VisualStudioCode Patch ### -# Ignore all local history of files -.history - -# End of https://www.gitignore.io/api/macos,python,visualstudiocode \ No newline at end of file +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +.build/ + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +### Xcode ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) + +## Xcode Patch +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno + +### Xcode Patch ### +**/xcshareddata/WorkspaceSettings.xcsettings + +# End of https://www.gitignore.io/api/swift,linux,xcode,macos,carthage,cocoapods From e17f032115802d974b5da5c6c59dad80c22c3fd7 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Wed, 24 Jun 2020 21:23:34 -0700 Subject: [PATCH 03/30] Base Project --- .../Game of Life.xcodeproj/project.pbxproj | 343 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + Game of Life/Game of Life/AppDelegate.swift | 37 ++ .../AppIcon.appiconset/Contents.json | 98 +++++ .../Assets.xcassets/Contents.json | 6 + .../Base.lproj/LaunchScreen.storyboard | 25 ++ .../Game of Life/Base.lproj/Main.storyboard | 24 ++ Game of Life/Game of Life/Info.plist | 64 ++++ Game of Life/Game of Life/SceneDelegate.swift | 53 +++ .../Game of Life/ViewController.swift | 20 + 11 files changed, 685 insertions(+) create mode 100644 Game of Life/Game of Life.xcodeproj/project.pbxproj create mode 100644 Game of Life/Game of Life.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Game of Life/Game of Life.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Game of Life/Game of Life/AppDelegate.swift create mode 100644 Game of Life/Game of Life/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Game of Life/Game of Life/Assets.xcassets/Contents.json create mode 100644 Game of Life/Game of Life/Base.lproj/LaunchScreen.storyboard create mode 100644 Game of Life/Game of Life/Base.lproj/Main.storyboard create mode 100644 Game of Life/Game of Life/Info.plist create mode 100644 Game of Life/Game of Life/SceneDelegate.swift create mode 100644 Game of Life/Game of Life/ViewController.swift diff --git a/Game of Life/Game of Life.xcodeproj/project.pbxproj b/Game of Life/Game of Life.xcodeproj/project.pbxproj new file mode 100644 index 000000000..91f3d78ef --- /dev/null +++ b/Game of Life/Game of Life.xcodeproj/project.pbxproj @@ -0,0 +1,343 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 92841AD024A45E1700C7B39F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841ACF24A45E1700C7B39F /* AppDelegate.swift */; }; + 92841AD224A45E1700C7B39F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AD124A45E1700C7B39F /* SceneDelegate.swift */; }; + 92841AD424A45E1700C7B39F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AD324A45E1700C7B39F /* ViewController.swift */; }; + 92841AD724A45E1700C7B39F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92841AD524A45E1700C7B39F /* Main.storyboard */; }; + 92841AD924A45E1B00C7B39F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92841AD824A45E1B00C7B39F /* Assets.xcassets */; }; + 92841ADC24A45E1B00C7B39F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92841ADA24A45E1B00C7B39F /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 92841ACC24A45E1700C7B39F /* Game of Life.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Game of Life.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 92841ACF24A45E1700C7B39F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 92841AD124A45E1700C7B39F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 92841AD324A45E1700C7B39F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 92841AD624A45E1700C7B39F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 92841AD824A45E1B00C7B39F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 92841ADB24A45E1B00C7B39F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 92841ADD24A45E1B00C7B39F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 92841AC924A45E1700C7B39F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 92841AC324A45E1700C7B39F = { + isa = PBXGroup; + children = ( + 92841ACE24A45E1700C7B39F /* Game of Life */, + 92841ACD24A45E1700C7B39F /* Products */, + ); + sourceTree = ""; + }; + 92841ACD24A45E1700C7B39F /* Products */ = { + isa = PBXGroup; + children = ( + 92841ACC24A45E1700C7B39F /* Game of Life.app */, + ); + name = Products; + sourceTree = ""; + }; + 92841ACE24A45E1700C7B39F /* Game of Life */ = { + isa = PBXGroup; + children = ( + 92841ACF24A45E1700C7B39F /* AppDelegate.swift */, + 92841AD124A45E1700C7B39F /* SceneDelegate.swift */, + 92841AD324A45E1700C7B39F /* ViewController.swift */, + 92841AD524A45E1700C7B39F /* Main.storyboard */, + 92841AD824A45E1B00C7B39F /* Assets.xcassets */, + 92841ADA24A45E1B00C7B39F /* LaunchScreen.storyboard */, + 92841ADD24A45E1B00C7B39F /* Info.plist */, + ); + path = "Game of Life"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 92841ACB24A45E1700C7B39F /* Game of Life */ = { + isa = PBXNativeTarget; + buildConfigurationList = 92841AE024A45E1B00C7B39F /* Build configuration list for PBXNativeTarget "Game of Life" */; + buildPhases = ( + 92841AC824A45E1700C7B39F /* Sources */, + 92841AC924A45E1700C7B39F /* Frameworks */, + 92841ACA24A45E1700C7B39F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Game of Life"; + productName = "Game of Life"; + productReference = 92841ACC24A45E1700C7B39F /* Game of Life.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 92841AC424A45E1700C7B39F /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1150; + LastUpgradeCheck = 1150; + ORGANIZATIONNAME = "Mark Gerrior"; + TargetAttributes = { + 92841ACB24A45E1700C7B39F = { + CreatedOnToolsVersion = 11.5; + }; + }; + }; + buildConfigurationList = 92841AC724A45E1700C7B39F /* Build configuration list for PBXProject "Game of Life" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 92841AC324A45E1700C7B39F; + productRefGroup = 92841ACD24A45E1700C7B39F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 92841ACB24A45E1700C7B39F /* Game of Life */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 92841ACA24A45E1700C7B39F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 92841ADC24A45E1B00C7B39F /* LaunchScreen.storyboard in Resources */, + 92841AD924A45E1B00C7B39F /* Assets.xcassets in Resources */, + 92841AD724A45E1700C7B39F /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 92841AC824A45E1700C7B39F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 92841AD424A45E1700C7B39F /* ViewController.swift in Sources */, + 92841AD024A45E1700C7B39F /* AppDelegate.swift in Sources */, + 92841AD224A45E1700C7B39F /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 92841AD524A45E1700C7B39F /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 92841AD624A45E1700C7B39F /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 92841ADA24A45E1B00C7B39F /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 92841ADB24A45E1B00C7B39F /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 92841ADE24A45E1B00C7B39F /* 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 = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 92841ADF24A45E1B00C7B39F /* 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_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 92841AE124A45E1B00C7B39F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4ZDYKHFRDV; + INFOPLIST_FILE = "Game of Life/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.gerrior.Game-of-Life"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 92841AE224A45E1B00C7B39F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4ZDYKHFRDV; + INFOPLIST_FILE = "Game of Life/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.gerrior.Game-of-Life"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 92841AC724A45E1700C7B39F /* Build configuration list for PBXProject "Game of Life" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 92841ADE24A45E1B00C7B39F /* Debug */, + 92841ADF24A45E1B00C7B39F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 92841AE024A45E1B00C7B39F /* Build configuration list for PBXNativeTarget "Game of Life" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 92841AE124A45E1B00C7B39F /* Debug */, + 92841AE224A45E1B00C7B39F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 92841AC424A45E1700C7B39F /* Project object */; +} diff --git a/Game of Life/Game of Life.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Game of Life/Game of Life.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..57c745c45 --- /dev/null +++ b/Game of Life/Game of Life.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Game of Life/Game of Life.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Game of Life/Game of Life.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Game of Life/Game of Life.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Game of Life/Game of Life/AppDelegate.swift b/Game of Life/Game of Life/AppDelegate.swift new file mode 100644 index 000000000..1ea36bcc2 --- /dev/null +++ b/Game of Life/Game of Life/AppDelegate.swift @@ -0,0 +1,37 @@ +// +// AppDelegate.swift +// Game of Life +// +// Created by Mark Gerrior on 6/24/20. +// Copyright © 2020 Mark Gerrior. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/Game of Life/Game of Life/Assets.xcassets/AppIcon.appiconset/Contents.json b/Game of Life/Game of Life/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..9221b9bb1 --- /dev/null +++ b/Game of Life/Game of Life/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Game of Life/Game of Life/Assets.xcassets/Contents.json b/Game of Life/Game of Life/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Game of Life/Game of Life/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Game of Life/Game of Life/Base.lproj/LaunchScreen.storyboard b/Game of Life/Game of Life/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..865e9329f --- /dev/null +++ b/Game of Life/Game of Life/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Game of Life/Game of Life/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Base.lproj/Main.storyboard new file mode 100644 index 000000000..25a763858 --- /dev/null +++ b/Game of Life/Game of Life/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Game of Life/Game of Life/Info.plist b/Game of Life/Game of Life/Info.plist new file mode 100644 index 000000000..2a3483c0d --- /dev/null +++ b/Game of Life/Game of Life/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Game of Life/Game of Life/SceneDelegate.swift b/Game of Life/Game of Life/SceneDelegate.swift new file mode 100644 index 000000000..b775262b0 --- /dev/null +++ b/Game of Life/Game of Life/SceneDelegate.swift @@ -0,0 +1,53 @@ +// +// SceneDelegate.swift +// Game of Life +// +// Created by Mark Gerrior on 6/24/20. +// Copyright © 2020 Mark Gerrior. All rights reserved. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/Game of Life/Game of Life/ViewController.swift b/Game of Life/Game of Life/ViewController.swift new file mode 100644 index 000000000..016f71eea --- /dev/null +++ b/Game of Life/Game of Life/ViewController.swift @@ -0,0 +1,20 @@ +// +// ViewController.swift +// Game of Life +// +// Created by Mark Gerrior on 6/24/20. +// Copyright © 2020 Mark Gerrior. All rights reserved. +// + +import UIKit + +class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + + +} + From d9210fc0f4285042895a4f4d256f3db455728687 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Wed, 24 Jun 2020 21:26:04 -0700 Subject: [PATCH 04/30] Project Organization --- .../Game of Life.xcodeproj/project.pbxproj | 30 ++++++++++++++----- .../{ => Resources}/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../Game of Life/{ => Resources}/Info.plist | 0 .../{ => Resources}/SceneDelegate.swift | 0 .../Base.lproj/LaunchScreen.storyboard | 0 .../Base.lproj/Main.storyboard | 0 8 files changed, 23 insertions(+), 7 deletions(-) rename Game of Life/Game of Life/{ => Resources}/AppDelegate.swift (100%) rename Game of Life/Game of Life/{ => Resources}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename Game of Life/Game of Life/{ => Resources}/Assets.xcassets/Contents.json (100%) rename Game of Life/Game of Life/{ => Resources}/Info.plist (100%) rename Game of Life/Game of Life/{ => Resources}/SceneDelegate.swift (100%) rename Game of Life/Game of Life/{ => Storyboards}/Base.lproj/LaunchScreen.storyboard (100%) rename Game of Life/Game of Life/{ => Storyboards}/Base.lproj/Main.storyboard (100%) diff --git a/Game of Life/Game of Life.xcodeproj/project.pbxproj b/Game of Life/Game of Life.xcodeproj/project.pbxproj index 91f3d78ef..83975fcd6 100644 --- a/Game of Life/Game of Life.xcodeproj/project.pbxproj +++ b/Game of Life/Game of Life.xcodeproj/project.pbxproj @@ -56,15 +56,31 @@ 92841ACE24A45E1700C7B39F /* Game of Life */ = { isa = PBXGroup; children = ( - 92841ACF24A45E1700C7B39F /* AppDelegate.swift */, - 92841AD124A45E1700C7B39F /* SceneDelegate.swift */, + 92841AE324A45E7E00C7B39F /* Resources */, + 92841AE424A45E8D00C7B39F /* Storyboards */, 92841AD324A45E1700C7B39F /* ViewController.swift */, - 92841AD524A45E1700C7B39F /* Main.storyboard */, + ); + path = "Game of Life"; + sourceTree = ""; + }; + 92841AE324A45E7E00C7B39F /* Resources */ = { + isa = PBXGroup; + children = ( + 92841ACF24A45E1700C7B39F /* AppDelegate.swift */, 92841AD824A45E1B00C7B39F /* Assets.xcassets */, - 92841ADA24A45E1B00C7B39F /* LaunchScreen.storyboard */, 92841ADD24A45E1B00C7B39F /* Info.plist */, + 92841AD124A45E1700C7B39F /* SceneDelegate.swift */, ); - path = "Game of Life"; + path = Resources; + sourceTree = ""; + }; + 92841AE424A45E8D00C7B39F /* Storyboards */ = { + isa = PBXGroup; + children = ( + 92841ADA24A45E1B00C7B39F /* LaunchScreen.storyboard */, + 92841AD524A45E1700C7B39F /* Main.storyboard */, + ); + path = Storyboards; sourceTree = ""; }; /* End PBXGroup section */ @@ -286,7 +302,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 4ZDYKHFRDV; - INFOPLIST_FILE = "Game of Life/Info.plist"; + INFOPLIST_FILE = "Game of Life/Resources/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -304,7 +320,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 4ZDYKHFRDV; - INFOPLIST_FILE = "Game of Life/Info.plist"; + INFOPLIST_FILE = "Game of Life/Resources/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/Game of Life/Game of Life/AppDelegate.swift b/Game of Life/Game of Life/Resources/AppDelegate.swift similarity index 100% rename from Game of Life/Game of Life/AppDelegate.swift rename to Game of Life/Game of Life/Resources/AppDelegate.swift diff --git a/Game of Life/Game of Life/Assets.xcassets/AppIcon.appiconset/Contents.json b/Game of Life/Game of Life/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Game of Life/Game of Life/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Game of Life/Game of Life/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Game of Life/Game of Life/Assets.xcassets/Contents.json b/Game of Life/Game of Life/Resources/Assets.xcassets/Contents.json similarity index 100% rename from Game of Life/Game of Life/Assets.xcassets/Contents.json rename to Game of Life/Game of Life/Resources/Assets.xcassets/Contents.json diff --git a/Game of Life/Game of Life/Info.plist b/Game of Life/Game of Life/Resources/Info.plist similarity index 100% rename from Game of Life/Game of Life/Info.plist rename to Game of Life/Game of Life/Resources/Info.plist diff --git a/Game of Life/Game of Life/SceneDelegate.swift b/Game of Life/Game of Life/Resources/SceneDelegate.swift similarity index 100% rename from Game of Life/Game of Life/SceneDelegate.swift rename to Game of Life/Game of Life/Resources/SceneDelegate.swift diff --git a/Game of Life/Game of Life/Base.lproj/LaunchScreen.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from Game of Life/Game of Life/Base.lproj/LaunchScreen.storyboard rename to Game of Life/Game of Life/Storyboards/Base.lproj/LaunchScreen.storyboard diff --git a/Game of Life/Game of Life/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard similarity index 100% rename from Game of Life/Game of Life/Base.lproj/Main.storyboard rename to Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard From 5ac88ae89e27ac0c10ef6408cb8c9c4924c154e0 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Wed, 24 Jun 2020 22:08:29 -0700 Subject: [PATCH 05/30] Some intial UI work --- .../Storyboards/Base.lproj/Main.storyboard | 125 +++++++++++++++++- 1 file changed, 119 insertions(+), 6 deletions(-) diff --git a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard index 25a763858..5d2154518 100644 --- a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard +++ b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard @@ -1,24 +1,137 @@ - + + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
 +2. Any live cell with two or three live neighbours lives on to the next generation. +
3. Any live cell with more than three live neighbours dies, as if by overpopulation. +
4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From aac37e9dcbb30278691fb3be6847ff0a8f81a7ac Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Thu, 25 Jun 2020 10:42:55 -0700 Subject: [PATCH 06/30] Got Rules page working --- .../Game of Life.xcodeproj/project.pbxproj | 4 ++++ .../Game of Life/RulesViewController.swift | 22 +++++++++++++++++ .../Storyboards/Base.lproj/Main.storyboard | 24 +++++++++++++++---- 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 Game of Life/Game of Life/RulesViewController.swift diff --git a/Game of Life/Game of Life.xcodeproj/project.pbxproj b/Game of Life/Game of Life.xcodeproj/project.pbxproj index 83975fcd6..6e014c0a3 100644 --- a/Game of Life/Game of Life.xcodeproj/project.pbxproj +++ b/Game of Life/Game of Life.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 92841AD724A45E1700C7B39F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92841AD524A45E1700C7B39F /* Main.storyboard */; }; 92841AD924A45E1B00C7B39F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92841AD824A45E1B00C7B39F /* Assets.xcassets */; }; 92841ADC24A45E1B00C7B39F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92841ADA24A45E1B00C7B39F /* LaunchScreen.storyboard */; }; + 92841AE624A50F2800C7B39F /* RulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AE524A50F2800C7B39F /* RulesViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -24,6 +25,7 @@ 92841AD824A45E1B00C7B39F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 92841ADB24A45E1B00C7B39F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 92841ADD24A45E1B00C7B39F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 92841AE524A50F2800C7B39F /* RulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RulesViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -59,6 +61,7 @@ 92841AE324A45E7E00C7B39F /* Resources */, 92841AE424A45E8D00C7B39F /* Storyboards */, 92841AD324A45E1700C7B39F /* ViewController.swift */, + 92841AE524A50F2800C7B39F /* RulesViewController.swift */, ); path = "Game of Life"; sourceTree = ""; @@ -156,6 +159,7 @@ files = ( 92841AD424A45E1700C7B39F /* ViewController.swift in Sources */, 92841AD024A45E1700C7B39F /* AppDelegate.swift in Sources */, + 92841AE624A50F2800C7B39F /* RulesViewController.swift in Sources */, 92841AD224A45E1700C7B39F /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Game of Life/Game of Life/RulesViewController.swift b/Game of Life/Game of Life/RulesViewController.swift new file mode 100644 index 000000000..5aad7e68e --- /dev/null +++ b/Game of Life/Game of Life/RulesViewController.swift @@ -0,0 +1,22 @@ +// +// RulesViewController.swift +// Game of Life +// +// Created by Mark Gerrior on 6/25/20. +// Copyright © 2020 Mark Gerrior. All rights reserved. +// + +import UIKit + +class RulesViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + @IBAction func okButton(_ sender: Any) { + dismiss(animated: true, completion: nil) + } +} diff --git a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard index 5d2154518..b66da6cdb 100644 --- a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard +++ b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard @@ -29,7 +29,7 @@ - + - + 1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
 2. Any live cell with two or three live neighbours lives on to the next generation. @@ -91,6 +95,12 @@ + @@ -98,13 +108,17 @@ - + + + + + From e2596a65ab830194d91d287310db58f468b0ff5d Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Thu, 25 Jun 2020 11:40:44 -0700 Subject: [PATCH 07/30] Wired up Example button --- .../Game of Life.xcodeproj/project.pbxproj | 18 +++++- Game of Life/Game of Life/Models/Cell.swift | 26 ++++++++ .../Game of Life/Models/GameGrid.swift | 59 +++++++++++++++++++ .../Storyboards/Base.lproj/Main.storyboard | 48 +++++++++++++++ .../Game of Life/ViewController.swift | 46 ++++++++++++++- 5 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 Game of Life/Game of Life/Models/Cell.swift create mode 100644 Game of Life/Game of Life/Models/GameGrid.swift diff --git a/Game of Life/Game of Life.xcodeproj/project.pbxproj b/Game of Life/Game of Life.xcodeproj/project.pbxproj index 6e014c0a3..27d2ac11d 100644 --- a/Game of Life/Game of Life.xcodeproj/project.pbxproj +++ b/Game of Life/Game of Life.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 92841AD924A45E1B00C7B39F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92841AD824A45E1B00C7B39F /* Assets.xcassets */; }; 92841ADC24A45E1B00C7B39F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92841ADA24A45E1B00C7B39F /* LaunchScreen.storyboard */; }; 92841AE624A50F2800C7B39F /* RulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AE524A50F2800C7B39F /* RulesViewController.swift */; }; + 92841AE924A51A1100C7B39F /* GameGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AE824A51A1100C7B39F /* GameGrid.swift */; }; + 92841AEB24A51AB600C7B39F /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AEA24A51AB600C7B39F /* Cell.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -26,6 +28,8 @@ 92841ADB24A45E1B00C7B39F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 92841ADD24A45E1B00C7B39F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 92841AE524A50F2800C7B39F /* RulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RulesViewController.swift; sourceTree = ""; }; + 92841AE824A51A1100C7B39F /* GameGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameGrid.swift; sourceTree = ""; }; + 92841AEA24A51AB600C7B39F /* Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cell.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -58,10 +62,11 @@ 92841ACE24A45E1700C7B39F /* Game of Life */ = { isa = PBXGroup; children = ( + 92841AE724A519DA00C7B39F /* Models */, 92841AE324A45E7E00C7B39F /* Resources */, + 92841AE524A50F2800C7B39F /* RulesViewController.swift */, 92841AE424A45E8D00C7B39F /* Storyboards */, 92841AD324A45E1700C7B39F /* ViewController.swift */, - 92841AE524A50F2800C7B39F /* RulesViewController.swift */, ); path = "Game of Life"; sourceTree = ""; @@ -86,6 +91,15 @@ path = Storyboards; sourceTree = ""; }; + 92841AE724A519DA00C7B39F /* Models */ = { + isa = PBXGroup; + children = ( + 92841AEA24A51AB600C7B39F /* Cell.swift */, + 92841AE824A51A1100C7B39F /* GameGrid.swift */, + ); + path = Models; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -159,8 +173,10 @@ files = ( 92841AD424A45E1700C7B39F /* ViewController.swift in Sources */, 92841AD024A45E1700C7B39F /* AppDelegate.swift in Sources */, + 92841AE924A51A1100C7B39F /* GameGrid.swift in Sources */, 92841AE624A50F2800C7B39F /* RulesViewController.swift in Sources */, 92841AD224A45E1700C7B39F /* SceneDelegate.swift in Sources */, + 92841AEB24A51AB600C7B39F /* Cell.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Game of Life/Game of Life/Models/Cell.swift b/Game of Life/Game of Life/Models/Cell.swift new file mode 100644 index 000000000..cb145ae50 --- /dev/null +++ b/Game of Life/Game of Life/Models/Cell.swift @@ -0,0 +1,26 @@ +// +// Cell.swift +// Game of Life +// +// Created by Mark Gerrior on 6/25/20. +// Copyright © 2020 Mark Gerrior. All rights reserved. +// + +import Foundation + +public enum State { + case dead + case alive +} + +public class Cell: NSObject { + public let x: Int + public let y: Int + public var state: State + + public init(x: Int, y: Int, state: State = .dead) { + self.x = x + self.y = y + self.state = state + } +} diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift new file mode 100644 index 000000000..5afe14f92 --- /dev/null +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -0,0 +1,59 @@ +// +// GameGrid.swift +// Game of Life +// +// Created by Mark Gerrior on 6/25/20. +// Copyright © 2020 Mark Gerrior. All rights reserved. +// + +import UIKit + +public enum Examples { + // Still Lifes + case behive + + // Oscillators + case blinker + case toad + case beacon + case pulsar + case pentadecathlon + + // Spaceships + case glider +} + +class GameGrid: NSObject { + let size: Int + var cells: [Cell] = [] + + var generation = 0 + var population: Int { + cells.filter{ $0.state == .alive }.count + } + + public init(size: Int) { + self.size = size + + // Create grid + for x in 0.. + + + + + + + + + + + + @@ -58,11 +99,18 @@ + + + + + + + diff --git a/Game of Life/Game of Life/ViewController.swift b/Game of Life/Game of Life/ViewController.swift index 016f71eea..e5eec465d 100644 --- a/Game of Life/Game of Life/ViewController.swift +++ b/Game of Life/Game of Life/ViewController.swift @@ -10,11 +10,55 @@ import UIKit class ViewController: UIViewController { + // MARK: - Properites + + // MARK: - Actions + + @IBAction func playPausebutton(_ sender: Any) { + } + + @IBAction func stepButton(_ sender: UIButton) { + } + + @IBAction func clearButton(_ sender: UIButton) { + } + + @IBAction func presetsButton(_ sender: Any) { + let alertController = UIAlertController(title: "Example Patterns", message: "Select a common Game of Life pattern.", preferredStyle: .alert) + + alertController.addAction(UIAlertAction(title: "Blinker", style: .default) { (_) in + print("Blinker") + }) + + alertController.addAction(UIAlertAction(title: "Toad", style: .default) { (_) in + print("Toad") + }) + + alertController.addAction(UIAlertAction(title: "Beacon", style: .default) { (_) in + print("Beacon") + }) + + alertController.addAction(UIAlertAction(title: "Glider", style: .default) { (_) in + print("Glider") + }) + + alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) + + present(alertController, animated: true, completion: nil) + } + + // MARK: - Outlets + + @IBOutlet weak var generationLabel: UILabel! + @IBOutlet weak var populationLabel: UILabel! + + // MARK: - View Lifecycle + override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } - + // MARK: - Private } From 162b071f3df1f2abb496f955ed76e48114eb6799 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Thu, 25 Jun 2020 12:00:10 -0700 Subject: [PATCH 08/30] Wired up clear button. Made pattern selection more real. --- .../Game of Life/Models/GameGrid.swift | 22 ++++++++++++++++++- .../Game of Life/ViewController.swift | 10 +++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift index 5afe14f92..3027b22b1 100644 --- a/Game of Life/Game of Life/Models/GameGrid.swift +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -8,7 +8,7 @@ import UIKit -public enum Examples { +public enum Patterns { // Still Lifes case behive @@ -56,4 +56,24 @@ class GameGrid: NSObject { cell.state = .dead } } + + public func useExamplePattern(pattern: Patterns = .glider) { + clearGrid() + switch pattern { + case .behive: + print(pattern) + case .blinker: + print(pattern) + case .toad: + print(pattern) + case .beacon: + print(pattern) + case .pulsar: + print(pattern) + case .pentadecathlon: + print(pattern) + case .glider: + print(pattern) + } + } } diff --git a/Game of Life/Game of Life/ViewController.swift b/Game of Life/Game of Life/ViewController.swift index e5eec465d..a63a2bdea 100644 --- a/Game of Life/Game of Life/ViewController.swift +++ b/Game of Life/Game of Life/ViewController.swift @@ -11,6 +11,7 @@ import UIKit class ViewController: UIViewController { // MARK: - Properites + var gameGrid = GameGrid(size: 25) // MARK: - Actions @@ -21,25 +22,26 @@ class ViewController: UIViewController { } @IBAction func clearButton(_ sender: UIButton) { + gameGrid.clearGrid() } @IBAction func presetsButton(_ sender: Any) { let alertController = UIAlertController(title: "Example Patterns", message: "Select a common Game of Life pattern.", preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "Blinker", style: .default) { (_) in - print("Blinker") + self.gameGrid.useExamplePattern(pattern: .blinker) }) alertController.addAction(UIAlertAction(title: "Toad", style: .default) { (_) in - print("Toad") + self.gameGrid.useExamplePattern(pattern: .toad) }) alertController.addAction(UIAlertAction(title: "Beacon", style: .default) { (_) in - print("Beacon") + self.gameGrid.useExamplePattern(pattern: .beacon) }) alertController.addAction(UIAlertAction(title: "Glider", style: .default) { (_) in - print("Glider") + self.gameGrid.useExamplePattern(pattern: .glider) }) alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) From 3a7f58f27238acdced7da263219654e6129485db Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Thu, 25 Jun 2020 12:50:01 -0700 Subject: [PATCH 09/30] Flushed out example pattern code --- .../Game of Life/Models/GameGrid.swift | 151 +++++++++++++++++- .../Game of Life/ViewController.swift | 14 +- 2 files changed, 157 insertions(+), 8 deletions(-) diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift index 3027b22b1..dce1a22e4 100644 --- a/Game of Life/Game of Life/Models/GameGrid.swift +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -58,22 +58,159 @@ class GameGrid: NSObject { } public func useExamplePattern(pattern: Patterns = .glider) { + print(pattern) + clearGrid() + switch pattern { case .behive: - print(pattern) + cellAt(x: 3, y: 2).state = .alive + cellAt(x: 4, y: 2).state = .alive + + cellAt(x: 2, y: 3).state = .alive + cellAt(x: 5, y: 3).state = .alive + + cellAt(x: 3, y: 4).state = .alive + cellAt(x: 4, y: 4).state = .alive + case .blinker: - print(pattern) + cellAt(x: 3, y: 2).state = .alive + cellAt(x: 4, y: 2).state = .alive + cellAt(x: 5, y: 2).state = .alive + case .toad: - print(pattern) + cellAt(x: 4, y: 3).state = .alive + cellAt(x: 5, y: 3).state = .alive + cellAt(x: 6, y: 3).state = .alive + + cellAt(x: 3, y: 4).state = .alive + cellAt(x: 4, y: 4).state = .alive + cellAt(x: 5, y: 4).state = .alive + case .beacon: - print(pattern) + cellAt(x: 2, y: 2).state = .alive + cellAt(x: 3, y: 2).state = .alive + cellAt(x: 2, y: 3).state = .alive + + cellAt(x: 5, y: 4).state = .alive + cellAt(x: 4, y: 5).state = .alive + cellAt(x: 5, y: 5).state = .alive + case .pulsar: - print(pattern) + // Row 1 + cellAt(x: 6, y: 2).state = .alive + cellAt(x: 6, y: 3).state = .alive + cellAt(x: 6, y: 4).state = .alive + cellAt(x: 7, y: 4).state = .alive + + cellAt(x: 12, y: 2).state = .alive + cellAt(x: 12, y: 3).state = .alive + cellAt(x: 12, y: 4).state = .alive + cellAt(x: 11, y: 4).state = .alive + + // Row 2 + cellAt(x: 2, y: 6).state = .alive + cellAt(x: 3, y: 6).state = .alive + cellAt(x: 4, y: 6).state = .alive + cellAt(x: 4, y: 7).state = .alive + + cellAt(x: 7, y: 6).state = .alive + cellAt(x: 8, y: 6).state = .alive + cellAt(x: 8, y: 7).state = .alive + cellAt(x: 6, y: 7).state = .alive + cellAt(x: 6, y: 8).state = .alive + cellAt(x: 7, y: 8).state = .alive + + cellAt(x: 10, y: 6).state = .alive + cellAt(x: 11, y: 7).state = .alive + cellAt(x: 10, y: 6).state = .alive + cellAt(x: 12, y: 7).state = .alive + cellAt(x: 11, y: 8).state = .alive + cellAt(x: 12, y: 8).state = .alive + + cellAt(x: 14, y: 6).state = .alive + cellAt(x: 15, y: 6).state = .alive + cellAt(x: 16, y: 6).state = .alive + cellAt(x: 14, y: 7).state = .alive + + // Row 3 + cellAt(x: 2, y: 12).state = .alive + cellAt(x: 3, y: 12).state = .alive + cellAt(x: 4, y: 12).state = .alive + cellAt(x: 4, y: 11).state = .alive + + cellAt(x: 6, y: 10).state = .alive + cellAt(x: 7, y: 10).state = .alive + cellAt(x: 6, y: 11).state = .alive + cellAt(x: 8, y: 11).state = .alive + cellAt(x: 7, y: 12).state = .alive + cellAt(x: 8, y: 12).state = .alive + + cellAt(x: 11, y: 10).state = .alive + cellAt(x: 12, y: 10).state = .alive + cellAt(x: 12, y: 11).state = .alive + cellAt(x: 10, y: 11).state = .alive + cellAt(x: 10, y: 12).state = .alive + cellAt(x: 11, y: 12).state = .alive + + cellAt(x: 14, y: 11).state = .alive + cellAt(x: 14, y: 12).state = .alive + cellAt(x: 15, y: 12).state = .alive + cellAt(x: 16, y: 12).state = .alive + + // Row 4 + cellAt(x: 6, y: 14).state = .alive + cellAt(x: 6, y: 15).state = .alive + cellAt(x: 6, y: 16).state = .alive + cellAt(x: 7, y: 14).state = .alive + + cellAt(x: 12, y: 14).state = .alive + cellAt(x: 12, y: 15).state = .alive + cellAt(x: 12, y: 16).state = .alive + cellAt(x: 11, y: 14).state = .alive + case .pentadecathlon: - print(pattern) + // Object 1 + cellAt(x: 5, y: 4).state = .alive + cellAt(x: 6, y: 4).state = .alive + cellAt(x: 7, y: 4).state = .alive + cellAt(x: 6, y: 5).state = .alive + cellAt(x: 6, y: 6).state = .alive + cellAt(x: 5, y: 7).state = .alive + cellAt(x: 6, y: 7).state = .alive + cellAt(x: 7, y: 7).state = .alive + + // Object 2 + cellAt(x: 5, y: 9).state = .alive + cellAt(x: 6, y: 9).state = .alive + cellAt(x: 7, y: 9).state = .alive + cellAt(x: 5, y: 10).state = .alive + cellAt(x: 6, y: 10).state = .alive + cellAt(x: 7, y: 10).state = .alive + + // Object 3 + cellAt(x: 5, y: 12).state = .alive + cellAt(x: 6, y: 12).state = .alive + cellAt(x: 7, y: 12).state = .alive + cellAt(x: 6, y: 13).state = .alive + cellAt(x: 6, y: 14).state = .alive + cellAt(x: 5, y: 15).state = .alive + cellAt(x: 6, y: 15).state = .alive + cellAt(x: 7, y: 15).state = .alive + case .glider: - print(pattern) + cellAt(x: 3, y: 2).state = .alive + cellAt(x: 4, y: 3).state = .alive + cellAt(x: 4, y: 4).state = .alive + cellAt(x: 3, y: 4).state = .alive + cellAt(x: 2, y: 4).state = .alive } } + + func cellAt(x: Int, y: Int) -> Cell { + var absolutePosition: Int + absolutePosition = x + ((y / size) * size) + (y % size) + return cells[absolutePosition] + } + } diff --git a/Game of Life/Game of Life/ViewController.swift b/Game of Life/Game of Life/ViewController.swift index a63a2bdea..dca4a299d 100644 --- a/Game of Life/Game of Life/ViewController.swift +++ b/Game of Life/Game of Life/ViewController.swift @@ -26,7 +26,11 @@ class ViewController: UIViewController { } @IBAction func presetsButton(_ sender: Any) { - let alertController = UIAlertController(title: "Example Patterns", message: "Select a common Game of Life pattern.", preferredStyle: .alert) + let alertController = UIAlertController(title: "Example Patterns", message: "Select a Game of Life pattern:", preferredStyle: .alert) + + alertController.addAction(UIAlertAction(title: "Behive", style: .default) { (_) in + self.gameGrid.useExamplePattern(pattern: .behive) + }) alertController.addAction(UIAlertAction(title: "Blinker", style: .default) { (_) in self.gameGrid.useExamplePattern(pattern: .blinker) @@ -40,6 +44,14 @@ class ViewController: UIViewController { self.gameGrid.useExamplePattern(pattern: .beacon) }) + alertController.addAction(UIAlertAction(title: "Pulsar", style: .default) { (_) in + self.gameGrid.useExamplePattern(pattern: .pulsar) + }) + + alertController.addAction(UIAlertAction(title: "Pentadecathlon", style: .default) { (_) in + self.gameGrid.useExamplePattern(pattern: .pentadecathlon) + }) + alertController.addAction(UIAlertAction(title: "Glider", style: .default) { (_) in self.gameGrid.useExamplePattern(pattern: .glider) }) From e4a2285a428b67bd7f17719b0a3a9683c078be91 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Thu, 25 Jun 2020 13:13:03 -0700 Subject: [PATCH 10/30] Organization --- Game of Life/Game of Life.xcodeproj/project.pbxproj | 12 ++++++++++-- .../{ => View Controllers}/RulesViewController.swift | 0 .../{ => View Controllers}/ViewController.swift | 0 3 files changed, 10 insertions(+), 2 deletions(-) rename Game of Life/Game of Life/{ => View Controllers}/RulesViewController.swift (100%) rename Game of Life/Game of Life/{ => View Controllers}/ViewController.swift (100%) diff --git a/Game of Life/Game of Life.xcodeproj/project.pbxproj b/Game of Life/Game of Life.xcodeproj/project.pbxproj index 27d2ac11d..72249d4f1 100644 --- a/Game of Life/Game of Life.xcodeproj/project.pbxproj +++ b/Game of Life/Game of Life.xcodeproj/project.pbxproj @@ -64,9 +64,8 @@ children = ( 92841AE724A519DA00C7B39F /* Models */, 92841AE324A45E7E00C7B39F /* Resources */, - 92841AE524A50F2800C7B39F /* RulesViewController.swift */, 92841AE424A45E8D00C7B39F /* Storyboards */, - 92841AD324A45E1700C7B39F /* ViewController.swift */, + 92841AEC24A53CA600C7B39F /* View Controllers */, ); path = "Game of Life"; sourceTree = ""; @@ -100,6 +99,15 @@ path = Models; sourceTree = ""; }; + 92841AEC24A53CA600C7B39F /* View Controllers */ = { + isa = PBXGroup; + children = ( + 92841AE524A50F2800C7B39F /* RulesViewController.swift */, + 92841AD324A45E1700C7B39F /* ViewController.swift */, + ); + path = "View Controllers"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ diff --git a/Game of Life/Game of Life/RulesViewController.swift b/Game of Life/Game of Life/View Controllers/RulesViewController.swift similarity index 100% rename from Game of Life/Game of Life/RulesViewController.swift rename to Game of Life/Game of Life/View Controllers/RulesViewController.swift diff --git a/Game of Life/Game of Life/ViewController.swift b/Game of Life/Game of Life/View Controllers/ViewController.swift similarity index 100% rename from Game of Life/Game of Life/ViewController.swift rename to Game of Life/Game of Life/View Controllers/ViewController.swift From cc28a25b639a78f6b2925969fb9347fedae066f3 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Thu, 25 Jun 2020 13:14:36 -0700 Subject: [PATCH 11/30] Added custom GridView --- .../Game of Life.xcodeproj/project.pbxproj | 4 ++++ Game of Life/Game of Life/GridView.swift | 21 +++++++++++++++++++ .../Storyboards/Base.lproj/Main.storyboard | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 Game of Life/Game of Life/GridView.swift diff --git a/Game of Life/Game of Life.xcodeproj/project.pbxproj b/Game of Life/Game of Life.xcodeproj/project.pbxproj index 72249d4f1..f95c6f4f2 100644 --- a/Game of Life/Game of Life.xcodeproj/project.pbxproj +++ b/Game of Life/Game of Life.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 92841AE624A50F2800C7B39F /* RulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AE524A50F2800C7B39F /* RulesViewController.swift */; }; 92841AE924A51A1100C7B39F /* GameGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AE824A51A1100C7B39F /* GameGrid.swift */; }; 92841AEB24A51AB600C7B39F /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AEA24A51AB600C7B39F /* Cell.swift */; }; + 92841AEE24A53CE700C7B39F /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92841AED24A53CE700C7B39F /* GridView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -30,6 +31,7 @@ 92841AE524A50F2800C7B39F /* RulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RulesViewController.swift; sourceTree = ""; }; 92841AE824A51A1100C7B39F /* GameGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameGrid.swift; sourceTree = ""; }; 92841AEA24A51AB600C7B39F /* Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cell.swift; sourceTree = ""; }; + 92841AED24A53CE700C7B39F /* GridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,6 +64,7 @@ 92841ACE24A45E1700C7B39F /* Game of Life */ = { isa = PBXGroup; children = ( + 92841AED24A53CE700C7B39F /* GridView.swift */, 92841AE724A519DA00C7B39F /* Models */, 92841AE324A45E7E00C7B39F /* Resources */, 92841AE424A45E8D00C7B39F /* Storyboards */, @@ -182,6 +185,7 @@ 92841AD424A45E1700C7B39F /* ViewController.swift in Sources */, 92841AD024A45E1700C7B39F /* AppDelegate.swift in Sources */, 92841AE924A51A1100C7B39F /* GameGrid.swift in Sources */, + 92841AEE24A53CE700C7B39F /* GridView.swift in Sources */, 92841AE624A50F2800C7B39F /* RulesViewController.swift in Sources */, 92841AD224A45E1700C7B39F /* SceneDelegate.swift in Sources */, 92841AEB24A51AB600C7B39F /* Cell.swift in Sources */, diff --git a/Game of Life/Game of Life/GridView.swift b/Game of Life/Game of Life/GridView.swift new file mode 100644 index 000000000..e5aefdea7 --- /dev/null +++ b/Game of Life/Game of Life/GridView.swift @@ -0,0 +1,21 @@ +// +// GridView.swift +// Game of Life +// +// Created by Mark Gerrior on 6/25/20. +// Copyright © 2020 Mark Gerrior. All rights reserved. +// + +import UIKit + +class GridView: UIView { + + /* + // Only override draw() if you perform custom drawing. + // An empty implementation adversely affects performance during animation. + override func draw(_ rect: CGRect) { + // Drawing code + } + */ + +} diff --git a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard index cd27c7d95..eec7af0c2 100644 --- a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard +++ b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard @@ -15,7 +15,7 @@ - + From 4fda806c489ce2ad111850f1f48c4e47f17392c1 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 00:03:52 -0700 Subject: [PATCH 12/30] Buttons working and example patterns working. --- Game of Life/Game of Life/GridView.swift | 86 +++++++++++++++++-- .../Game of Life/Models/GameGrid.swift | 25 ++++-- .../Storyboards/Base.lproj/Main.storyboard | 7 +- .../View Controllers/ViewController.swift | 79 +++++++++++++---- 4 files changed, 165 insertions(+), 32 deletions(-) diff --git a/Game of Life/Game of Life/GridView.swift b/Game of Life/Game of Life/GridView.swift index e5aefdea7..3310a8df0 100644 --- a/Game of Life/Game of Life/GridView.swift +++ b/Game of Life/Game of Life/GridView.swift @@ -10,12 +10,88 @@ import UIKit class GridView: UIView { - /* - // Only override draw() if you perform custom drawing. - // An empty implementation adversely affects performance during animation. + // MARK: - Properties + var gameGrid = GameGrid(gridSize: 25) + private var cellSize: Int = 15 + private var timer: Timer? + + // MARK: - Actions + + // MARK: - Outlets + + // MARK: - Initialization + public convenience init(gridSize: Int, cellSize: Int) { + let frame = CGRect(x: 0, y: 0, width: cellSize * gridSize, height: cellSize * gridSize) + self.init(frame: frame) + self.gameGrid = GameGrid(gridSize: gridSize) + self.cellSize = cellSize + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + public override init(frame: CGRect) { + super.init(frame: frame) + } + override func draw(_ rect: CGRect) { - // Drawing code + let context = UIGraphicsGetCurrentContext() + context?.saveGState() + + for cell in gameGrid.cells { + let color = cell.state == .dead ? UIColor.white.cgColor : UIColor.systemTeal.cgColor + context?.setFillColor(color) + + let rect = CGRect(x: cell.x * cellSize, + y: cell.y * cellSize, + width: cellSize, + height: cellSize) + context?.addRect(rect) + context?.fill(rect) + } + + context?.restoreGState() + } + + // MARK: - Public Interface + + public func cancelTimer() { + timer?.invalidate() + timer = nil + } + + public func cellTapped(at index: Int) { + gameGrid.cellTapped(at: index) + setNeedsDisplay() } - */ + public func clearGrid() { + gameGrid.clearGrid() + setNeedsDisplay() + } + + @objc private func performGameTurn() { + self.gameGrid.performGameTurn() + self.setNeedsDisplay() + } + + public func start() { + timer = Timer.scheduledTimer(timeInterval: 0.25, + target: self, + selector: #selector(performGameTurn), + userInfo: nil, + repeats: true) + } + + public func step() { + gameGrid.performGameTurn() + setNeedsDisplay() + } + + public func useExamplePattern(pattern: Patterns) { + gameGrid.clearGrid() + gameGrid.useExamplePattern(pattern: pattern) + setNeedsDisplay() + } } diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift index dce1a22e4..09202fd3d 100644 --- a/Game of Life/Game of Life/Models/GameGrid.swift +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -32,8 +32,8 @@ class GameGrid: NSObject { cells.filter{ $0.state == .alive }.count } - public init(size: Int) { - self.size = size + public init(gridSize: Int) { + self.size = gridSize // Create grid for x in 0.. Cell { var absolutePosition: Int - absolutePosition = x + ((y / size) * size) + (y % size) + // 3, 2 on 25 x 25 grid + absolutePosition = ((x) * size) + y return cells[absolutePosition] } + func cellTapped(at index: Int) { + if cells[index].state == .alive { + cells[index].state = .dead + } else { + cells[index].state = .alive + } + // Recompute population + print("population = \(population)") + } + + func performGameTurn() { + generation += 1 + } + } diff --git a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard index eec7af0c2..210baf038 100644 --- a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard +++ b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard @@ -57,7 +57,7 @@ - + @@ -109,6 +109,7 @@ + @@ -135,10 +136,10 @@ - 1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
 + 1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
 2. Any live cell with two or three live neighbours lives on to the next generation. 
3. Any live cell with more than three live neighbours dies, as if by overpopulation. -
4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. +
4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. diff --git a/Game of Life/Game of Life/View Controllers/ViewController.swift b/Game of Life/Game of Life/View Controllers/ViewController.swift index dca4a299d..3ba73db96 100644 --- a/Game of Life/Game of Life/View Controllers/ViewController.swift +++ b/Game of Life/Game of Life/View Controllers/ViewController.swift @@ -11,49 +11,49 @@ import UIKit class ViewController: UIViewController { // MARK: - Properites - var gameGrid = GameGrid(size: 25) + var buttons: [UIButton] = [] - // MARK: - Actions + // MARK: - Outlets - @IBAction func playPausebutton(_ sender: Any) { - } + @IBOutlet weak var generationLabel: UILabel! + @IBOutlet weak var populationLabel: UILabel! + @IBOutlet weak var gridView: GridView! - @IBAction func stepButton(_ sender: UIButton) { - } + // MARK: - Actions @IBAction func clearButton(_ sender: UIButton) { - gameGrid.clearGrid() + gridView.clearGrid() } - @IBAction func presetsButton(_ sender: Any) { + @IBAction func patternsButton(_ sender: Any) { let alertController = UIAlertController(title: "Example Patterns", message: "Select a Game of Life pattern:", preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "Behive", style: .default) { (_) in - self.gameGrid.useExamplePattern(pattern: .behive) + self.gridView.useExamplePattern(pattern: .behive) }) alertController.addAction(UIAlertAction(title: "Blinker", style: .default) { (_) in - self.gameGrid.useExamplePattern(pattern: .blinker) + self.gridView.useExamplePattern(pattern: .blinker) }) alertController.addAction(UIAlertAction(title: "Toad", style: .default) { (_) in - self.gameGrid.useExamplePattern(pattern: .toad) + self.gridView.useExamplePattern(pattern: .toad) }) alertController.addAction(UIAlertAction(title: "Beacon", style: .default) { (_) in - self.gameGrid.useExamplePattern(pattern: .beacon) + self.gridView.useExamplePattern(pattern: .beacon) }) alertController.addAction(UIAlertAction(title: "Pulsar", style: .default) { (_) in - self.gameGrid.useExamplePattern(pattern: .pulsar) + self.gridView.useExamplePattern(pattern: .pulsar) }) alertController.addAction(UIAlertAction(title: "Pentadecathlon", style: .default) { (_) in - self.gameGrid.useExamplePattern(pattern: .pentadecathlon) + self.gridView.useExamplePattern(pattern: .pentadecathlon) }) alertController.addAction(UIAlertAction(title: "Glider", style: .default) { (_) in - self.gameGrid.useExamplePattern(pattern: .glider) + self.gridView.useExamplePattern(pattern: .glider) }) alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) @@ -61,18 +61,59 @@ class ViewController: UIViewController { present(alertController, animated: true, completion: nil) } - // MARK: - Outlets + @IBAction func playPausebutton(_ sender: Any) { + } - @IBOutlet weak var generationLabel: UILabel! - @IBOutlet weak var populationLabel: UILabel! + @IBAction func stepButton(_ sender: UIButton) { + gridView.step() + } // MARK: - View Lifecycle override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. + setupButtons() } // MARK: - Private -} + private func setupButtons() { + var index = 0 + var topOffset = CGFloat(0) + var leadingOffset = CGFloat(0) + + for _ in 0..= 375 { + topOffset = 0 + } + } + leadingOffset += 15 + } + } + @objc private func buttonTapped(_ sender: UIButton) { + print(sender.tag) + gridView.cellTapped(at: sender.tag) + } +} From 6115c13fc7a895f493d7341879612f6188cc5f82 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 00:07:54 -0700 Subject: [PATCH 13/30] Made Random a Pattern option --- Game of Life/Game of Life/Models/GameGrid.swift | 7 ++++++- .../Game of Life/View Controllers/ViewController.swift | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift index 09202fd3d..816e2eb15 100644 --- a/Game of Life/Game of Life/Models/GameGrid.swift +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -9,6 +9,8 @@ import UIKit public enum Patterns { + case random + // Still Lifes case behive @@ -46,7 +48,7 @@ class GameGrid: NSObject { func randomizeGrid() { for cell in cells { - let randomState = Int.random(in: 0...1) + let randomState = Int.random(in: 0...5) cell.state = randomState == 0 ? .alive : .dead } } @@ -63,6 +65,9 @@ class GameGrid: NSObject { clearGrid() switch pattern { + case .random: + randomizeGrid() + case .behive: cellAt(x: 3, y: 2).state = .alive cellAt(x: 4, y: 2).state = .alive diff --git a/Game of Life/Game of Life/View Controllers/ViewController.swift b/Game of Life/Game of Life/View Controllers/ViewController.swift index 3ba73db96..774f2c53a 100644 --- a/Game of Life/Game of Life/View Controllers/ViewController.swift +++ b/Game of Life/Game of Life/View Controllers/ViewController.swift @@ -28,6 +28,10 @@ class ViewController: UIViewController { @IBAction func patternsButton(_ sender: Any) { let alertController = UIAlertController(title: "Example Patterns", message: "Select a Game of Life pattern:", preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: "Random Pattern", style: .default) { (_) in + self.gridView.useExamplePattern(pattern: .random) + }) + alertController.addAction(UIAlertAction(title: "Behive", style: .default) { (_) in self.gridView.useExamplePattern(pattern: .behive) }) From 3a16cf6ccf796be7b577c19ff0857a897b86f6fb Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 00:49:58 -0700 Subject: [PATCH 14/30] Randomize grid and populate generation and population in the grid --- Game of Life/Game of Life/Models/GameGrid.swift | 15 +++++++++++++-- .../View Controllers/ViewController.swift | 13 +++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift index 816e2eb15..4f0b4de04 100644 --- a/Game of Life/Game of Life/Models/GameGrid.swift +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -25,9 +25,15 @@ public enum Patterns { case glider } +protocol GameStatsDelegate { + func showGeneration() + func showPopulation() +} + class GameGrid: NSObject { let size: Int var cells: [Cell] = [] + var delegate: GameStatsDelegate? var generation = 0 var population: Int { @@ -44,6 +50,10 @@ class GameGrid: NSObject { cells.append(cell) } } + + super.init() + + self.randomizeGrid() } func randomizeGrid() { @@ -225,12 +235,13 @@ class GameGrid: NSObject { } else { cells[index].state = .alive } - // Recompute population - print("population = \(population)") + // Tell delegate to display population + delegate?.showPopulation() } func performGameTurn() { generation += 1 + delegate?.showGeneration() } } diff --git a/Game of Life/Game of Life/View Controllers/ViewController.swift b/Game of Life/Game of Life/View Controllers/ViewController.swift index 774f2c53a..c48d630df 100644 --- a/Game of Life/Game of Life/View Controllers/ViewController.swift +++ b/Game of Life/Game of Life/View Controllers/ViewController.swift @@ -78,6 +78,9 @@ class ViewController: UIViewController { super.viewDidLoad() // Do any additional setup after loading the view. setupButtons() + gridView.gameGrid.delegate = self + showGeneration() + showPopulation() } // MARK: - Private @@ -121,3 +124,13 @@ class ViewController: UIViewController { gridView.cellTapped(at: sender.tag) } } + +extension ViewController: GameStatsDelegate { + func showGeneration() { + generationLabel.text = "\(gridView.gameGrid.generation)" + } + + func showPopulation() { + populationLabel.text = "\(gridView.gameGrid.population)" + } +} From 3bc1db2696934a68de8b52af4cea7dd3289de6e7 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 01:41:40 -0700 Subject: [PATCH 15/30] First attempt at performGameTurn --- .../Game of Life/Models/GameGrid.swift | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift index 4f0b4de04..504e999f9 100644 --- a/Game of Life/Game of Life/Models/GameGrid.swift +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -67,6 +67,7 @@ class GameGrid: NSObject { for cell in cells { cell.state = .dead } + generation = 0 } public func useExamplePattern(pattern: Patterns = .glider) { @@ -229,6 +230,16 @@ class GameGrid: NSObject { return cells[absolutePosition] } + func cellCoordinates(index: Int) -> (x: Int, y: Int) { + var y = 0 + var x = 0 + + y = index / size + x = index - (y * size) + + return (x, y) + } + func cellTapped(at index: Int) { if cells[index].state == .alive { cells[index].state = .dead @@ -240,6 +251,79 @@ class GameGrid: NSObject { } func performGameTurn() { + var index = 0 + for cell in cells { + var count = 0 + let coordinates = cellCoordinates(index: index) + + // West + if coordinates.x != 0 { + if cellAt(x: coordinates.x - 1, y: coordinates.y).state == .alive { + count = count + 1 + } + } + + // North West + if coordinates.x != 0 && coordinates.y != 0 { + if cellAt(x: coordinates.x - 1, y: coordinates.y - 1).state == .alive { + count = count + 1 + } + } + + // North + if coordinates.y != 0 { + if cellAt(x: coordinates.x, y: coordinates.y - 1).state == .alive { + count = count + 1 + } + } + + // North East + if coordinates.y != 0 && coordinates.x < (size - 1) { + if cellAt(x: coordinates.x + 1, y: coordinates.y - 1).state == .alive { + count = count + 1 + } + } + + // East + if coordinates.x < (size - 1) { + if cellAt(x: coordinates.x + 1, y: coordinates.y).state == .alive { + count = count + 1 + } + } + + // South East + if coordinates.x < (size - 1) && coordinates.y < (size - 1) { + if cellAt(x: coordinates.x + 1, y: coordinates.y + 1).state == .alive { + count = count + 1 + } + } + + // South + if coordinates.y < (size - 1) { + if cellAt(x: coordinates.x, y: coordinates.y + 1).state == .alive { + count = count + 1 + } + } + + // South West + if coordinates.y < (size - 1) && coordinates.x != 0 { + if cellAt(x: coordinates.x - 1, y: coordinates.y + 1).state == .alive { + count = count + 1 + } + } + + if cell.state == .alive { + if count < 2 || count > 3 { + cell.state = .dead + } + } else { // cell.state == .dead + if count == 3 { + cell.state = .alive + } + } + index = index + 1 + } + generation += 1 delegate?.showGeneration() } From ac656dc2907288b5cf2530887da4b66f0c2f1a85 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 01:57:30 -0700 Subject: [PATCH 16/30] Couple fixes --- Game of Life/Game of Life/Models/GameGrid.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift index 504e999f9..9f5172999 100644 --- a/Game of Life/Game of Life/Models/GameGrid.swift +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -278,8 +278,8 @@ class GameGrid: NSObject { } // North East - if coordinates.y != 0 && coordinates.x < (size - 1) { - if cellAt(x: coordinates.x + 1, y: coordinates.y - 1).state == .alive { + if coordinates.x != 0 && coordinates.y != 0 { + if cellAt(x: coordinates.x - 1, y: coordinates.y - 1).state == .alive { count = count + 1 } } @@ -306,7 +306,7 @@ class GameGrid: NSObject { } // South West - if coordinates.y < (size - 1) && coordinates.x != 0 { + if coordinates.x != 0 && coordinates.y < (size - 1) { if cellAt(x: coordinates.x - 1, y: coordinates.y + 1).state == .alive { count = count + 1 } From 844430c95edfec0a0783e75eb7e58aa5467b4a60 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 08:45:33 -0700 Subject: [PATCH 17/30] Variables weren't updating in all cases --- Game of Life/Game of Life/Models/GameGrid.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Game of Life/Game of Life/Models/GameGrid.swift b/Game of Life/Game of Life/Models/GameGrid.swift index 9f5172999..33d04e76a 100644 --- a/Game of Life/Game of Life/Models/GameGrid.swift +++ b/Game of Life/Game of Life/Models/GameGrid.swift @@ -68,6 +68,10 @@ class GameGrid: NSObject { cell.state = .dead } generation = 0 + delegate?.showGeneration() + + // Tell delegate to display population + delegate?.showPopulation() } public func useExamplePattern(pattern: Patterns = .glider) { @@ -221,6 +225,12 @@ class GameGrid: NSObject { cellAt(x: 3, y: 4).state = .alive cellAt(x: 2, y: 4).state = .alive } + + generation = 0 + delegate?.showGeneration() + + // Tell delegate to display population + delegate?.showPopulation() } func cellAt(x: Int, y: Int) -> Cell { @@ -326,6 +336,9 @@ class GameGrid: NSObject { generation += 1 delegate?.showGeneration() + + // Tell delegate to display population + delegate?.showPopulation() } } From a44dfd1e7f1d3f7af57ede750c78523e4f599ad1 Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 09:01:22 -0700 Subject: [PATCH 18/30] Got start and pause timer UX working --- Game of Life/Game of Life/GridView.swift | 3 +++ .../Game of Life/Storyboards/Base.lproj/Main.storyboard | 3 +++ .../Game of Life/View Controllers/ViewController.swift | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/Game of Life/Game of Life/GridView.swift b/Game of Life/Game of Life/GridView.swift index 3310a8df0..199c9609a 100644 --- a/Game of Life/Game of Life/GridView.swift +++ b/Game of Life/Game of Life/GridView.swift @@ -14,6 +14,9 @@ class GridView: UIView { var gameGrid = GameGrid(gridSize: 25) private var cellSize: Int = 15 private var timer: Timer? + var timerRunning: Bool { + timer == nil ? false : true + } // MARK: - Actions diff --git a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard index 210baf038..5010ef4f0 100644 --- a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard +++ b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard @@ -35,6 +35,7 @@ - + + + + 1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
 2. Any live cell with two or three live neighbours lives on to the next generation. 
3. Any live cell with more than three live neighbours dies, as if by overpopulation. @@ -152,16 +155,47 @@ + + + + + + + + + + + + + + + + + - + + + + + diff --git a/Game of Life/Game of Life/View Controllers/RulesViewController.swift b/Game of Life/Game of Life/View Controllers/RulesViewController.swift index 5aad7e68e..0e5663be1 100644 --- a/Game of Life/Game of Life/View Controllers/RulesViewController.swift +++ b/Game of Life/Game of Life/View Controllers/RulesViewController.swift @@ -10,13 +10,33 @@ import UIKit class RulesViewController: UIViewController { + // MARK: - Properites + var gridView: GridView? + + // MARK: - Actions + @IBAction func okButton(_ sender: Any) { + dismiss(animated: true, completion: nil) + } + + @IBAction func secondsSegmentedControl(_ sender: UISegmentedControl) { + switch(sender.selectedSegmentIndex) { + case 1: + gridView?.timeInterval = 0.50 + case 2: + gridView?.timeInterval = 0.75 + case 3: + gridView?.timeInterval = 1.00 + default: + gridView?.timeInterval = 0.25 + } + } + + // MARK: - Outlets + + // MARK: - View Lifecycle override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } - - @IBAction func okButton(_ sender: Any) { - dismiss(animated: true, completion: nil) - } } diff --git a/Game of Life/Game of Life/View Controllers/ViewController.swift b/Game of Life/Game of Life/View Controllers/ViewController.swift index ca3511e17..d7e40b38a 100644 --- a/Game of Life/Game of Life/View Controllers/ViewController.swift +++ b/Game of Life/Game of Life/View Controllers/ViewController.swift @@ -140,6 +140,13 @@ class ViewController: UIViewController { topOffset += 15 } } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "RulesSegue" { + guard let vc = segue.destination as? RulesViewController else { return } + vc.gridView = gridView + } + } } extension ViewController: GameStatsDelegate { From 109acfbda9bdc6340386f459c1cec1832b2b3b7d Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 11:53:33 -0700 Subject: [PATCH 28/30] Added color section for 2nd Stretch --- .../Storyboards/Base.lproj/Main.storyboard | 23 +++++++++++++++++++ .../RulesViewController.swift | 12 ++++++++++ .../View Controllers/ViewController.swift | 6 +++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard index 95082318f..d91e9f329 100644 --- a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard +++ b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard @@ -179,12 +179,33 @@ + + + + + + + + + + + + + + + + @@ -193,9 +214,11 @@ + + diff --git a/Game of Life/Game of Life/View Controllers/RulesViewController.swift b/Game of Life/Game of Life/View Controllers/RulesViewController.swift index 0e5663be1..412077bb6 100644 --- a/Game of Life/Game of Life/View Controllers/RulesViewController.swift +++ b/Game of Life/Game of Life/View Controllers/RulesViewController.swift @@ -12,8 +12,20 @@ class RulesViewController: UIViewController { // MARK: - Properites var gridView: GridView? + var viewController: ViewController? // MARK: - Actions + @IBAction func colorSegmentedControl(_ sender: UISegmentedControl) { + switch(sender.selectedSegmentIndex) { + case 1: + viewController?.buttonColor = UIColor.systemGreen + case 2: + viewController?.buttonColor = UIColor.systemYellow + default: + viewController?.buttonColor = UIColor.systemTeal + } + } + @IBAction func okButton(_ sender: Any) { dismiss(animated: true, completion: nil) } diff --git a/Game of Life/Game of Life/View Controllers/ViewController.swift b/Game of Life/Game of Life/View Controllers/ViewController.swift index d7e40b38a..5596512f1 100644 --- a/Game of Life/Game of Life/View Controllers/ViewController.swift +++ b/Game of Life/Game of Life/View Controllers/ViewController.swift @@ -12,6 +12,7 @@ class ViewController: UIViewController { // MARK: - Properites var buttons: [UIButton] = [] + var buttonColor = UIColor.systemTeal // MARK: - Outlets @@ -119,7 +120,7 @@ class ViewController: UIViewController { button.backgroundColor = .clear button.layer.borderWidth = 0.5 - button.layer.borderColor = UIColor.systemTeal.cgColor + button.layer.borderColor = UIColor.systemGray6.cgColor button.translatesAutoresizingMaskIntoConstraints = false button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) @@ -145,6 +146,7 @@ class ViewController: UIViewController { if segue.identifier == "RulesSegue" { guard let vc = segue.destination as? RulesViewController else { return } vc.gridView = gridView + vc.viewController = self } } } @@ -154,7 +156,7 @@ extension ViewController: GameStatsDelegate { var index = 0 for cell in gridView.gameGrid.cells { if cell.state == .alive { - buttons[index].backgroundColor = UIColor.systemTeal + buttons[index].backgroundColor = buttonColor } else { buttons[index].backgroundColor = .clear } From ca708a2d7797145b75c15a70f21db167e7e80b4a Mon Sep 17 00:00:00 2001 From: Mark Gerrior Date: Fri, 26 Jun 2020 12:01:39 -0700 Subject: [PATCH 29/30] Load current speed and color into settings. --- .../Storyboards/Base.lproj/Main.storyboard | 6 ++++- .../RulesViewController.swift | 26 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard index d91e9f329..c6d28d79f 100644 --- a/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard +++ b/Game of Life/Game of Life/Storyboards/Base.lproj/Main.storyboard @@ -170,7 +170,7 @@ - +