Multiple buttons - repetitive code

I have made a custom button in its own struct. I have inserted 5 of them into the ContentView body. Is there a better way to code the buttons into ContentView? It seems to be repetitive. Thanks for any assistance.

struct ContentView: View { @State private var score = 0

var body: some View {
    ZStack {
        Color.pink.opacity(0.2).ignoresSafeArea()
        VStack {
            Spacer()
            Text("Keep Score")
                .foregroundStyle(.black)
                .font(.system(size: 50, weight: .semibold, design: .rounded))
            Spacer()
            Text("The score is: \(score)")
                .foregroundStyle(.secondary)
                .font(.system(size: 30, weight: .semibold, design: .rounded))
            Spacer()
            ButtonView(name: "Add 1", background: .red) {
                score += 1
            }
            ButtonView(name: "Add 2", background: .green) {
                score += 2
            }
            ButtonView(name: "Add 3", background: .yellow) {
                score += 3
            }
            ButtonView(name: "Minus 1", background: .cyan) {
                score -= 1
            }
            ButtonView(name: "Reset", background: .mint) {
                score = 0
            }
        }
        Spacer()
    }
}

}

struct ButtonView: View { let name: String let background: Color let action: () -> Void

var body: some View {
    Button  {
        action()
    } label: {
        ZStack {
            RoundedRectangle(cornerRadius: 5)
                .stroke(lineWidth: 4)
                .foregroundColor(.black)
            RoundedRectangle(cornerRadius: 5)
                .foregroundColor(background)
            Text(name)
                .foregroundStyle(.black).bold().font(.subheadline)
        }
    }
    .padding(5)
    .frame(width: 75, height: 50)
}

}

You can use ForEach.

But it is not that much simpler:

struct ContentView: View {
    @State private var score = 0
    
    struct NumAndColor : Hashable {
        var num: Int
        var color: Color
    }
    
    let buttonsNumsAndColors: [NumAndColor] = [NumAndColor(num: 1, color: Color.red), NumAndColor(num: 2, color: Color.green), NumAndColor(num: 3, color: Color.yellow), NumAndColor(num: -1, color: Color.cyan), NumAndColor(num: 0, color: Color.mint)]
    
    var body: some View {
        ZStack {
            Color.pink.opacity(0.2).ignoresSafeArea()
            VStack {
                Spacer()
                Text("Keep Score")
                    .foregroundStyle(.black)
                    .font(.system(size: 50, weight: .semibold, design: .rounded))
                Spacer()
                Text("The score is: \(score)")
                    .foregroundStyle(.secondary)
                    .font(.system(size: 30, weight: .semibold, design: .rounded))
                Spacer()
                ForEach(buttonsNumsAndColors, id: \.self) { numAndColor in
                    if numAndColor.num > 0 {
                        ButtonView(name: "Add \(numAndColor.num)", background: numAndColor.color) {
                            score += numAndColor.num
                        }
                    } else if numAndColor.num < 0 {
                        ButtonView(name: "Minus \(-numAndColor.num)", background: numAndColor.color) {
                            score += numAndColor.num
                        }
                    } else {
                        ButtonView(name: "Reset", background: numAndColor.color) {
                            score = 0
                        }
                    }
                }
                /*
                 ButtonView(name: "Add 1", background: .red) {
                 score += 1
                 }
                 ButtonView(name: "Add 2", background: .green) {
                 score += 2
                 }
                 ButtonView(name: "Add 3", background: .yellow) {
                 score += 3
                 }
                 ButtonView(name: "Minus 1", background: .cyan) {
                 score -= 1
                 }
                 ButtonView(name: "Reset", background: .mint) {
                 score = 0
                 }*/
            }
            Spacer()
        }
    }
}
struct ButtonView: View {
    
    let name: String
    let background: Color
    let action: () -> Void
    
    var body: some View {
        Button  {
            action()
        } label: {
            ZStack {
                RoundedRectangle(cornerRadius: 5)
                    .stroke(lineWidth: 4)
                    .foregroundColor(.black)
                RoundedRectangle(cornerRadius: 5)
                    .foregroundColor(background)
                Text(name)
                    .foregroundStyle(.black).bold().font(.subheadline)
            }
        }
        .padding(5)
        .frame(width: 75, height: 50)
    }
}

You can improve by having a computed var for op in NumAndColor struct

struct ContentView: View {
    @State private var score = 0
    
    struct NumAndColor : Hashable {
        var num: Int
        var color: Color
        var op: String {
            switch num {
                case 0: return "Reset"
                case 1...: return "Add"
                case ...0: return "Minus"
                default: return "No Op"  // Will never occur
            }
        }
    }
    
    let buttonsNumsAndColors: [NumAndColor] =
    [NumAndColor(num: 1, color: Color.red),
     NumAndColor(num: 2, color: Color.green),
     NumAndColor(num: 3, color: Color.yellow),
     NumAndColor(num: -1, color: Color.cyan),
     NumAndColor(num: 0, color: Color.mint)]
    
    var body: some View {
        ZStack {
            Color.pink.opacity(0.2).ignoresSafeArea()
            VStack {
                Spacer()
                Text("Keep Score")
                    .foregroundStyle(.black)
                    .font(.system(size: 50, weight: .semibold, design: .rounded))
                Spacer()
                Text("The score is: \(score)")
                    .foregroundStyle(.secondary)
                    .font(.system(size: 30, weight: .semibold, design: .rounded))
                Spacer()
                ForEach(buttonsNumsAndColors, id: \.self) { numAndColor in
                        ButtonView(name: "\(numAndColor.op) \(abs(numAndColor.num))", background: numAndColor.color) {
                            if numAndColor.num == 0 {  // This case has to be dealt separately
                                score = 0
                            } else {
                                score += numAndColor.num
                            }
                        }
                }
            }
            Spacer()
        }
    }
}

And here's what I would do:

struct ContentView: View {
  @State private var score = 0

  let buttons = [ButtonData(name: "Add 1", background: .red, delta: 1),
                 ButtonData(name: "Add 2", background: .green, delta: 2),
                 ButtonData(name: "Add 3", background: .yellow, delta: 3),
                 ButtonData(name: "Minus 1", background: .cyan, delta: -1),
                 ButtonData(name: "Reset", background: .mint, delta: 0)
  ]

  var body: some View {
    ZStack {
      Color.pink.opacity(0.2).ignoresSafeArea()
      VStack {
        Spacer()
        Text("Keep Score")
          .foregroundStyle(.black)
          .font(.system(size: 50, weight: .semibold, design: .rounded))
        Spacer()
        Text("The score is: \(score)")
          .foregroundStyle(.secondary)
          .font(.system(size: 30, weight: .semibold, design: .rounded))
        Spacer()
        ForEach(buttons.indices, id: \.self) { b in
          ButtonView(button: buttons[b], score: $score)
        }
      }
      Spacer()
    }
  }
}

struct ButtonData {
  let name: String
  let background: Color
  let delta: Int
}

struct ButtonView: View {
  var button: ButtonData
  @Binding var score: Int

  var body: some View {
    Button {
      score = (button.delta == 0 ? 0 : score + button.delta)
    } label: {
      ZStack {
        RoundedRectangle(cornerRadius: 5)
          .stroke(lineWidth: 4)
          .foregroundColor(.black)
        RoundedRectangle(cornerRadius: 5)
          .foregroundColor(button.background)
        Text(button.name)
          .foregroundStyle(.black).bold().font(.subheadline)
      }
    }
    .padding(5)
    .frame(width: 75, height: 50)
  }
}
Multiple buttons - repetitive code
 
 
Q