GithubHelp home page GithubHelp logo

pointfreeco / isowords Goto Github PK

View Code? Open in Web Editor NEW
2.6K 55.0 214.0 3.7 MB

Open source game built in SwiftUI and the Composable Architecture.

Home Page: https://www.isowords.xyz

License: Other

Swift 95.78% Dockerfile 0.12% Shell 0.05% Makefile 0.77% GLSL 0.13% CSS 0.97% HTML 2.18% C 0.01%
swiftui swift-composable-architecture ios game

isowords's Introduction

isowords

CI

This repo contains the full source code for isowords, an iOS word search game played on a vanishing cube. Connect touching letters to form words, the longer the better, and the third time a letter is used its cube is removed, revealing more letters inside!

Available on the App Store now!

Download isowords on the App Store

isowords screenshots


About

isowords is a large, complex application built entirely in Swift. The iOS client's logic is built in the Composable Architecture and the UI is built mostly in SwiftUI with a little bit in SceneKit. The server is also built in Swift using our experimental web server libraries.

We published a 4-part series of videos covering these topics and more on Point-Free, a video series exploring functional programming and the Swift language, hosted by Brandon Williams and Stephen Celis.

video poster image



Some things you might find interesting:

The Composable Architecture

The whole application is powered by the Composable Architecture, a library we built from scratch on Point-Free that provides tools for building applications with a focus on composability, modularity, and testability. This means:

  • The entire app's state is held in a single source of truth, called a Store.
  • The entire app's behavior is implemented by a single unit, called a Reducer, which is composed out of many other reducers.
  • All effectful operations are made explicit as values returned from reducers.
  • Dependencies are made explicit as simple data types wrapping their live implementations, along with various mock instances.

There are a ton of benefits to designing applications in this manner:

  • Large, complex features can be broken down into smaller child domains, and those domains can communicate via simple state mutations. Typically this is done in SwiftUI by accessing singletons inside ObservableObject instances, but this is not necessary in the Composable Architecture.
  • We take control of dependencies rather than allow them to take control of us. Just because you are using StoreKit, GameCenter, UserNotifications, or any other 3rd party APIs in your code, it doesn't mean you should sacrifice your ability to run your app in the simulator, SwiftUI previews, or write concise tests.
  • Exhaustive tests can be written very quickly. We test very detailed user flows, capture subtle edge cases, and assert on how effects execute and how their outputs feed back into the application.
  • It is straightforward to write integration tests that exercise multiple independent parts of the application.

Hyper-modularization

The application is built in a hyper-modularized style. At the time of writing this README the client and server are split into 86 modules. This allows us to work on features without building the entire application, which improves compile times and SwiftUI preview stability. It also made it easy for us to ship an App Clip, whose size must be less than 10 MB uncompressed, by choosing the bare minimum of code and resources to build.

Client/Server monorepo

The code for both the iOS client and server are included in this single repository. This makes it easy to run both the client and server at the same time, and we can even debug them at the same time, e.g. set breakpoints in the server that are triggered when the simulator makes API requests.

We also share a lot of code between client and server:

  • The core types that describe players, puzzles, moves, etc.
  • Game logic, such as the random puzzle generator, puzzle verification, dictionaries, and more.
  • The router used for handling requests on the server is the exact same code the iOS client uses to make API requests to the server. New routes only have to be specified a single time and it is immediately available to both client and server.
  • We write integration tests that simultaneously test the server and iOS client. During a test, API requests made by the client are actually running real server code under the hood.
  • And more...

Automated App Store screenshots and previews

The screenshots and preview video that we upload to the App Store for this app are automatically generated.

  • The screenshots are generated by a test suite using our SnapshotTesting library, and do the work of constructing a very specific piece of state that we load into a screen, as well as framing the UI and providing the surrounding graphics.

  • The preview video is generated as a screen recording of running a slimmed-down version of the app that embeds specific letters onto a cube and runs a sequence of actions to emulate a user playing the game. The app can be run locally by selecting the TrailerPreview target in Xcode and running it in the simulator.

Preview apps

There are times that we want to test a feature in isolation without building the entire app. SwiftUI previews are great for this but they also have their limitations, such as if you need to use APIs unavailable to previews, or if you need to debug more complex flows, etc.

So, we create mini-applications that build a small subset of the 86+ modules that comprise the entire application. Setting up these applications requires minimal work. You just specify what dependencies you need in the Xcode project and then create an entry point to launch the feature.

For example, here is all the code necessary to create a preview app for running the onboarding flow in isolation. If we were at the whims of the full application to test this feature we would need to constantly delete and reinstall the app since this screen is only shown on first launch.

