I am attempting the following problem:
Two players start with a pile of coins, and each player has the choice of removing either one or two coins from the pile. The player who removes the last coin loses.
I have come up with the following naive, recursive implementation
(playgound):
func gameWinner(coinsRemaining int, currentPlayer string) string {
if coinsRemaining <= 0 {
return currentPlayer
}
var nextPlayer string
if currentPlayer == "you" {
nextPlayer = "them"
} else {
nextPlayer = "you"
}
if gameWinner(coinsRemaining-1, nextPlayer) == currentPlayer || gameWinner(coinsRemaining-2, nextPlayer) == currentPlayer {
return currentPlayer
} else {
return nextPlayer
}
}
func main() {
fmt.Println(gameWinner(4, "you")) // "them"
}
The above code works fine.
However, when I improve this solution by implementing memoization (see below, or on the playgound), I get the wrong answer.
func gameWinner(coinsRemaining int, currentPlayer string, memo map[int]string) string {
if coinsRemaining <= 0 {
return currentPlayer
}
var nextPlayer string
if currentPlayer == "you" {
nextPlayer = "them"
} else {
nextPlayer = "you"
}
if _, exists := memo[coinsRemaining]; !exists {
if gameWinner(coinsRemaining-1, nextPlayer, memo) == currentPlayer || gameWinner(coinsRemaining-2, nextPlayer, memo) == currentPlayer {
memo[coinsRemaining] = currentPlayer
} else {
memo[coinsRemaining] = nextPlayer
}
}
return memo[coinsRemaining]
}
func main() {
memo := make(map[int]string)
fmt.Println(gameWinner(4, "you", memo))
}
Any help as to why the second implementation is returning different values to the first would be greatly appreciated!
Your memoization is wrong: the winner does not only depend on the current number of coins, but also on whose turn it is. You need something like the following:
type state struct {
coinsRemaining int
currentPlayer string
}
memo := make(map[state]string)
Related
I have to write a function for school that decodes Caesar-Encrypted messages. Our teacher gave us the code that encodes the messages, and asked us to write one based on the givenb function that decodes any encrypted message. (The key/shift wasn't given but was explicitly not 3 as in the the encode example, we should figure out ourselves. With online tools i know the key is 17 but for the purpose ofthe question i chose the given example with the known shift of 3)
The given Function with the Shift 3:
func main () {
var textN string = "Wenn man jetzt diesen Text Cäsar-Codieren möchte, dann macht man das so!" // Variable was given by tacher
var textC string = "Zhqq pdq mhwdw glhvhq Whbw Fävdu-Frglhuhq pöfkwh, gdqq pdfkw pdq gdv vr!" // Variable was given by tacher
fmt.Println(textN)
encode(textN)
decode(textC)
}
// The given Function with the shift 3:
func encode (text string){
var ergebnis string
for _,w:=range(text){
if w>='A' && w<='Z' {
if w+3>'Z'{
ergebnis += string((w+3)-'Z'+'A')
} else {
ergebnis += string(w+3)
}
} else if w>='a' && w<='z'{
if w+3>'z' {
ergebnis += string((w+3)-'z'+'a')
} else {
ergebnis += string(w+3)
}
} else {
ergebnis += string(w)
}
}
fmt.Println(ergebnis)
}
// My decode funtion with the "backwards shift" 3:
func decode (text string) {
var ergebnis string
for _,w:=range(text){
if w >='A' && w <='Z' {
if w-3 < 'A' {
// fmt.Println(string(w-3)) // Search for Mistakes made by me
ergebnis += string((w-3)+'Z'-'A')
} else {
// fmt.Println(string(w-3)) // Search for Mistakes made by me
ergebnis += string(w-3)
}
} else if w>='a' && w<='z'{
if w-3 < 'a' {
// fmt.Println(string(w-3)) // Search for Mistakes made by me
ergebnis += string((w-3)+'z'-'a')
} else {
// fmt.Println(string(w-3)) // Search for Mistakes made by me
ergebnis += string(w-3)
}
} else{
ergebnis += string(w)
}
}
fmt.Println(ergebnis)
}
Now the problem is: textN isn't equal to decode(textC), my code seems to fail at lowercase letters that shifted back 3 letters don't become the decoded letters they should be. I saw this at "z" and "x" and i dont have a clue why. I tried highering/lowering the shift but that didn't work, changed plusses and minusses and bigger lower signs. I don't know what to try and am thankful in advance.
there is one solution you can use, i can provide other slower one, but more interesting if you want.
func Chipher(input string, shift int) string {
bts := []rune(input)
var cursor *rune
// i em using it like this to remove repetition but its little advanced
// it may make you suspicious to teacher
shiftFn := func(start, end rune) bool {
r := *cursor
// not in range we cannot shift it
if r < start || r > end {
return false
}
res := start + (r-start+rune(shift))%(end-start)
if res < start {
res += end - start + 1
}
*cursor = res
return true
}
for i := range bts {
cursor = &bts[i]
// this is little trick, if one of expresions returns true, expressions
// after will not get executed as result would be true anyway
_ = shiftFn('a', 'z') || shiftFn('A', 'Z') || shiftFn('0', '9')
}
return string(bts)
}
now this is all beautiful but we have to do tests as well
func TestChipher(t *testing.T) {
testCases := []struct {
desc string
input, output string
shift int
}{
{
desc: "simple shift",
input: "abcd",
shift: 1,
output: "bcde",
},
{
desc: "negative shift",
input: "abcd",
shift: -1,
output: "zabc",
},
{
desc: "numbers",
input: "0123",
shift: 1,
output: "1234",
},
{
desc: "capital letters",
input: "ABCD",
shift: 1,
output: "BCDE",
},
{
desc: "big shift",
input: "ABCD",
shift: 1000,
output: "ABCD",
},
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
res := Chipher(tC.input, tC.shift)
if res != tC.output {
t.Errorf("\n%s :result\n%s :expected", res, tC.output)
}
})
}
}
hope you will learn new things from this
Any suggestions on how to improve the following code to make it more Functional Programming oriented. Specifically how to remove the MutableList which signifies historical states. There are two data classes: Bank, which represents a riverbank (number of missionaries and number of cannibals currently on the bank) and BankState which represents a historical state of the two banks (the source bank, target bank and boatAtSource - a boolean which indicates whether the boat is currently at the source or target bank). overloaded operator function plus adds missionaries and cannibals to a riverbank and function minus removes them from a riverbank. The boat function is the one which carries the most heft. You can call the following algorithm from fun main (app.kt) as such:
app.kt
fun main(args:Array<String>) {
val source:Bank = Bank(3,3)
val target:Bank = Bank()
source boat target
}
Bank.kt
data class Bank(val missionaries:Int=0,val cannibals:Int=0)
data class BankState(val sourceTarget:Pair<Bank,Bank>,val boatAtSource:Boolean)
operator fun Bank.plus(b:Pair<Int,Int>):Bank = Bank(this.missionaries+b.first,this.cannibals+b.second)
operator fun Bank.minus(b:Pair<Int,Int>):Bank = Bank(this.missionaries-b.first,this.cannibals-b.second)
infix fun Bank.boat(target:Bank):List<BankState> {
val begin = Pair(this,target)
val history = mutableListOf<BankState>(BankState(begin,true))
boat(begin,true,this.missionaries,this.cannibals,history)
return history
}
fun boat(sourceTarget:Pair<Bank,Bank>,
boatAtSource:Boolean,
totalMissionaries:Int,
totalCannibals:Int,
history:MutableList<BankState>):Boolean {
if(sourceTarget.first.cannibals+sourceTarget.second.cannibals==totalCannibals &&
sourceTarget.first.missionaries + sourceTarget.second.missionaries==totalMissionaries &&
sourceTarget.first.cannibals>=0 &&
sourceTarget.first.missionaries>=0 &&
sourceTarget.second.cannibals>=0 &&
sourceTarget.second.missionaries>=0 &&
(sourceTarget.first.missionaries==0 || sourceTarget.first.missionaries>=sourceTarget.first.cannibals) &&
(sourceTarget.second.missionaries==0 || sourceTarget.second.missionaries >= sourceTarget.second.cannibals)) {
if(sourceTarget.second.missionaries==totalMissionaries &&
sourceTarget.second.cannibals==totalCannibals) {
history.forEach(::println)
return true
} else {
val deltas = listOf(Pair(0,1),Pair(1,1),Pair(1,0),Pair(2,0),Pair(0,2))
val comparator = object : Comparator<Pair<Pair<Boolean,Int>,Pair<Bank,Bank>>> {
override fun compare(arg1:Pair<Pair<Boolean,Int>,Pair<Bank,Bank>>,arg2:Pair<Pair<Boolean,Int>,Pair<Bank,Bank>>):Int {
if(arg1.first.first && arg2.first.first) {
return if(arg1.first.second<arg2.first.second) -1 else if(arg1.first.second>arg2.first.second) 1 else 0
} else if(arg1.first.first){
return 1
} else if(arg2.first.first) {
return -1
}
return 0
}
}
val result = deltas.map{
checkNext(it.first,it.second,totalMissionaries,totalCannibals,history,sourceTarget,boatAtSource)
}.maxWith(comparator)
if(result?.first?.first!=null && result.first.first) {
history.add(BankState(result.second,!boatAtSource))
return true;
}
}
}
return false
}
fun checkNext(missionariesDelta:Int,
cannibalsDelta:Int,
totalMissionaries:Int,
totalCannibals:Int,
history:MutableList<BankState>,
sourceTarget:Pair<Bank,Bank>,
boatAtSource:Boolean):Pair<Pair<Boolean,Int>,Pair<Bank,Bank>> {
val nextSrcTgt = if(boatAtSource) Pair(sourceTarget.first-Pair(missionariesDelta,cannibalsDelta),sourceTarget.second+Pair(missionariesDelta,cannibalsDelta))
else Pair(sourceTarget.first+Pair(missionariesDelta,cannibalsDelta),sourceTarget.second-Pair(missionariesDelta,cannibalsDelta))
val bankState:BankState = BankState(nextSrcTgt,!boatAtSource)
if(!history.contains(bankState)) {
history.add(bankState)
val combo2:Boolean = boat(nextSrcTgt,!boatAtSource,totalMissionaries,totalCannibals,history)
val combo2Depth = history.size
history.remove(bankState)
return Pair(Pair(combo2,combo2Depth),nextSrcTgt)
} else {
return Pair(Pair(false,0),nextSrcTgt)
}
}
Given an array of integers nums and an integer k. Find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the difference between i and j is at most k.
It is supposed to give me true, but it gives me false.
Any help, I appreciate it. Thank you so much.
class Solution
{
func containsNearbyDuplicate (nums: [Int], _ k: Int) -> Bool
{
var dict = [Int:Int]()
for i in 0..<nums.count
{
if dict[nums[i]] != nil
{
if dict.values.contains(nums[i]) && (i - dict[nums[i]]! <= k)
{
return true
}
else
{
dict[i] = nums[i]
}
}
}
return false
}
}
let test1 = Solution()
//var haha = [1,2,1,5,6,7,6,8,7,5]
//var haha = [1]
//var haha = [1,2]
//var haha = [1,2,3,5,6,8]
var haha = [-1,-1]
var result = test1.containsNearbyDuplicate(haha,1)
print(result)
You never add anything to dict:
func containsNearbyDuplicate (nums: [Int], _ k: Int) ->Bool
{
var dict = [Int:Int]()
for i in 0..<nums.count
{
if dict[nums[i]] != nil // This prevents anything to be added to dict
{
if dict.values.contains(nums[i]) && (i - dict[nums[i]]! <= k)
{
return true
}
else
{
dict[i] = nums[i] // This is never executed because of the above if above
}
}
}
return false
}
Try this one:
class Solution {
func containsNearbyDuplicate (nums: [Int], _ k: Int) ->Bool {
var dict = [Int:Int]()
for i in 0..<nums.count {
if let firstIndex = dict[nums[i]] where i - firstIndex <= k {
return true
}
dict[nums[i]] = i
}
return false
}
}
In my Android app, I am trying to sort Bus route tags in order 1, 2, 3..etc.
For that I am using this
Collections.sort(directions, Comparator { lhs, rhs ->
var obj1 = lhs.short_names.firstOrNull() ?: ""
var obj2 = rhs.short_names.firstOrNull() ?: ""
if (obj1 === obj2) {
obj1 = lhs.headsigns.firstOrNull() ?: ""
obj2 = rhs.headsigns.firstOrNull() ?: ""
if (obj1 === obj2) {
return#Comparator 0
}
obj1.compareTo(obj2)
} else {
obj1.compareTo(obj2)
}
The issue I am having is this sorts them, but will run into the issue of
1, 2, 3, 30, 31, 4, 5
How should I change this to get the correct ordering.
If you need just a simple number comparison you can do it like that.
directions.sortWith(Comparator { lhs, rhs ->
val i1 = lhs.toInt()
val i2 = rhs.toInt()
when {
i1 < i2 -> -1
i1 > i2 -> 1
else -> 0
}
})
As hotkey pointed out the code above can be replaced with almost identical implementation that looks much simplier.
directions.sortBy { it.toInt() }
The general version of this algorithm is called alphanum sorting and described in details here. I made a Kotlin port of this algorithm, which you can use. It's more complicated than what you need, but it will solve your problem.
class AlphanumComparator : Comparator<String> {
override fun compare(s1: String, s2: String): Int {
var thisMarker = 0
var thatMarker = 0
val s1Length = s1.length
val s2Length = s2.length
while (thisMarker < s1Length && thatMarker < s2Length) {
val thisChunk = getChunk(s1, s1Length, thisMarker)
thisMarker += thisChunk.length
val thatChunk = getChunk(s2, s2Length, thatMarker)
thatMarker += thatChunk.length
// If both chunks contain numeric characters, sort them numerically.
var result: Int
if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) {
// Simple chunk comparison by length.
val thisChunkLength = thisChunk.length
result = thisChunkLength - thatChunk.length
// If equal, the first different number counts.
if (result == 0) {
for (i in 0..thisChunkLength - 1) {
result = thisChunk[i] - thatChunk[i]
if (result != 0) {
return result
}
}
}
} else {
result = thisChunk.compareTo(thatChunk)
}
if (result != 0) {
return result
}
}
return s1Length - s2Length
}
private fun getChunk(string: String, length: Int, marker: Int): String {
var current = marker
val chunk = StringBuilder()
var c = string[current]
chunk.append(c)
current++
if (isDigit(c)) {
while (current < length) {
c = string[current]
if (!isDigit(c)) {
break
}
chunk.append(c)
current++
}
} else {
while (current < length) {
c = string[current]
if (isDigit(c)) {
break
}
chunk.append(c)
current++
}
}
return chunk.toString()
}
private fun isDigit(ch: Char): Boolean {
return '0' <= ch && ch <= '9'
}
}
To use this Comparator just call
directions.sortWith(AlphanumComparator())
If you don't need it to be coded in Kotlin you can just take an original Java version on Dave Koelle's page. And the Kotlin version of the algorithm can be also found on GitHub.
I have an array of CLBeacon objects which all have a property .proximity.
I want to order the array by this property which contains the CLProximity enum. So I want all objects to be in order IMMEDIATE, NEAR, FAR, UNKNOWN.
Is there a way to do this neatly without resorting to a bunch of if statements?
If you define a (computed read-only) property sortIndex of CLProximity
extension CLProximity {
var sortIndex : Int {
switch self {
case .Immediate:
return 0
case .Near:
return 1
case .Far:
return 2
case .Unknown:
return 3
}
}
}
then you can sort an array of beacons with
let sortedBeacons = sorted(beacons) { $0.proximity.sortIndex < $1.proximity.sortIndex }
If .Unknown is the only CLProximity value that needs
"special treatment" and all other possible values are in the desired
relative order then you can simplify the property definition to
extension CLProximity {
var sortIndex : Int {
return self == .Unknown ? Int.max : rawValue
}
}
You can use custom comparator and sort an array using that ,
You will "say" for all objects that has "unknown" proximity are "bigger" than others
var sortedArray = persons.sortedArrayUsingComparator {
(obj1, obj2) -> NSComparisonResult in
if obj1.proximity.rawValue == obj12.proximity.rawValue {
return NSComparisonResult.OrderedSame
} else if obj1.proximity == .UNKNOWN || obj1.proximity.rawValue > obj12.proximity.rawValue {
return NSComparisonResult.OrderedDescending
}
return NSComparisonResult.OrderedAscending
}
Based on what Julia wrote above I had cobbled this together:
self.beacons = beacons as! [CLBeacon]
var tempBeacons = zip(self.beacons, self.beacons.map({
(b: CLBeacon) -> Int in
if b.proximity == .Immediate {
return 0
} else if b.proximity == .Near {
return 1
} else if b.proximity == .Far {
return 2
} else if b.proximity == .Unknown {
return 3
}
return 0
}))
self.beacons = sorted(tempBeacons, {$0.1 < $1.1}).map({ $0.0 })
Thanks all!
Based on #Martin answer.
You can also create Int enum and assign value to it and then sort it like below.
enum myEnum: Int {
case A = 0
case B = 1
case C = 2
case D = 3
}
let myData : [myEnum:[String]] = [.C:["3"],.D:["4"],.B:["2"],.A:["1"]]
print(myData.first?.key)
let newData = myData.sorted(by: { $0.key.rawValue < $1.key.rawValue })
print(newData.first?.key)
Hope this helps
Swift 5
Now you can just add Comparable to your enum and it respects the order
enum ContainerLevel: Comparable {
case empty
case almostEmpty
case halfFull
case almostFull
case full
}
//Are we running low?
let needMoreCoffee = coffeeMugLevel > .halfFull
print(needMoreCoffee) //true
Link to more Code examples