diff --git a/050-encode_shift.dfy b/050-encode_shift.dfy new file mode 100644 index 0000000..b58a7b1 --- /dev/null +++ b/050-encode_shift.dfy @@ -0,0 +1,48 @@ +function encode_char(c: char): char + requires 'a' <= c <= 'z' + ensures 'a' <= encode_char(c) <= 'z' +{ + ((c as int - 'a' as int + 5) % 26 + 'a' as int) as char +} + +function decode_char(c: char): char + requires 'a' <= c <= 'z' + ensures 'a' <= decode_char(c) <= 'z' + ensures encode_char(decode_char(c)) == c +{ + ((c as int - 'a' as int - 5) % 26 + 'a' as int) as char +} + +method encode_shift(s: string) returns (t: string) + requires forall i :: 0 <= i < |s| ==> 'a' <= s[i] <= 'z' + ensures |s| == |t| + ensures forall i :: 0 <= i < |s| ==> t[i] == encode_char(s[i]) +{ + t := ""; + var i := 0; + while i < |s| + invariant 0 <= i <= |s| + invariant |t| == i + invariant forall j :: 0 <= j < i ==> t[j] == encode_char(s[j]) + { + t := t + [encode_char(s[i])]; + i := i + 1; + } +} + +method decode_shift(s: string) returns (t: string) + requires forall i :: 0 <= i < |s| ==> 'a' <= s[i] <= 'z' + ensures |s| == |t| + ensures forall i :: 0 <= i < |s| ==> t[i] == decode_char(s[i]) +{ + t := ""; + var i := 0; + while i < |s| + invariant 0 <= i <= |s| + invariant |t| == i + invariant forall j :: 0 <= j < i ==> t[j] == decode_char(s[j]) + { + t := t + [decode_char(s[i])]; + i := i + 1; + } +} \ No newline at end of file diff --git a/093-encode.dfy b/093-encode.dfy new file mode 100644 index 0000000..618101d --- /dev/null +++ b/093-encode.dfy @@ -0,0 +1,45 @@ +method encode(s: string) returns (t: string) + requires forall i :: 0 <= i < |s| ==> 'a' <= s[i] <= 'z' || 'A' <= s[i] <= 'Z' + ensures |s| == |t| + ensures forall i :: 0 <= i < |s| && is_vowel(s[i]) ==> t[i] == rot2(swap_case(s[i])) + ensures forall i :: 0 <= i < |s| && !is_vowel(s[i]) ==> t[i] == swap_case(s[i]) +{ + t := ""; + var i := 0; + while i < |s| + invariant 0 <= i <= |s| + invariant |t| == i + invariant forall j :: 0 <= j < i && is_vowel(s[j]) ==> t[j] == rot2(swap_case(s[j])) + invariant forall j :: 0 <= j < i && !is_vowel(s[j]) ==> t[j] == swap_case(s[j]) + { + if is_vowel(s[i]) { + t := t + [rot2(swap_case(s[i]))]; + } else { + t := t + [swap_case(s[i])]; + } + i := i + 1; + } +} + +function swap_case(c: char): char + requires 'a' <= c <= 'z' || 'A' <= c <= 'Z' + ensures 'a' <= c <= 'z' ==> 'A' <= swap_case(c) <= 'Z' + ensures 'A' <= c <= 'Z' ==> 'a' <= swap_case(c) <= 'z' + ensures is_vowel(swap_case(c)) == is_vowel(c) +{ + if 'a' <= c <= 'z' then + 'A' + (c - 'a') + else + 'a' + (c - 'A') +} + +function rot2(c: char): char + requires is_vowel(c) +{ + (c as int + 2) as char +} + +predicate is_vowel(c: char) { + (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') + || (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U') +} \ No newline at end of file diff --git a/109-move_one_ball.dfy b/109-move_one_ball.dfy new file mode 100644 index 0000000..063f6ca --- /dev/null +++ b/109-move_one_ball.dfy @@ -0,0 +1,53 @@ +predicate is_sorted(a: seq) { + forall i, j :: 0 <= i < j < |a| ==> a[i] <= a[j] +} + +method move_one_ball(a: seq) returns (can: bool) + requires |a| > 0 + requires forall i, j :: 0 <= i < |a| && 0 <= j < |a| && i != j ==> a[i] != a[j] + ensures can <==> exists i :: 0 <= i < |a| && is_sorted(a[i..] + a[..i]) +{ + if |a| <= 1 { + assert is_sorted(a[..0]); + return true; + } + can := false; + var i := 0; + var min_index := 0; + while i < |a| + invariant 0 <= i <= |a| + invariant 0 <= min_index < |a| + invariant forall j :: 0 <= j < i && min_index != j ==> a[min_index] < a[j] + { + if a[i] < a[min_index] { + min_index := i; + } + i := i + 1; + } + + assert forall j :: ( + 0 <= j < |a| && min_index != j + ==> ( + (forall i :: j <= i < |a| ==> a[j..][i - j] == a[i]) + && (forall i :: 0 <= i < j ==> (a[j..] + a[..j])[|a| - j + i] == a[i]) + && ( + if min_index < j then + (a[j..] + a[..j])[|a| - j + min_index] == a[min_index] + else + (a[j..] + a[..j])[min_index - j] == a[min_index] + ) + && ( + (exists p :: ( + 1 <= p < |a[j..] + a[..j]| + && (a[j..] + a[..j])[p] == a[min_index] + && (a[j..] + a[..j])[0] > (a[j..] + a[..j])[p] + )) ==> !is_sorted(a[j..] + a[..j]) + ) + ) + ); + + assert forall j :: 0 <= j < |a| && min_index != j ==> !is_sorted(a[j..] + a[..j]); + + var new_a := a[min_index..] + a[..min_index]; + can := is_sorted(new_a); +} \ No newline at end of file diff --git a/112-reverse_delete.dfy b/112-reverse_delete.dfy new file mode 100644 index 0000000..de383b4 --- /dev/null +++ b/112-reverse_delete.dfy @@ -0,0 +1,50 @@ +method reverse_delete(s: string, chars: string) returns (res: string, is_palindrome: bool) + ensures forall i :: 0 <= i < |res| ==> res[i] !in chars + ensures forall i :: 0 <= i < |res| ==> res[i] in s + ensures forall i :: 0 <= i < |s| && s[i] !in chars ==> s[i] in res + ensures is_palindrome <==> is_palindrome_pred(res) +{ + res := ""; + var i := 0; + while i < |s| + invariant 0 <= i <= |s| + invariant forall i :: 0 <= i < |res| ==> res[i] !in chars + invariant forall i :: 0 <= i < |res| ==> res[i] in s + invariant forall j :: 0 <= j < i && s[j] !in chars ==> s[j] in res + { + if s[i] !in chars { + res := res + [s[i]]; + } + i := i + 1; + } + + is_palindrome := check_palindrome(res); +} + +method check_palindrome(s: string) returns (result: bool) + ensures result <==> is_palindrome_pred(s) +{ + if |s| == 0 { + return true; + } + result := true; + var i := 0; + var j := |s| - 1; + while (i < j) + invariant 0 <= i < |s| + invariant 0 <= j < |s| + invariant j == |s| - i - 1 + invariant forall k :: 0 <= k < i ==> s[k] == s[|s| - 1 - k] + { + if (s[i] != s[j]) { + result := false; + break; + } + i := i + 1; + j := j - 1; + } +} + +predicate is_palindrome_pred(s : string) { + forall k :: 0 <= k < |s| ==> s[k] == s[|s| - 1 - k] +} \ No newline at end of file diff --git a/121-solution.dfy b/121-solution.dfy new file mode 100644 index 0000000..4eeffa8 --- /dev/null +++ b/121-solution.dfy @@ -0,0 +1,49 @@ +method solution(numbers: seq) returns (s: int) + ensures s == sum(numbers, seq(|numbers|, i requires 0 <= i < |numbers| => i % 2 == 0 && numbers[i] % 2 == 1)) +{ + var i := 0; + s := 0; + ghost var p := []; + while i < |numbers| + invariant 0 <= i <= |numbers| + invariant |p| == i + invariant s == sum(numbers[..i], p[..i]) + invariant p == seq(i, j requires 0 <= j < i => j % 2 == 0 && numbers[j] % 2 == 1) + { + ghost var old_p := p; + p := p + [i % 2 == 0 && numbers[i] % 2 == 1]; + + assert sum(numbers[..i], p[..i]) == sum(numbers[..i], old_p[..i]) by { + assert p[..i] == old_p[..i]; + } + assert sum(numbers[..i + 1], p[..i + 1]) == sum(numbers[..i], p[..i]) + (if p[i] then numbers[i] else 0) by { + assert numbers[..i+1][..i] == numbers[..i]; + assert p[..i + 1][..i] == p[..i] by { + assert forall j :: 0 <= j < i ==> p[..i + 1][j] == p[..i][j]; + } + sum_prop(numbers[..i + 1], p[..i + 1]); + } + s := s + (if i % 2 == 0 && numbers[i] % 2 == 1 then numbers[i] else 0); + + i := i + 1; + } + assert numbers[..|numbers|] == numbers; + assert p[..|p|] == p; +} + +function sum(s: seq, p: seq) : int + requires |s| == |p| +{ + if |s| == 0 then 0 else (if p[0] then s[0] else 0) + sum(s[1..], p[1..]) +} + +lemma sum_prop(s: seq, p: seq) + requires |s| > 0 + requires |p| == |s| + ensures sum(s, p) == sum(s[..|s| - 1], p[..|s| - 1]) + (if p[|s| - 1] then s[|s| - 1] else 0) +{ + if (|s| > 1) { + assert (s[1..][..|s[1..]| - 1]) == s[1..|s| - 1]; + assert (p[1..][..|p[1..]| - 1]) == p[1..|p| - 1]; + } +} \ No newline at end of file diff --git a/README.md b/README.md index 5d28ac6..86450cf 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Current status: - [ ] 47. median - [x] 48. is_palindrome - [x] 49. modp -- [ ] 50. encode_shift +- [x] 50. encode_shift - [x] 51. remove_vowels - [x] 52. below_threshold - [x] 53. add @@ -95,7 +95,7 @@ Current status: - [ ] 90. next_smallest - nullable - [ ] 91. is_bored - complex strings - [x] 92. any_int -- [ ] 93. encode +- [x] 93. encode - [x] 94. skjkasdkd - [x] 95. check_dict_case - [x] 96. count_up_to @@ -111,19 +111,19 @@ Current status: - [x] 106. f - [ ] 107. even_odd_palindrome - [x] 108. count_nums -- [ ] 109. move_one_ball +- [x] 109. move_one_ball - [x] 110. exchange - [ ] 111. histogram -- [ ] 112. reverse_delete +- [x] 112. reverse_delete - [ ] 113. odd_count -- [ ] 114. minSubArraySum +- [x] 114. minSubArraySum - [x] 115. max_fill - [x] 116. sort_array - sorting - [ ] 117. select_words - complex strings - [x] 118. get_closest_vowel - [ ] 119. match_parens - [ ] 120. maximum - sorting -- [ ] 121. solution - sum +- [x] 121. solution - sum - [x] 122. add_elements - [x] 123. get_odd_collatz - sorting - [ ] 124. valid_date diff --git a/REMAINING.md b/REMAINING.md index 642b432..04d4189 100644 --- a/REMAINING.md +++ b/REMAINING.md @@ -2,30 +2,25 @@ Current status: +## Priority - [ ] 25. factorize -- [ ] 28. concatenate -- [ ] 32. poly - [ ] 36. fizz_buzz + +## Other + +- [ ] 32. poly - [ ] 38. encode_cyclic - [ ] 44. change_base - [ ] 47. median -- [ ] 50. encode_shift -- [ ] 56. correct_bracketing -- [ ] 61. correct_bracketing - [ ] 65. circular_shift - [ ] 79. decimal_to_binary - [ ] 84. solve - [ ] 90. next_smallest - nullable -- [ ] 93. encode - [ ] 103. rounded_avg - [ ] 107. even_odd_palindrome -- [ ] 109. move_one_ball - [ ] 111. histogram -- [ ] 112. reverse_delete - [ ] 113. odd_count -- [ ] 114. minSubArraySum - [ ] 119. match_parens -- [ ] 121. solution - sum - [ ] 124. valid_date - [ ] 129. minPath - [ ] 131. digits @@ -38,11 +33,15 @@ Current status: - [ ] 161. solve - [ ] 162. string_to_md5 - needs hash + ## Complex strings - [ ] 15. string_sequence - [ ] 17. parse_music - [ ] 18. how_many_times - [ ] 19. sort_numbers +- [ ] 28. concatenate +- [ ] 56. correct_bracketing +- [ ] 61. correct_bracketing - [ ] 67. fruit_distribution - [ ] 86. anti_shuffle - [ ] 91. is_bored