Getting Started

This repo contains both the client and server code for running the entire isowords application, as well as an extensive test suite. To get things running:

  1. Make sure git-lfs is installed so that app assets (images, etc.) can be fetched. For example, with Homebrew:

    $ brew install git-lfs  # Download and install Git LFS
    $ git lfs install       # Set up Git LFS for your user
  2. Grab the code:

    git clone https://github.com/pointfreeco/isowords
    cd isowords
  3. Bootstrap the application:

    1. If you are only interested in building the iOS client, then run the following bootstrap command:
      make bootstrap-client
    2. If you want to build the client and server make sure PostgreSQL is installed and running, and then run the following bootstrap command:
      make bootstrap
  4. Open the Xcode project App/isowords.xcodeproj.

  5. To run the client locally, select the isowords target in Xcode and run (⌘R).

  6. To run the server locally, select the server target in Xcode and run (⌘R).

Learn More

Most of the concepts discussed in this README are covered in-depth on Point-Free, a video series exploring functional programming and the Swift language, hosted by Brandon Williams and Stephen Celis.

Point-Free

Related Projects

This application makes use of a number of open source projects built by us and discussed on Point-Free, including:

License

The source code in this repository may be run and altered for education purposes only and not for commercial purposes. For more information see our full license.

isowords's People

Contributors

acosmicflamingo avatar andreyz avatar buffsldr avatar ccrazy88 avatar chucks avatar filblue avatar gohanlon avatar hanneskaeufler avatar imjn avatar jasdev avatar mbrandonw avatar mfclarke-ts avatar myrronth avatar myurieff avatar ryu0118 avatar shmlktz avatar stephencelis avatar takagisou avatar tgrapperon avatar thomvis avatar tplaymeow avatar yimajo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

isowords's Issues

No file prompt when creating new files in the `isowords` local package

Describe the bug
When creating new swift file anywhere inside under the isowords local package, there's no file name prompt, and a new File.swift is instantly created instead. As opposed to creating new file outside the local pacakage, like inside the AppClip folder or Config folder. I've also noticed that I can't use any of my custom Xcode templates.

I've encountered this on my own projects as well and was wondering if you have a workaround for that, other than creating the file outside the local package and then dragging it inside.

To reproduce

  1. open App/isowords.xcodeproj
  2. Right click on the BottomMenu folder inside isowords -> Sources.
  3. Click New File
  4. Choose Swift File
  5. Click Next

Expected behavior
I expect a file name prompt:
image

Screenshots/video
image

Environment

  • Xcode Version 13.3.1 (13E500a)

Settings.Action.binding actions are not being handled as expected

Describe the bug
It seems like many of the viewStore actions sent within views of the Settings module (e.g. SoundsSettingsView) do not actually do anything within the Settings reducer as I'd expect. Instead, I see in the debug console a message like this:

2022-12-09 17:31:27.590658-0600 isowords[11473:1931144] [ComposableArchitecture] A binding action sent from a view store 
at "SettingsFeature/SoundsSettingsView.swift:22" was not handled. …

  Action:
    Settings.Action.binding(.set(_, 0.6017382))

To fix this, invoke "BindingReducer()" from your feature reducer's "body".

This is very strange because BindingReducer() is indeed within the Settings reducer body.

To reproduce
If I compile isowords in Xcode, run the app, click on the settings button, select the sound button and try and change the value of any of the sound sliders, the sliders actually do not change value.

Expected behavior
I'd expect that the Settings reducer would actually stop at any of the breakpoints I set within it.

Screenshots/video
https://user-images.githubusercontent.com/67525430/206812842-45fda284-78ec-4908-8177-1ab66a1a5015.mov

Environment

  • Device: iPhone 14 Simulator
  • OS: iOS 16.1
  • Xcode: 14.1

Additional context
What is strange is that if I run "SettingsPreview", I do not see this problem.

`isowords` app target missing

Describe the bug

After following the readme instructions, there is no isowords.xcodeproj and the package itself also doesn't contain a isowords application target.

Open the Xcode project App/isowords.xcodeproj.

To run the client locally, select the isowords target in Xcode and run (⌘R).

To reproduce
follow the steps in the readme.

Expected behavior
Be able to build the isowords app standalone

Screenshots/video
If applicable, add screenshots/video to help explain the problem.

Environment

  • Device: [e.g. iPhone 12 Pro]
  • OS: [e.g. iOS 14]

Additional context
Add any more context about the problem here.

isowords is running audio and using battery even when the isowords audio settings have turned audio off.

Describe the bug
Audio is turned off in isowords settings.
Battery in System Settings is showing significant percentage of battery drain and Audio as the load.

To reproduce
Turn audio off, run isowords for a couple of games, go to battery (an hour later) and look at the description.

Expected behavior
If Audio is turned off isowords should be spending zero cpu cycles playing audio. Quick look at the code makes it seem like there aren't any checks for sound off and it just plays the audio with zero volume. You'd hope iOS would be smart about that, but it seems it may not be.

Screenshots/video
IMG_4851

IMG_4850

Environment

  • Device: iPhone 12 Pro
  • OS: iOS 15.5
  • isowords build 102 (fe7eb2c)

`make bootstrap-client` fails (words/SQL issue?)

Upon running make bootstrap-client, the console throws the following output:

  ⚠️  Checking for Git LFS...
  ✅ Git LFS is good to go!
touch Sources/AppAudioLibrary/Resources/empty.mp3
touch Sources/AppClipAudioLibrary/Resources/empty.mp3
/dev/stdin:173: INSERT failed: UNIQUE constraint failed: words.word
/dev/stdin:236: INSERT failed: UNIQUE constraint failed: words.word
/dev/stdin:629: INSERT failed: UNIQUE constraint failed: words.word
#...etc...

I've tried prepending sudo as well just in case, but no dice.

(p.s., thanks so much for open-sourcing this! It's a great service to the community.)

[Feature] - Time limit for multiplayer mode

As described in the title, I think it will be a good feature if we add a time limit for each turn in multiplayer mode. For example, there can be an adjustable time limit of say 1 minute before the person's turn is forfeited.

I will add more design details because I would actually like to work on this, once I get a better understanding of the codebase (just discovered this amazing project today).

Various layout issues when iPad app is in compact width

Describe the bug
iPad multitasking is enabled in info.plist, but the app has various layout issues when running side by side in compact width.

This is true even with the cube worldScale fix from #126

To reproduce

  • Launch the app on iPad and use multitasking to put the app into compact width.
  • rotate the iPad etc etc

Expected behavior
Nothing is clipped and screen width is used effectively. It would probably be most effective if the iPad app in compact width used layout metrics similar to the phone app since compact width sizes are fairly similar.

Screenshots/video

some representative examples.

Screen Shot 2021-08-16 at 4 52 41 PM
Screen Shot 2021-08-16 at 4 52 23 PM
Screen Shot 2021-08-16 at 4 51 41 PM

Environment

  • iPad, iOS 14.7.1

I'm working on a PR to use the iPhone layout values when running on iPad in compact width.

Mimicking the modular structure of this app

Hi. Love the project and the way it is structured. I have tried to move one of my own apps over to a similar sort of scheme by following the setup of your package file

I am seeing a few flaky CI runs, sometimes testing passes and sometimes it fails.

the failure seems to be related to the resolution of XCTestDynamicOverlay

error: Missing package product 'XCTestDynamicOverlay' 

when I see this locally I can get rid of the issue by clearing my derived data which then prompts Xcode to do its thing and pull the dependencies again.

I know it may be difficult to diagnose without having a copy of my project, but I figure it was worth an ask. Maybe you guys have seen something similar? I am using an almost identical copy of your ci workflow and a paired down set of package dependencies. Hopefully I am missing something small.

Can't set a custom icon on iPad

When you attempt to set a custom icon from Settings…Appearance on iPad, the first tap on a custom icon will select it, but nothing else will happen. If you tap again, you'll see a confirmation from the system, but the stock icon will be in the dialog box, and the actual icon on device will not be changed.

Exported.mov

When the app attempts to set the custom icon, it fails with an error, which is suppressed by a fire and forget effect

Error Domain=NSCocoaErrorDomain Code=4 "The file doesn’t exist." UserInfo={_LSLine=191, NSUnderlyingError=0x6000031a8210 {Error Domain=LSApplicationWorkspaceErrorDomain Code=-105 "iconName not found in CFBundleAlternateIcons entry" UserInfo={_LSLine=179, NSLocalizedDescription=iconName not found in CFBundleAlternateIcons entry, _LSFunction=-[LSAltIconManager _setAlternateIconName:forIdentifier:withIconsDictionary:error:]}}, _LSFunction=-[LSAltIconManager _setAlternateIconName:forIdentifier:withIconsDictionary:error:]}

I'll submit a PR to update info.plist to register the custom icons for iPad specifically.

unexpected service error: “multiple configured targets of \’CubeCore\’ are being created for iOS Simulator”

--- Solved --- But feel free to comment...

In the spirit of issue #49 I'll ask this question here - but please let me know if you'd prefer I ask it elsewhere (Twitter, StackOverflow, forums.swift.org - where is best?)

I'm interested in using Previews to view some of the available screens. I’m running into an issue I’m sure you had to solve early on in your development:

“unexpected service error: build aborted due to an internal error: planning Failed(“multiple configured targets of \’CubeCore\’ are being created for iOS Simulator”)

I see multiple proposed solutions, from setting the DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC build setting to YES in the app target to converting static libraries to dynamic. What worked best for you?

Cube is incorrectly sized after rotation on iPad

Describe the bug
If you rotate the iPad while playing isowords, the cube will not be sized the same as if the game was launched in that orientation.

To reproduce

  • Launch isowords in landscape on iPad or the simulator

  • start a new game

  • rotate to portrait

  • Launch isowords in portrait on iPad on the simulator

  • start a new game

  • rotate to landscape

Expected behavior
The cube would be shown without clipping and at the same size as if the app was launched in the given orientation.

Screenshots/video
Launch Portrait

rotate to portrait

Launch Landscape

rotate to landscape

Environment

  • iPad running iOS 14.7.1

Additional context
Similar issues exist if you switch the iPad from full screen into side-by-side multitasking, but there are additional issues with the multitasking UI not covered by this problem. I'll log a separate issue for these.

make bootstrap-client produces multiple fail messages

I'm new to git-lfs and the version bootstrap tried to use caused a segmentation fault. I removed it and reinstalled using brew.
Then I was asked to issue 'git lfs install' when I issued 'git-lfs' with no args. That worked fine.
At this point I am cd-ed into isowords, and issue 'make bootstrap-client':

⚠️ Checking for Git LFS...
✅ Git LFS is good to go!
touch Sources/AppAudioLibrary/Resources/empty.mp3
touch Sources/AppClipAudioLibrary/Resources/empty.mp3
/dev/stdin:173: INSERT failed: UNIQUE constraint failed: words.word
/dev/stdin:236: INSERT failed: UNIQUE constraint failed: words.word
--- for a total of 1468 similar lines

are these normal error messages that can be safely ignored?

Change my user name?

I tried asking via Twitter, but I think my privacy settings were messed up.
I was using the test version of isowords until you released it on the store, and then bought that version.
I notice a lot of people have normal user names, whereas mine is a randomly generated string. Can I change my user name?
If not, it's not a big deal... Alas, I'm afraid my days in the top ten are forever gone!

Text truncation issues for onboarding screens with Accessibility text sizes

Hi,

I realize this may have been improved with #8 , but just in case my issue is different I wanted to log it.

I have my phone set to the smallest of the "accessibility" dynamic type sizes, and there are a couple places in the onboarding flow where words are truncated.

IMG_4797
IMG_4796

I'm super happy overall to see a game like this support Dynamic Type, since games are often difficult to play for low-vision users.

There are other places where text layout isn't always optimal, but they don't affect playability the way truncation does.

make bootstrap-client does not fetch image assets

Describe the bug
After cloning the repository, running:
make bootstrap-client
and then opening the workspace file and attempting to run the main isowords target produces the following error:
The stickers icon set or app icon set named "AppIcon" did not have any applicable content.

To reproduce

  • Clone the repository
  • Run make bootstrap-client in terminal
  • Open workspace
  • Run isowords target
  • Build fails

Expected behavior
The app runs in the iOS simulator

Screenshots/video
Screen Shot 2021-06-11 at 4 05 40 PM

Environment

  • 2016 MacBook Pro 15":
  • OS: macOS 11.4

Mostly Empty Project

Cloning the repo is failing, and downloading the zip file results in the same mostly empty project folder.

% tree
.
└── App
    └── AppClip
        ├── AppClip.entitlements
        ├── AppClipApp.swift
        └── Assets.xcassets
            └── AppIcon.appiconset
                └── Contents.json
% git clone https://github.com/pointfreeco/isowords.git
Cloning into 'isowords'...
remote: Enumerating objects: 970, done.
remote: Counting objects: 100% (970/970), done.
remote: Compressing objects: 100% (755/755), done.
remote: Total 970 (delta 202), reused 921 (delta 171), pack-reused 0
Receiving objects: 100% (970/970), 2.04 MiB | 5.25 MiB/s, done.
Resolving deltas: 100% (202/202), done.
git-lfs filter-process: git-lfs: command not found
fatal: the remote end hung up unexpectedly
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry with 'git restore --source=HEAD :/'
% git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	deleted:    .gitattributes
	deleted:    .github/workflows/ci.yml
	deleted:    .github/workflows/format.yml
	deleted:    .gitignore
        ...

Android?

Hi, will you make an android version of this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.