Skip to content

Commit

Permalink
improving details, project euler p98
Browse files Browse the repository at this point in the history
  • Loading branch information
refaktor committed Jan 20, 2025
1 parent fd2dae4 commit 43302b1
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 26 deletions.
43 changes: 43 additions & 0 deletions env/envutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,41 @@ func ToRyeValue(val any) Object {
}
}

func ToRyeValueAggressive(ps *ProgramState, val any) Object { // TODO -- find better name
switch v := val.(type) {
case float64:
return *NewDecimal(v)
case int:
return *NewInteger(int64(v))
case int64:
return *NewInteger(v)
case string:
return *NewString(v)
case rune:
return *NewString(string(v))
case map[string]any:
return *NewDict(v)
case []any:
return *NewList(v)
case *List:
return List2Block(ps, *v)
case *Block:
return *v
case *Object:
return *v
case Object:
return v
case nil:
return nil
case time.Time:
return *NewString(v.Format(time.RFC3339))
default:
fmt.Println(val)
// TODO-FIXME
return Void{}
}
}

func IsPointer(x any) bool {
return reflect.TypeOf(x).Kind() == reflect.Pointer
}
Expand All @@ -59,3 +94,11 @@ func DereferenceAny(x any) any {
func ReferenceAny(x any) any {
return &x
}

func List2Block(ps *ProgramState, s List) Block {
blk := make([]Object, len(s.Data))
for i, val := range s.Data {
blk[i] = ToRyeValueAggressive(ps, val)
}
return *NewBlock(*NewTSeries(blk))
}
66 changes: 52 additions & 14 deletions evaldo/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,19 @@ func (s RyeListSort) Less(i, j int) bool {
return greaterThanNew(env.ToRyeValue(s[j]), env.ToRyeValue(s[i]))
}

// Sort list interface
type RyeStringSort []rune

func (s RyeStringSort) Len() int {
return len(s)
}
func (s RyeStringSort) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s RyeStringSort) Less(i, j int) bool {
return s[i] < s[j]
}

