I'm really struggling as newbie with how to solve a problem of counting elements in an array of an array of structs. I've tried several different methods but it isn't giving me the results I need.
So I have a Struct called Card defined as follows:
struct Card: Hashable {
var dateGroup: DateGroup
var countryGroup: CountryGroup
var icon1: IconGroup
var icon2: IconGroup
init(dateGroup: DateGroup, countryGroup: CountryGroup, icon1: IconGroup, icon2: IconGroup) {
self.dateGroup = dateGroup
self.countryGroup = countryGroup
self.icon1 = icon1
self.icon2 = icon2
}
}
For reference, the elements of Card are defined as enums using the following code:
enum DateGroup: String {
case DG1, DG2, DG3
static let allValues = [DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG1, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG2, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3, DG3]
}
enum CountryGroup: String {
case IT, NE, FS, US
static let allValues = [IT, IT, IT, IT, IT, IT, IT, IT, NE, NE, IT, NE, NE, NE, IT, IT, IT, NE, IT, NE, IT, IT, IT, NE, IT, IT, IT, IT, NE, IT, NE, NE, FS, FS, NE, IT, IT, NE, NE, IT, IT, NE, FS, FS, FS, NE, FS, NE, NE, NE, NE, FS, NE, NE, FS, NE, IT, NE, NE, FS, FS, NE, IT, NE, FS, NE, NE, NE, NE, FS, FS, FS, FS, FS, US, FS, FS, FS, FS, NE, FS, FS, FS, NE, US, IT]
}
enum IconGroup: String {
case Portrait, People, Still, Scape, Setting
static let allValues1 = [Portrait, People, People, Portrait, Portrait, People, People, People, People, Portrait, People, Portrait, People, People, People, Portrait, People, Portrait, People, Portrait, Portrait, People, People, Portrait, People, People, Portrait, People, Portrait, People, Portrait, People, Portrait, People, People, People, People, Still, People, Portrait, People, Portrait, Still, People, People, People, Portrait, Still, People, Portrait, Portrait, People, Still, Still, People, Still, People, Portrait, Portrait, People, People, People, People, Portrait, Portrait, People, Scape, Scape, Setting, People, People, Still, People, Still, Setting, Scape, People, People, People, Still, Still, Portrait, People, Portrait, People, People]
static let allValues2 = [Setting, Setting, Setting, Setting, Setting, Setting, Setting, Scape, Setting, Setting, Scape, Scape, Setting, Setting, Scape, Scape, Setting, Scape, Setting, Scape, Scape, Scape, Scape, Setting, Scape, Scape, Setting, Scape, Setting, Setting, Portrait, Setting, Setting, Setting, Scape, Portrait, Setting, Still, Scape, Setting, Scape, Setting, Still, Scape, Scape, Scape, Setting, Still, Scape, Portrait, Setting, Setting, Still, Still, Scape, Still, Scape, Portrait, Scape, Setting, Scape, Setting, Scape, Setting, Setting, Scape, Scape, Scape, Scape, Scape, Scape, Still, Scape, Still, Still, Scape, Setting, Setting, Scape, Still, Still, Setting, Setting, Setting, Setting, Setting]
}
I've created a class called DeckOfCards and functions to shuffle the deck and deal a hand to a defined number of players. I've eventually got all that to work and checked by printing results in the console and it all checks out.
So each player has say 10 cards and is defined as an array of type Card (and as an aside the players are also stored in an array called newGame). So newGame[0] is player 1 and newGame[0][0] is the first card in the players hand. And therefore I can reference the dateGroup of that card by newgame[0][0].dateGroup for example.
What I'm trying to achieve is checking if a player has a set of 5 or more cards where two of the card elements are the same. I've started by trying to do a count of the card elements in a players hand. So for example how may of the cards have dateGroup of DG1, how many are DG2 etc, how many are countryGroup IT etc etc.
I've tried to do use joined() and then do a count but that didn't work. I'm thinking of returning an array with a count by each possible element type and have started with this very skeletal code:
func createIconCount(playerHand: [Card] ) -> [String : Int] {
var counts: [String: Int] = [:]
//insert counting code here
return counts
}
So I'd get an array back with something like [DG1: 3, DG2: 3, ....... IT: 4, NE: 5, .... Portrait: 6, People: 4, .....]
Help! Any ideas?
Rob
Use the rawValue
of the attributes and a default
total of 0
on dictionary lookup to total the values:
func createIconCount(playerHand: [Card] ) -> [String : Int] {
var counts: [String: Int] = [:]
for card in playerHand {
counts[card.dateGroup.rawValue, default: 0] += 1
counts[card.countryGroup.rawValue, default: 0] += 1
counts[card.icon1.rawValue, default: 0] += 1
// Don't count icon2 if it is the same as icon1
if card.icon2 != card.icon1 {
counts[card.icon2.rawValue, default: 0] += 1
}
}
return counts
}
Creating an array of indices of cards with icon:
Instead of creating a count of the cards with a matching icon, you can create an array of the indices of the cards in the player's hand. Start by adding .enumerated
to playerHand
to get the indices, and then append the idx
to the array. Here we use []
as the default dictionary lookup value creating an empty array if one doesn't already exist.
func createIconCount(playerHand: [Card] ) -> [String : [Int]] {
var counts: [String: [Int]] = [:]
for (idx, card) in playerHand.enumerated() {
counts[card.dateGroup.rawValue, default: []].append(idx)
counts[card.countryGroup.rawValue, default: []].append(idx)
counts[card.icon1.rawValue, default: []].append(idx)
// Don't count icon2 if it is the same as icon1
if card.icon2 != card.icon1 {
counts[card.icon2.rawValue, default: []].append(idx)
}
}
return counts
}