Default screen with cards on it working
This commit is contained in:
64
Set/AspectVGrid.swift
Normal file
64
Set/AspectVGrid.swift
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// AspectVGrid.swift
|
||||||
|
// Memorize
|
||||||
|
//
|
||||||
|
// Created by Oliver Hnát on 08.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct AspectVGrid<Item, ItemView>: View where ItemView: View, Item: Identifiable {
|
||||||
|
var items: [Item]
|
||||||
|
var aspectRatio: CGFloat
|
||||||
|
var content: (Item) -> ItemView
|
||||||
|
|
||||||
|
init(items: [Item], aspectRatio: CGFloat, @ViewBuilder content: @escaping (Item) -> ItemView) {
|
||||||
|
self.items = items
|
||||||
|
self.aspectRatio = aspectRatio
|
||||||
|
self.content = content
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
VStack {
|
||||||
|
let width: CGFloat = widthThatFits(itemCount: items.count, in: geometry.size, itemAspectRatio: aspectRatio)
|
||||||
|
LazyVGrid(columns: [adaptiveGridItem(width: width)], spacing: 0) {
|
||||||
|
ForEach(items) { item in
|
||||||
|
content(item).aspectRatio(aspectRatio, contentMode: .fit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(minLength: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func adaptiveGridItem(width: CGFloat) -> GridItem {
|
||||||
|
var gridItem = GridItem(.adaptive(minimum: width))
|
||||||
|
gridItem.spacing = 0
|
||||||
|
return gridItem
|
||||||
|
}
|
||||||
|
|
||||||
|
private func widthThatFits(itemCount: Int, in size: CGSize, itemAspectRatio: CGFloat) -> CGFloat {
|
||||||
|
var columnCount = 1
|
||||||
|
var rowCount = itemCount
|
||||||
|
repeat {
|
||||||
|
let itemWidth = size.width / CGFloat(columnCount)
|
||||||
|
let itemHeight = itemWidth / itemAspectRatio
|
||||||
|
if CGFloat(rowCount) * itemHeight < size.height {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
columnCount += 1
|
||||||
|
rowCount = (itemCount + (columnCount-1)) / columnCount
|
||||||
|
} while columnCount < itemCount
|
||||||
|
if columnCount > itemCount {
|
||||||
|
columnCount = itemCount
|
||||||
|
}
|
||||||
|
return floor(size.width / CGFloat(columnCount))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//struct AspectVGrid_Previews: PreviewProvider {
|
||||||
|
// static var previews: some View {
|
||||||
|
// AspectVGrid()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
//
|
|
||||||
// ContentView.swift
|
|
||||||
// Set
|
|
||||||
//
|
|
||||||
// Created by Oliver Hnát on 08.04.2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentView: View {
|
|
||||||
var body: some View {
|
|
||||||
VStack {
|
|
||||||
Image(systemName: "globe")
|
|
||||||
.imageScale(.large)
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
Text("Hello, world!")
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
ContentView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
31
Set/Diamond.swift
Normal file
31
Set/Diamond.swift
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Diamond.swift
|
||||||
|
// Set
|
||||||
|
//
|
||||||
|
// Created by Oliver Hnát on 08.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
|
||||||
|
struct Diamond: Shape {
|
||||||
|
|
||||||
|
func path(in rect: CGRect) -> Path {
|
||||||
|
|
||||||
|
let leftSide = CGPoint(x: rect.minX, y: rect.midY)
|
||||||
|
let bottom = CGPoint(x: rect.midX, y: rect.midY-rect.maxY/4)
|
||||||
|
let rightSide = CGPoint(x: rect.maxX, y: rect.midY)
|
||||||
|
let top = CGPoint(x: rect.midX, y: rect.midY+rect.maxY/4)
|
||||||
|
|
||||||
|
var p = Path()
|
||||||
|
|
||||||
|
p.move(to: rightSide)
|
||||||
|
p.addLine(to: top)
|
||||||
|
p.addLine(to: leftSide)
|
||||||
|
p.addLine(to: bottom)
|
||||||
|
p.addLine(to: rightSide)
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import SwiftUI
|
|||||||
struct SetApp: App {
|
struct SetApp: App {
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
SetGameView(game: SetGame())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
68
Set/SetGame.swift
Normal file
68
Set/SetGame.swift
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// SetGame.swift
|
||||||
|
// Set
|
||||||
|
//
|
||||||
|
// Created by Oliver Hnát on 09.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SetGame {
|
||||||
|
private var deck: Array<Card>
|
||||||
|
private(set) var cardsOnTable: Array<Card>
|
||||||
|
|
||||||
|
|
||||||
|
init() {
|
||||||
|
var deck = SetGame.createCards()
|
||||||
|
deck.shuffle()
|
||||||
|
let cardsOnTable = Array(deck[0..<12])
|
||||||
|
deck.removeAll { card in
|
||||||
|
cardsOnTable.contains { $0 == card }
|
||||||
|
}
|
||||||
|
self.deck = deck
|
||||||
|
self.cardsOnTable = cardsOnTable
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func createCards() -> Array<SetGame.Card> {
|
||||||
|
let colors: Array<Color> = [.blue, .green, .red]
|
||||||
|
var deck: Array<SetGame.Card> = Array()
|
||||||
|
var id = 0
|
||||||
|
for symbol in CardSymbol.allCases {
|
||||||
|
for shading in CardShading.allCases {
|
||||||
|
for number in 1..<4 {
|
||||||
|
for symbolColor in colors.indices {
|
||||||
|
let newCard = SetGame.Card(id: id, shading: shading, symbol: symbol, color: colors[symbolColor], numberOnCard: number)
|
||||||
|
deck.append(newCard)
|
||||||
|
id += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deck
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func newGame() {
|
||||||
|
var deck = SetGame.createCards()
|
||||||
|
deck.shuffle()
|
||||||
|
let cardsOnTable = Array(deck[0..<12])
|
||||||
|
deck.removeAll { card in
|
||||||
|
cardsOnTable.contains { $0 == card }
|
||||||
|
}
|
||||||
|
self.deck = deck
|
||||||
|
self.cardsOnTable = cardsOnTable
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct Card: Identifiable, Equatable {
|
||||||
|
var id: Int
|
||||||
|
var shading: CardShading
|
||||||
|
var symbol: CardSymbol
|
||||||
|
var color: Color
|
||||||
|
var isMatched: Bool = false
|
||||||
|
var isSelected: Bool = false
|
||||||
|
var numberOnCard: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
104
Set/SetGameView.swift
Normal file
104
Set/SetGameView.swift
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
//
|
||||||
|
// ContentView.swift
|
||||||
|
// Set
|
||||||
|
//
|
||||||
|
// Created by Oliver Hnát on 08.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SetGameView: View {
|
||||||
|
|
||||||
|
var game: SetGame
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
AspectVGrid(items: game.cardsOnTable, aspectRatio: 2/3) { card in
|
||||||
|
CardView(card: card).foregroundColor(.red)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
Spacer()
|
||||||
|
// Button(action: {game.newGame()}, label: {Text("New game")})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct CardView: View {
|
||||||
|
var card: SetGame.Card
|
||||||
|
var numberOfSymbols: Int
|
||||||
|
var color: Color
|
||||||
|
var symbol: CardSymbol
|
||||||
|
var shading: CardShading
|
||||||
|
|
||||||
|
init(card: SetGame.Card) {
|
||||||
|
self.card = card
|
||||||
|
self.numberOfSymbols = card.numberOnCard
|
||||||
|
self.color = card.color
|
||||||
|
self.symbol = card.symbol
|
||||||
|
self.shading = card.shading
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
ZStack {
|
||||||
|
let cardShape = RoundedRectangle(cornerRadius: 10)
|
||||||
|
cardShape.aspectRatio(2/3, contentMode: .fit)
|
||||||
|
cardShape.foregroundColor(.white)
|
||||||
|
cardShape.strokeBorder(lineWidth: 5)
|
||||||
|
|
||||||
|
if (shading == CardShading.open) {
|
||||||
|
}
|
||||||
|
VStack {
|
||||||
|
ForEach (0..<numberOfSymbols, id: \.self) { _ in
|
||||||
|
createShape().frame(height: geometry.size.height/4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func createShape() -> some View {
|
||||||
|
switch symbol {
|
||||||
|
case .diamond:
|
||||||
|
colorShape(Diamond())
|
||||||
|
case .squiggles:
|
||||||
|
colorShape(Rectangle())
|
||||||
|
default:
|
||||||
|
colorShape(RoundedRectangle(cornerRadius: 100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func colorShape(_ shape: some Shape) -> some View {
|
||||||
|
opacityShape(shape).foregroundColor(color).padding(.horizontal)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func opacityShape(_ shape: some Shape) -> some View {
|
||||||
|
switch shading {
|
||||||
|
case .solid:
|
||||||
|
shape.stroke(lineWidth: 2.5)
|
||||||
|
case .striped:
|
||||||
|
shape.opacity(0.5)
|
||||||
|
default:
|
||||||
|
shape
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct ContentView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
let game = SetGame()
|
||||||
|
SetGameView(game: game)
|
||||||
|
.preferredColorScheme(.dark)
|
||||||
|
SetGameView(game: game)
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Set/Uniqueness.swift
Normal file
20
Set/Uniqueness.swift
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Shading.swift
|
||||||
|
// Set
|
||||||
|
//
|
||||||
|
// Created by Oliver Hnát on 08.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum CardShading: CaseIterable {
|
||||||
|
case solid
|
||||||
|
case striped
|
||||||
|
case open
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CardSymbol: CaseIterable {
|
||||||
|
case diamond
|
||||||
|
case squiggles
|
||||||
|
case oval
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user