// Custom Sort object interface
type RyeBlockCustomSort struct {
data []env.Object
Expand Down Expand Up @@ -1590,15 +1603,21 @@ var builtins = map[string]*env.Builtin{
Doc: "Returns part of the String between two positions.",
Pure: true,
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
switch s1 := arg1.(type) {
switch s2 := arg1.(type) {
case env.String:
switch s2 := arg0.(type) {
switch s1 := arg0.(type) {
case env.String:
res := strings.Index(s2.Value, s1.Value)
res := strings.Index(s1.Value, s2.Value)
return *env.NewInteger(int64(res))
default:
return MakeArgError(ps, 2, []env.Type{env.StringType}, "index?")
}
case env.Block:
res := util.IndexOfSlice(ps, s2.Series.S, arg0)
if res == -1 {
return MakeBuiltinError(ps, "not found", "index?")
}
return *env.NewInteger(int64(res))
default:
return MakeArgError(ps, 1, []env.Type{env.StringType}, "index?")
}
Expand All @@ -1613,21 +1632,21 @@ var builtins = map[string]*env.Builtin{
Doc: "Returns part of the String between two positions.",
Pure: true,
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
switch s1 := arg0.(type) {
case env.String: // TODO-FIX ... let s1 be any type if s2 is block, and string only if s2 is string .. reverse nesting in switches
switch s2 := arg1.(type) {
switch s2 := arg1.(type) {
case env.String:
switch s1 := arg0.(type) {
case env.String:
res := strings.Index(s1.Value, s2.Value)
return *env.NewInteger(int64(res + 1))
case env.Block:
res := util.IndexOfSlice(ps, s2.Series.S, s1)
if res == -1 {
return MakeBuiltinError(ps, "not found", "position?")
}
return *env.NewInteger(int64(res + 1))
default:
return MakeArgError(ps, 2, []env.Type{env.StringType}, "position?")
}
case env.Block:
res := util.IndexOfSlice(ps, s2.Series.S, arg0)
if res == -1 {
return MakeBuiltinError(ps, "not found", "position?")
}
return *env.NewInteger(int64(res + 1))
default:
return MakeArgError(ps, 1, []env.Type{env.StringType}, "position?")
}
Expand Down Expand Up @@ -2073,6 +2092,20 @@ var builtins = map[string]*env.Builtin{
}
}
return *env.NewBlock(*env.NewTSeries(res))
case env.List:
res := make([]any, 0)
for _, val := range bloc.Data {
switch val_ := val.(type) {
case env.List:
res = append(res, val_.Data...)
//for _, val2 := range val_.Series.S {
// res = append(res, val2)
// }
default:
res = append(res, val)
}
}
return *env.NewList(res)
default:
return MakeArgError(ps, 1, []env.Type{env.BlockType}, "unpack")
}
Expand Down Expand Up @@ -2816,8 +2849,13 @@ var builtins = map[string]*env.Builtin{
copy(copied, block.Data)
sort.Sort(RyeListSort(copied))
return *env.NewList(copied)
case env.String:
copied := []rune(block.Value)
// copy(copied, block.Data)
sort.Sort(RyeStringSort(copied))
return *env.NewString(string(copied))
default:
return MakeArgError(ps, 1, []env.Type{env.BlockType, env.ListType}, "sort!")
return MakeArgError(ps, 1, []env.Type{env.BlockType, env.ListType, env.StringType}, "sort")
}
},
},
Expand Down Expand Up @@ -4774,7 +4812,7 @@ var builtins = map[string]*env.Builtin{
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
switch list := arg0.(type) {
case env.List:
return util.List2Block(ps, list)
return env.List2Block(ps, list)
default:
return MakeArgError(ps, 1, []env.Type{env.DictType}, "to-context")
}
Expand Down
2 changes: 1 addition & 1 deletion examples/project-euler/prob001.rye
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
; sum all factors of 3 and 5 smaller than 1000

range 0 1000
|filter { :x all { x .multiple-of 3 x .multiple-of 5 } }
|filter { ::x all { x .multiple-of 3 x .multiple-of 5 } }
|sum .print

; result 33165
Expand Down
5 changes: 2 additions & 3 deletions examples/project-euler/prob002.rye
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
; Sum all even numbers in fibonnaci sequence that are smaller than 4 million

produce\while { .last < 4000000 } { 1 2 } ; condition and a starting block
{ :b .tail 2 |sum .concat* b } ; sums last 2 elements and concat's result to block
|head -1 ; last one is already greater than 4 million
|filter { .even } ; filter to even numbers
{ ::b .tail 2 |sum .concat* b } ; sums last 2 elements and concat's result to block
|filter { .even } ; filter out even numbers
|sum .print ; sum them and print

; result: 4613732
Expand Down
57 changes: 57 additions & 0 deletions examples/project-euler/prob098.rye
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
;# Project Euler: Problem 98 - Base on Jared Krinje's code
; https://github.com/jaredkrinke/100-languages/blob/main/src/p98.rye
;
; Algorithm: first, count characters in words to find anagrams, then compute
; the transformation required for each anagram pair (by counting the first
; character as "1", second as "2", etc., using previous digits for repeated
; characters--note that the pattern of the source word must also be included to
; distinguish "abc" from "abb" or "aba"), and finally find the intersection of
; word and square transformations and take the largest square.

; Utilities
permute-pairs: fn { list } { .map { ::x list |filter { = x |not } |map { ::y [ x y ] } } |unpack }

; Anagram finder (list of lists)
find-anagrams: fn { l } {
.map { ::w [ w sort w ] } :info
|map { .second } |sort |partition { , } |filter { .length? > 1 } |map { .first } :anagrams
info
|filter { .second .contains* anagrams }
|map { .first }
|group { .sort }
|values .to-block
|map { .permute-pairs }
|unpack
}

; "Normalize" two words (could be digits or letters) by calculating the position of characters of a in b
get-transformation: fn { pair } {
.second :b , .first :a
|split "" |vals\with {
.map { .position?* a } |join ,
.map { .position?* b } |join
} |join\with "-"
}

; Find anagrams from words file and keep transformations only
word-anagrams:
split\quoted read %0098_words.txt "," `"` ;"
|find-anagrams
|map { .get-transformation } |probe
,

; Find square anagrams and compute each pair's transformation, keeping that and the larger square
square-anagrams:
range 1 1000
|map { ::n , n * n |to-string }
|find-anagrams
|map { .vals\with { .map { .to-integer } |max , .get-transformation } } |probe
,

; Intersect the two lists
anagramic-squares:
square-anagrams
|filter { .second .contains* word-anagrams }
|map { .first }
|print
,
67 changes: 67 additions & 0 deletions examples/project-euler/prob098_jared.rye
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
;# Project Euler: Problem 98 - Solution by Jared Krinke in his 100-languages project
; https://github.com/jaredkrinke/100-languages/blob/main/src/p98.rye
;
; Algorithm: first, count characters in words to find anagrams, then compute
; the transformation required for each anagram pair (by counting the first
; character as "1", second as "2", etc., using previous digits for repeated
; characters--note that the pattern of the source word must also be included to
; distinguish "abc" from "abb" or "aba"), and finally find the intersection of
; word and square transformations and take the largest square.

; Utilities
split\characters: fn { s } { s |split "" }
contains?: fn { l i } { ( filter l { = i } ) .length? > 0 }
concat\lists: fn { list } { reduce list 'acc { .concat* acc } }
pairs\permutations: fn { list } { list |map { ::x list |filter { = x |not } |map { ::y [ x y ] } } |concat\lists }
group: fn { list get-key } {
info: list |map { ::o [ o ( do concat { o } get-key ) ] } ,
groups: info |map { .second } |sort |unique ,
groups |map { ::key , [ key ( info |filter { .second = key } ) |map { .first } ] }
}

; Anagram finder (list of lists)
sort-word: fn { word } { word |split\characters |sort |join }
find-anagrams: fn { l } {
info: l |map { ::w [ w sort-word w ] } ,
anagrams: info |map { .second } |sort |partition { , } |filter { .length? > 1 } |map { .first } ,
info
|filter { ::x contains? anagrams second x }
|map { .first }
|group { .sort-word }
|map { .second .pairs\permutations }
|concat\lists
}

; "Normalize" two words (could be digits or letters) by calculating the position of characters of a in b
get-transformation: fn { pair } {
a: first pair ,
b: second pair ,
al: ( a |split\characters ) ,
a1: al |map { .position?* a } |join ,
a2: al |map { .position?* b } |join ,
join [ a1 "-" a2 ]
}

; Find anagrams from words file and keep transformations only
word-anagrams:
( split\quoted read %0098_words.txt "," `"` ) ; "
|find-anagrams
|map { .get-transformation }
,

; Find square anagrams and compute each pair's transformation, keeping that and the larger square
square-anagrams:
range 1 1000
|map { ::n n * n }
|map { .to-string }
|find-anagrams
|map { ::pair [ ( max ( pair |map { .to-integer } ) ) ( get-transformation pair ) ] }
,

; Intersect the two lists
anagramic-squares:
square-anagrams
|filter { ::o contains? word-anagrams ( second o ) }
|map { .first }
|print
,
8 changes: 0 additions & 8 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,6 @@ func IsTruthy(o env.Object) bool {
}
}

func List2Block(ps *env.ProgramState, s env.List) env.Block {
blk := make([]env.Object, len(s.Data))
for i, val := range s.Data {
blk[i] = env.ToRyeValue(val)
}
return *env.NewBlock(*env.NewTSeries(blk))
}

func Dict2Context(ps *env.ProgramState, s1 env.Dict) env.RyeCtx {
ctx := env.NewEnv(ps.Ctx)
for k, v := range s1.Data {
Expand Down

0 comments on commit 43302b1

Please sign in to comment.