Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Rock Paper Scissors Trainer
import SwiftUI
struct PlayerMoveEmoji: ViewModifier {
func body(content: Content) -> some View {
content
.font(.system(size: 60))
.padding(.bottom, 8)
}
}
extension View {
func playerMoveEmoji() -> some View {
self.modifier(PlayerMoveEmoji())
}
}
struct PlayerMoveCardStyle: ButtonStyle {
let defaultTransform = CGAffineTransform(translationX: 0, y: 0)
let pressedTransform = CGAffineTransform(translationX: 0, y: -12)
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.frame(minWidth: 60, maxWidth: 125, maxHeight: 160)
.clipShape(RoundedRectangle(cornerRadius: 24, style: .continuous))
.shadow(color: Color(red: 0, green: 0, blue: 0, opacity: configuration.isPressed ? 0.2 : 0.16), radius: configuration.isPressed ? 4 : 12, y: configuration.isPressed ? 2 : 8)
.scaleEffect(configuration.isPressed ? 0.96 : 1.0)
.transformEffect(configuration.isPressed ? pressedTransform : defaultTransform)
}
}
struct PlayerMoveCard: View {
var emoji: String
var name: String
var index: Int {
switch self.name {
case "Rock": return 0
case "Paper": return 1
case "Scissors": return 2
default:
return 0
}
}
var handleTap: (Int) -> Void
var body: some View {
Button(action: {
handleTap(index)
}) {
ZStack {
Color.white
VStack {
Text(emoji)
.rotationEffect(.degrees(self.name == "Rock" ? 98 : 0))
.padding(.leading, self.name == "Rock" ? 4 : 0)
.playerMoveEmoji()
Text(name)
.foregroundColor(.primary)
.font(.headline)
}
}
}
.buttonStyle(PlayerMoveCardStyle())
.animation(.spring())
}
}
struct ContentView: View {
var moveEmojis = ["🤛", "🖐", "✌️"]
var moveNames = ["Rock", "Paper", "Scissors"]
var maxTurns = 10
@State private var score = 0
@State private var appChoice = Int.random(in: 0 ..< 3)
@State private var shouldWin = Bool.random()
@State private var playerChoice = 0
@State private var turns = 0
@State private var showScore = false
var body: some View {
VStack {
HStack {
ProgressView(value: Float(turns) / Float(maxTurns))
.padding(.trailing, 20)
Text("Score: \(score)")
.font(.callout)
.padding(8)
.background(Color(red: 0.95, green: 0.95, blue: 0.95))
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
}
Spacer()
VStack {
shouldWin ? Text("WIN") : Text("LOSE")
Text("against").font(.subheadline)
}
.font(.system(size: 48, weight: .heavy, design: .default))
.padding(.bottom, 8)
VStack {
Text(moveNames[appChoice]).font(.title).bold()
.padding(.bottom, 20)
Text(moveEmojis[appChoice])
.rotationEffect(.degrees(appChoice == 0 ? -82 : 180))
.font(.system(size: 100))
.padding(.leading, appChoice == 0 ? -6 : 0)
}
.padding(.bottom, 24)
Spacer()
HStack(spacing: 16) {
ForEach(0 ..< moveNames.count) {
PlayerMoveCard(emoji: moveEmojis[$0], name: moveNames[$0]) {
playerChoice = $0
handleCardTap()
}
}
}
.padding(.bottom, 36)
}
.padding(20)
.alert(isPresented: $showScore, content: {
Alert(title: Text("Score: \(score) out of 10"), dismissButton: .default(Text("Play Again!")) {
score = 0
turns = 0
})
})
}
func handleCardTap() {
if shouldWin {
switch appChoice {
case 0: if playerChoice == 1 { score += 1 }
case 1: if playerChoice == 2 { score += 1 }
case 2: if playerChoice == 0 { score += 1 }
default: score += 0
}
} else {
switch appChoice {
case 0: if playerChoice == 2 { score += 1 }
case 1: if playerChoice == 0 { score += 1 }
case 2: if playerChoice == 1 { score += 1 }
default: score += 0
}
}
appChoice = Int.random(in: 0 ..< 3)
shouldWin = Bool.random()
turns += 1
if turns == maxTurns {
showScore.toggle()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
@k-mao

This comment has been minimized.

Copy link
Owner Author

@k-mao k-mao commented Sep 21, 2020

A brain training game that challenges players to win or lose at rock, paper, scissors.
Check it out in action here: https://twitter.com/k_mao/status/1308084646240907264?s=21

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment