How to check and calculate full house of dice - flutter

I'm making a Yahtzee-like game with 5 dices using Flutter + Dart. I keep the dice values in a List<int>. What would be the best way to check if there is a full house, and what is the sum or relevant dices?
If I want only to determine if I have a full house, this solution would be good. But I have to calculate the sum afterwards, so I need to know how many of which numbers I have.
Making 30 ifs to cover each case is a solution, but probably not the best one. Does anyone have any better idea?

Here would be a simple Dart implementation using List/Iterable methods:
bool fullHouse(List<int> dice) {
final counts = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0};
dice.forEach((n) => counts[n]++);
return counts.containsValue(3) && counts.containsValue(2);
}
int diceSum(List<int> dice) => dice.reduce((v, e) => v + e);
As you can see, I separated the sum and the full house check, but I can also adjust this if necessary.
Extension
If you are using a Dart 2.6 or later, you could also create a nice extension for this:
void main() {
print([1, 1, 2, 1, 2].fullHouseScore);
}
extension YahtzeeDice on List<int> {
int get fullHouseScore {
if (isFullHouse) return diceSum;
return 0;
}
bool get isFullHouse {
final counts = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0};
forEach((n) => counts[n]++);
return counts.containsValue(3) && counts.containsValue(2);
}
int get diceSum => reduce((v, e) => v + e);
}
Testing
This would be a simple usage of the functions for testing:
int checkFullHouse(List<int> dice) {
if (fullHouse(dice)) {
final sum = diceSum(dice);
print('Dice are a full house. Sum is $sum.');
return sum;
} else {
print('Dice are not a full house.');
return 0;
}
}
void main() {
const fullHouses = [
[1, 1, 1, 2, 2],
[1, 2, 1, 2, 1],
[2, 1, 2, 1, 1],
[6, 5, 6, 5, 5],
[4, 4, 3, 3, 3],
[3, 5, 3, 5, 3],
],
other = [
[1, 2, 3, 4, 5],
[1, 1, 1, 1, 2],
[5, 5, 5, 5, 5],
[6, 5, 5, 4, 6],
[4, 3, 2, 5, 6],
[2, 4, 6, 3, 2],
];
print('Testing dice that are full houses.');
fullHouses.forEach(checkFullHouse);
print('Testing dice that are not full houses.');
other.forEach(checkFullHouse);
}

Why not just use the linked solution?
bool isFullHouse(List<int> diceResults) {
String counterString = diceResults.map((i) => i.toString()).join();
return RegExp('20*3|30*2').hasMatch(counterString);
}
int getDiceSum(List<int> diceResults) {
int sum = 0;
for (int i = 0; i < 6; i++) {
sum += [0, 0, 2, 0, 3, 0][i] * (i + 1);
}
return sum;
}
// elsewhere
dice = [0, 0, 2, 0, 3, 0]; // example result
if (isFullHouse(dice)) {
int score = getDiceSum(dice);
// Do something with sum
}

Related

Flutter: doing math to each item in a list?

How do we do math to each item in a list (add numbers from variable and multiply final value) and return another List?
Something like this:
var list = [1, 2, 3, 4, 5];
print(list); // Prints [1, 2, 3, 4, 5]
var list2 = list.map((i) => i * 2 + 5 /* math here*/).toList();
print(list2); // Prints [7, 9, 11, 13, 15]

Contract m-repeated numbers in list to n-repeated (n<m) in place in O(1) space

I want to write a python 3.7 function that has a sorted list of numbers as an input, and a number n which is the max number each one of the integers can be repeated and modifies the list in place, so that any numbers that are repeated more than n times, would be cut to n repeats, and it should be done in O(1) space, no additional data structures allowed (e.g. set()). Special case - remove duplicates where n = 1. Example:
dup_list = [1, 1, 1, 2, 3, 7, 7, 7, 7, 12]
dedup(dup_list, n = 1)
print(dup_list)
[1, 2, 3, 7, 12]
dup_list = [1, 1, 1, 2, 3, 7, 7, 7, 7, 12]
dedup(dup_list, n = 2)
print(dup_list)
[1, 1, 2, 3, 7, 7, 12]
dup_list = [1, 1, 1, 2, 3, 7, 7, 7, 7, 12]
dedup(dup_list, n = 3)
print(dup_list)
[1, 1, 1, 2, 3, 7, 7, 7, 12]
Case n = 1 is easy, the code is below (code is taken from Elements of Prograqmming Interviews, 2008, page 49 except the last line return dup_list[:write_index]):
def dedup(dup_list):
if not dup_list:
return 0
write_index = 1
for i in range(1, len(dup_list)):
if dup_list[write_index-1] != dup_list[i]:
dup_list[write_index] = dup_list[i]
write_index += 1
return dup_list[:write_index]
This should work:
def dedup2(dup_list, n):
count = 1
list_len = len(dup_list)
i = 1
while i < list_len:
if dup_list[i - 1] != dup_list[i]:
count = 1
else:
count += 1
if count > n:
del(dup_list[i])
i -= 1
list_len -= 1
i += 1
return dup_list
print(dedup2([1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 8, 9], 1))

Sorting with higher order functions: Giving precedence to one element

With an unordered array of Ints as such:
let numbers = [4, 3, 1, 5, 2]
Is it possible in Swift, using .sorted { }, to order the array with one item prioritised and placed in the first index of the array. So instead of returning [1, 2, 3, 4, 5] we could get [3, 1, 2, 4, 5]?
You can declare a function like this :
func sort(_ array: [Int], prioritizing n: Int) -> [Int] {
var copy = array
let pivot = copy.partition { $0 != n }
copy[pivot...].sort()
return copy
}
Which uses the partition(by:) function.
You could use it like so:
let numbers = [4, 3, 1, 5, 2]
let specialNumber = 3
sort(numbers, prioritizing: specialNumber) //[3, 1, 2, 4, 5]
Here are some test cases :
sort([3, 3, 3], prioritizing: 3) //[3, 3, 3]
sort([9, 4, 1, 5, 2], prioritizing: 3) //[1, 2, 4, 5, 9]
Here an alternative solution that uses sorted(by:) only :
let numbers = [4, 3, 1, 5, 2]
let vipNumber = 3
let result = numbers.sorted {
($0 == vipNumber ? Int.min : $0) < ($1 == vipNumber ? Int.min : $1)
}
print(result) //[3, 1, 2, 4, 5]

How can I raise all the elements in an int array by a power of 3 in Swift?

For example say I have the array:
let nums = [1, 2, 3, 4, 5, 6]
I would like to output a new array with the cube values: [1, 8, 27, 64, 125, 216]
Do I have to use a loop?
You can use map() and pow() together:
import Foundation
let nums = [1, 2, 3, 4, 5, 6]
let cubes = nums.map { Int(pow(Double($0), 3)) }
let raisedBySix = nums.map { Int(pow(Double($0), 6)) }
print(cubes) // [1, 8, 27, 64, 125, 216]
print(raisedBySix) // [1, 64, 729, 4096, 15625, 46656]

Given two dictionaries containing arrays of different capacities add elements to the lesser populated array

So given this data
var data =
["groupA":
[1, 2, 3, 4, 5, 6],
"groupB":
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
I want this output:
["groupA":
[0, 0, 0, 0, 1, 2, 3, 4, 5, 6],
"groupB":
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
This is the best answer I was able to come up with but I feel like its lacking as I have access to the accumulator that I want to mutate within the reduce function.
let maxElement = data.reduce(data.first!) { (acc, obj) in
return acc.value.count > obj.value.count ? acc : obj
}
for dict in data {
if dict.value.count < maxElement.value.count {
var mutableValues = dict.value
mutableValues.insert(0, at: 0)
data[dict.key] = mutableValues
}
}
I think I'm not understanding how to best refactor my reduce function.
If, like me, you don't like for loops, how about this:
data.reduce(data.values.reduce(0){max($0,$1.count)})
{ data[$1.0] = Array(repeating:0,count:$0-$1.1.count) + $1.1; return $0}
You can get the maximum count of your arrays and create an array of zeros with the difference to append to the lesser populated arrays as follow:
var dict: [String:[Int]] = ["groupA": [1, 2, 3, 4, 5, 6],
"groupB": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
let maxCount = dict.values.map{ $0.count }.max() ?? 0
for (key, value) in dict {
let difference = maxCount - value.count
if difference > 0 {
dict[key] = repeatElement(0, count: difference) + value
}
}
print(dict) // ["groupB": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "groupA": [0, 0, 0, 0, 1, 2, 3, 4, 5, 6]]
As per your question you need to refactor your code for the reduce function, I did it the following way.
Hope this helps,
let maxElement = data.reduce(data.first!) {
$0.value.count > $1.value.count ? $0 : $1
}
further I modified the code you provided to achieve the results you were trying.
and the code worked well for me.
let maxElement = data.reduce(data.first!) {
$0.value.count > $1.value.count ? $0 : $1
}
let minElement = data.reduce(data.first!) {
$0.value.count < $1.value.count ? $0 : $1
}
for dict in data {
if dict.value.count < maxElement.value.count {
var mutableValues = minElement.value
let arrayOfZeros = Array(repeating: 0, count: maxElement.value.count - minElement.value.count)
mutableValues.insert(contentsOf: arrayOfZeros, at: 0)
data[dict.key] = mutableValues
}
}