[-*- Mode: lispcc -*-] [ Game values for the game of Chomp Copyright 2017 Ken Takusagawa This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ] [-----grammar (gz start (prog)) (gz prog (module)) (gz module (f decl-mark id :class language-pragma-opt exports imports topdecl-star j ::pr("[[language-pragma-opt]]module [[id]] [[exports]] where{\n[[imports]]\n" "[[topdecl-star('',';\n','\n')]]}\n\n"))) (gz language-pragma ( :language-pragma f id-non-star j ::pr ("{-# LANGUAGE [[id-non-star('',',','')]] #-}\n"))) (gz exports (f export-star j ::pr("[[export-star('(',', ',')')]]")) (:export-everything ::pr(""))) (gz export (id)) (gz imports (f import-star j ::pr("[[import-star('',';\n',';\n')]]"))) (gz import(id ::pr( "import [[id]]")) (f :qualified (original-name ::is id) (new-name ::is id) j ::pr ( "import qualified [[original-name]] as [[new-name]]"))) (gz type-class (f decl-mark (class-name ::is id) :type-class context-opt id-non-plus f type-class-decl-star j j ::pr("class [[context-opt]][[class-name]] [[id-non-plus('',' ','')]] where{\n" "[[type-class-decl-star('',';\n','\n')]]}"))) (gz topdecl (decl) (data)(type-synonym)(newtype)(instance)(type-class)) (gz type-class-decl (type-signature)(decl)) (gz type-signature (f :tysig name ret-type-and-params j ::pr("[[name]] :: [[ret-type-and-params]]"))) (gz instance (f :instance (type ::is id) (name ::is simpletype) decls j ::pr ("instance [[type]] ([[name]]) where [[decls]]"))) [(gz instance (f :instance context-opt (type ::is id) simpletype-plus :x decls j ::pr ("instance [[context-opt]][[type]] [[simpletype-plus('(',')(',')')]] where [[decls]]")))] (gz newtype (f decl-mark id :newtype type-vars type deriving-opt j ::pr("newtype [[id]] [[type-vars]] = [[type]][[deriving-opt]]"))) (gz deriving (:deriving f id-non-plus j ::pr(" deriving [[id-non-plus('(',', ',')')]]"))) (gz id-non (id)) (gz type-synonym (f decl-mark id :type-synonym type-vars type j ::pr("type [[id]] [[type-vars]] = [[type]]"))) (gz data (f decl-mark id :data type-vars constrs deriving-opt j ::pr("data [[id]] [[type-vars]] = [[constrs]][[deriving-opt]]"))) (gz simpletype (f id-non-plus j ::pr ("[[id-non-plus('',' ','')]]"))) (gz type-vars (f id-non-star j ::pr ("[[id-non-star('',' ','')]]"))) (gz constrs(f constr-star j ::pr("[[constr-star('',' | ','')]]")) ) (gz field-type-and-param (f param type j ::pr("[[param]] :: [[type]]"))) (gz type-and-param ( f param type j ::pr("[[type]]"))) (gz constr(positional-constructor) (field-label-constructor) ) (gz field-label-constructor(f type-ctor :field f field-type-and-param-star j j ::pr("[[type-ctor]][[field-type-and-param-star('{',', ','}')]]"))) (gz decls ( decl-star ::pr("{[[decl-star('\n',';\n','\n')]]}\n"))) (gz context (:context f a-context-plus j ::pr ("[[a-context-plus('(',', ',')')]] => "))) (gz a-context [(f (type ::is id) id-non-plus j ::pr("[[type]] [[id-non-plus('',' ','')]]"))] (f (class ::is id) type-plus j ::pr("[[class]] [[type-plus('(',')(',')')]]")) ) (gz forall (:forall f id-non-plus j ::pr("forall [[id-non-plus('',' ','')]] . "))) (gz ret-type-and-params (forall-opt context-opt type f type-and-param-star j ::pr("[[forall-opt]][[context-opt]][[type-and-param-star('',' \x2d> ','')]]" (::c "if(my_type_and_param_star->v.size()>0)out(' \x2d> ');") "[[type]]"))) (gz decl (f decl-mark name :fun ret-type-and-params expr j ::pr("[[name]] :: [[ret-type-and-params]];\n" "[[name]]" (::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){" "const tr_type_and_param* t=dynamic_cast(*pos);" "assert(t);" "out(' ');" "t->my_param->print();" "}") " = [[expr]]")) (f decl-mark name :fun :no-sig ret-type-and-params expr j ::pr("[[name]]" (::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){" "const tr_type_and_param* t=dynamic_cast(*pos);" "assert(t);" "out(' ');" "t->my_param->print();" "}") " = [[expr]]")) (f decl-mark name :simple expr j ::pr("[[name]] = [[expr]]")) ) (gz name (id)) (gz positional-constructor (type-ctor ::pr("[[type-ctor]]")) (f type-ctor typepls-opt j ::pr("[[type-ctor]][[typepls-opt]]")) (f :tuple type-plus j ::pr("[[type-plus('(',', ',')')]]")) ) (gz pattern (f pattern-ctor pattern-star j ::pr ("([[pattern-ctor]][[pattern-star('',' ','')]])")) (f pattern-ctor :fpat f fpat-star j j ::pr ("[[pattern-ctor]][[fpat-star('{',', ','}')]]")) (f :ptuple pattern-plus j [pattern-plus cuz :nil exists for empty lists] ::pr("[[pattern-plus('(',', ',')')]]")) (f :plist pattern-plus j [pattern-plus cuz :nil exists for empty lists] ::pr("[[pattern-plus('\x5b',', ','\x5d')]]")) (f :pchar astring j ::pr("(\x27[[astring]]\x27)")) (f :pstring astring j ::pr("\x22[[astring]]\x22")) (f :as id pattern j ::pr("[[id]]@[[pattern]]")) ) (gz pattern-ctor (id) (:cons ::pr ("(:)")) (:nil ::pr ("[]"))) (gz fpat (f (variable ::is id) pattern j ::pr("[[variable]] = [[pattern]]"))) (gz type (f :fn ret-type-and-params j ::pr ("([[ret-type-and-params]])")) (:unit ::pr("()")) (positional-constructor)) (gz typepls (paren-type-plus)) (gz paren-type (type ::pr( "([[type]])")) (f :strict type j ::pr("!([[type]])")) (f :generic id j ::pr (" [[id]] "))) (gz type-ctor(id)(:list ::pr ("[]"))(:nondet ::pr ("[]"))) (gz param (id)) (gz qastring (astring ::pr("\x22[[astring]]\x22"))) (gz expr (id) (:mcons ::pr ("(:)")) [(:nil ::pr ("[]"))] [(f :pipe expr-plus j ::pr[("[[expr-star('(',' $ ',')')]]")] ( (::c "for(many_trees::const_iterator pos = my_expr_plus->v.begin();" "pos!=my_expr_plus->v.end();++pos){") "(" (::c "(*pos)->print();" "}") (::c "for(many_trees::const_iterator pos = my_expr_plus->v.begin();" "pos!=my_expr_plus->v.end();++pos){") ")" (::c "}") ) )] (f :join expr-plus j ::pr("[[expr-plus('(',' >>= ',')')]]")) (f :rpipe expr-plus j ::pr[("[[expr-star('(',' $ ',')')]]")] (["http;//gcc.gnu.org/bugzilla/show_bug.cgi?id=11729"] (::c "for(many_trees::reverse_iterator pos = my_expr_plus->v.rbegin();" "pos!=my_expr_plus->v.rend();++pos){") "(" (::c "(*pos)->print();" "}") (::c "for(many_trees::const_iterator pos = my_expr_plus->v.begin();" "pos!=my_expr_plus->v.end();++pos){") ")" (::c "}") ) ) (f :rcompose expr-plus j ::pr [("[[expr-plus('(',' . ',')')]]")] ("(" (::c "for(many_trees::reverse_iterator pos = my_expr_plus->v.rbegin();" "pos!=my_expr_plus->v.rend();++pos){") (::c "if(pos!=my_expr_plus->v.rbegin())") " . " (::c "(*pos)->print();" "}") ")" ) ) (f :cc expr-star j ::pr ("[[expr-star('(',' ++ ',')')]]")) (qastring) (f :lit astring j ::pr("[[astring]]")) (f :ty type expr j ::pr("([[expr]] :: [[type]])")) (f (fun-name ::is expr) expr-star j ::pr ("([[fun-name]][[expr-star(' ',' ','')]])")) [(f :construct ctor expr-star j ::pr ("([[ctor]] [[expr-star('',' ','')]])"))] (f :do stmt-star j ::pr("(do{\n[[stmt-star(' ','\n ','\n')]]})")) (f :case expr alt-star j ::pr("(case [[expr]] of {\n[[alt-star(' ',';\n ','\n')]]})")) (f :lcase alt-star j ::pr("(\x5clambda_case_var ->" "case lambda_case_var of {\n" "[[alt-star(' ',';\n ','\n')]]})")) (f :let decl-star expr j ::pr("(let {[[decl-star('\n',';\n','\n')]]}\n in [[expr]])")) (f :lambda name ret-type-and-params expr j ::pr("(let {[[name]] :: [[ret-type-and-params]];\n" "[[name]]" (::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){" "const tr_type_and_param* t=dynamic_cast(*pos);" "assert(t);" "out(' ');" "t->my_param->print();" "}") " = [[expr]]} in [[name]])")) (f :cfd (type ::is id) assignments-star j ::pr("[[type]][[assignments-star('{',', ','}')]]")) [(f :compose (a ::is expr) (b ::is expr) j ::pr("((.)[[a]] [[b]])"))] [(:compose ::pr ("(.)"))] [(f :compose expr-plus j ::pr ("[[expr-plus('(',' . ',')')]]"))] (f :mlist expr-star j ::pr("[[expr-star('\x5b',', ','\x5d')]]")) (f :cons-list expr-star j ::pr("[[expr-star('(',':',')')]]")) (f :mtuple expr-star j ::pr("[[expr-star('(',', ',')')]]")) (:nothing ::pr ("()")) [(f :lambda id f pattern-star j expr j ::pr("(\x5c[[pattern-star('',' ','')]] -> [[expr]])"))] ) (gz assignments (f id expr j ::pr("[[id]] = [[expr]]"))) (gz stmt (expr ::pr("[[expr]];")) (f ":=" name type expr j ::pr("[[name]] :: [[type]] <- [[expr]];"))) (gz alt (f pattern expr-or-gpat j ::pr("[[pattern]][[expr-or-gpat]]"))) (gz expr-or-gpat (expr ::pr ("-> [[expr]]")) (f :where decls :gpats pred-expr-star j [silly lookahead limitation] ::pr ("\n[[pred-expr-star('','','')]]" "where " "[[decls]]" ))) (gz pred-expr ( f (pred ::is expr) (do ::is expr) j ::pr ("| [[pred]]\n -> [[do]]\n"))) (gz decl-mark (":")) ] (: Main :class :language-pragma (ScopedTypeVariables) :export-everything ( Control.Exception [Ratio] [Foreign.C.Types] [IO] System.IO.Unsafe [List] [Monad] Control.Monad Control.Monad.ST [Control.Monad.Error] [(:qualified Control.Monad.State State)] [Array] [(:qualified Data.Set Set)] [Data.Set] [System.Directory] (:qualified Data.Map Map) Data.Array.ST Data.Maybe System.Random [Char] System.Environment [Data.Bits] Data.STRef [Numeric] Data.Array.IArray Data.Ord Control.Parallel.Strategies Data.List [(:qualified Data.ByteString B)] [(:qualified Data.Sequence Seq)] [Data.IORef] System.IO [Data.Word] [SHA1] ) (: main :fun (IO :unit)() (:do (hPutStrLn stderr rcs-code) (:join getArgs (:lcase ((:plist(:pstring "nothing"))(return :nothing)) ((:plist(:pstring "go")(num))(go (read num))) ((:plist(:pstring "pnumslow")(num))(:rpipe num read positions-with-n-pieces-slow length print)) ((:plist(:pstring "pnumfast")(num))(:rpipe num read positions-with-n-pieces-fast length print)) )) )) (: show-list :fun :context ((Show(a)))(String)((l(:list(a)))) (unlines (map show l)) ) (: quiet :fun(Bool)() False) (: cerr :fun(a)((message (:list(String)))(x(a))) (:case quiet ((True)x) ((_)(unsafePerformIO (:do (hPutStrLn stderr (concat message)) (return x)))))) (: cerr0 :fun(a)((message(String))(x(a))) (:case quiet ((True)x) ((_)(unsafePerformIO (:do (hPutStrLn stderr message ) (return x)))))) (: cerr-x :fun(a)((_(:list(String)))(x(a)))x) (: peek :fun :context((Show(a)))(a)((x(a))) (seq x (cerr (:mlist(show x)) x))) [(: peek-more :fun(a)((f(:fn(:list(String))((x(a)))))(x(a))) (:case quiet ((True)x) ((_)(seq x (cerr (f x) x)))))] (: peek-more-x :fun(a)((_(:fn(:list(String))((x(a)))))(x(a)))x) (: zip-map :fun(:list(:tuple(a)(b))) ((f(:fn(b)((x(a)))))(l(:list(a)))) (zip l (map f l))) (: zip-map-parallel :fun(:list(:tuple(a)(b))) ((strat(Strategy b))(f(:fn(b)((x(a)))))(l(:list(a)))) (zip l (using (map f l) (parList strat) ))) (: show-and :fun :context ((Show(a))(Show(b))) (IO :unit)((f(:fn(b)((x(a)))))(l(:list(a)))) (:rpipe (zip-map f l) show-list putStr)) (: ntakes :fun(:list(:list(a)))((n(Int))(l(:list(a)))) (:mcons(take n l)(ntakes n (tail l))) ) (: enum-from-count :fun :context ((Enum(a))) (:list(a)) ((start(a))(count(Int))) (take count (enumFrom start))) (: map-tuple :fun(:tuple(b)(b))((fn(:fn(b)((x(a))))) (x(:tuple(a)(a)))) (:mtuple (fn (fst x))(fn (snd x)))) [(: sort-by-extractor :fun :context ((Ord(b)))(:list(a)) ((extract(:fn(b)((x(a)))))(l(:list(a)))) (:let (sortBy (compare-by-extractor extract) l) )) (use sortBy (comparing extract)) ] [(: compare-by-extractor :fun :context ((Ord(b)))(Ordering) ((extract(:fn(b)((x(a)))))(x(a))(y(a))) (compare (extract x)(extract y))) == comparing] (: reverse-comparison :fun (Ordering) ((o(Ordering))) (:case o ((LT)GT) ((EQ)EQ) ((GT)LT) )) (: reverse-comparison-function :fun (:fn(Ordering)((x(a))(y(a)))) ((f(:fn(Ordering)((x(a))(y(a)))))) (:rpipe (:rcompose (uncurry f) reverse-comparison) curry)) (: n-chunk :fun(:list(:list(a)))((n(Int))(l(:list(a)))) (:case l ((:nil)(:mlist) ) ((_)(:mcons (take-enough n l) (n-chunk n (drop n l)))) )) (: take-enough :fun (:list a) ((n Int)(l(:list a))) (:case (compare 0 n) ((EQ)(:mlist)) ((LT)(:case l ((:cons(head)(tail)) (:mcons head (take-enough (pred n)(tail)))))))) [(: zip-check-same-length :fun(:list(:tuple(a)(b))) ((x1(:list(a)))(x2(:list(b)))) (assert (==(length x1)(length x2)) (zip x1 x2)) )] (: zip-check-same-length :fun (:list(:tuple(a)(b))) ((x1(:list(a)))(x2(:list(b)))) (:case (:mtuple x1 x2) ((:ptuple(:nil)(:nil))(:mlist)) ((:ptuple(:cons(a)(arest)) (:cons(b)(brest))) (:mcons(:mtuple a b) (zip-check-same-length arest brest))))) (: zipWith-check-same-length :fun (:list(c)) ((f(:fn(c)((x1(a))(x2(b)))))(x1(:list(a)))(x2(:list(b)))) (:case (:mtuple x1 x2) ((:ptuple(:nil)(:nil))(:mlist)) ((:ptuple(:cons(a)(arest)) (:cons(b)(brest))) (:mcons(f a b) (zipWith-check-same-length f arest brest))))) (: powers-of-two :fun :no-sig(:list(a))() (:mcons 1 (map (* 2) powers-of-two))) (: binary-to-decimal :fun :no-sig (Int) ((bits(:list(Int)))) (sum (zipWith * (reverse bits) powers-of-two))) [(: compress-rle :fun :context ((Eq a)) (:tuple(:list(a))(:list(Int)))((l(:list(a)))) (:let (:mtuple (map head g) (map length g)) (: g :fun :no-sig(:list(:list(a)))() (group l) )) )] [(: uncompress-rle :fun(:list(a))((rle(RLE(a))) ) (:pipe (assert (== (length (fst rle))(length (snd rle)))) (concatMap (uncurry (flip replicate)) ((uncurry zip-check-same-length) rle)) ))] (: apply-first :fun(:tuple(b)(c))((fn(:fn(b)((_(a)))))(x(:tuple(a)(c)))) (:mtuple (fn (fst x))(snd x))) (: apply-second :fun(:tuple(c)(b))((fn(:fn(b)((_(a)))))(x(:tuple(c)(a)))) (:mtuple (fst x)(fn (snd x)))) (: RLE :type-synonym (a)(:tuple(:list(a))(:list(Int)))) (: diffs :fun :no-sig (Maybe(:list(Int))) ((l(:list(Int)))) (:case l ((:nil)Nothing) ((:cons(h)(t)) (Just(:mcons h (zipWith - t l)))))) (: undiff :fun :no-sig (:list(Int))((l(Maybe(:list(Int))))) (:case l ((Nothing)(:mlist)) ((Just(l))(scanl1 + l)) )) (: every-n :fun(:list(a))((n(Int))(l(:list(a)))) (:let (: is-mult :fun (Bool)((i(Int))) (== 0 (mod i n))) (map snd (filter(:rcompose fst is-mult) (zip (enumFrom 0)l))) )) (: tab-split :fun(:list(String))((s(String))) (:let(: br :fun(:tuple(String)(String))()(break (== (:lit "'\t'"))s)) (:mcons (fst br) (:case (snd br) ((:nil)(:mlist)) ((:cons(:pchar "\t")(rest))(tab-split rest))) ) )) (: second-is-longer :fun(Bool)((small(:list(a)))(big(:list(a)))) (:case (:mtuple small big) ((:ptuple(:nil)(_))True) ((:ptuple(_)(:nil))False) ((:ptuple(:cons(_)(r1))(:cons(_)(r2)))(second-is-longer r1 r2)) )) (: is-prefix :fun :context ((Eq(a))) (Bool) ((prefix(:list(a)))(l(:list(a)))) (&&(second-is-longer prefix l) (and (zipWith == prefix l)))) (: is-suffix :fun :context ((Eq(a))) (Bool) ((suffix(:list(a)))(l(:list(a)))) (is-prefix (reverse suffix) (reverse l))) (: concatenate-many-files :fun(IO(String))((files(:list(String)))) (:join (mapM readFile files) (:rcompose concat return)) ) [(: glob-directory :fun(IO(:list(FilePath))) ((dir(FilePath))(prefix(FilePath))(suffix(FilePath))) (:do (:= files (getDirectoryContents dir)) (:pipe return (map (++ (++ dir "/"))) (filter (is-suffix suffix)) (filter (is-prefix prefix)) files) ))] [(: concatenate-glob :fun(IO(String)) ((dir(FilePath))(prefix(FilePath))(suffix(FilePath))) (:do (:= files (glob-directory dir prefix suffix)) (concatenate-many-files files) ))] ["sort-tuple"] (: put-in-order :fun :context((Ord(a)))(:tuple(a)(a))((x(:tuple(a)(a)))) (:case (> (fst x)(snd x)) ((True)(:mtuple (snd x)(fst x))) ((_)x))) (: punch-array :fun :context((Ix(a))) (Array(a)(Bool)) ((bounds(:tuple(a)(a))) (l(:list(a)))) (:let (: set-true :fun (Bool)((_(Bool))(_(Bool))) True ) (accumArray set-true False bounds (zip l (repeat (error "fnord")))) )) (: build-array-from-list :fun :context((Ix(a))) (Array(a)(:list(b))) ((bounds(:tuple(a)(a))) (l(:list(:tuple(a)(b))))) (accumArray snoc (:mlist) bounds l)) (: snoc :fun (:list(a)) ((rest(:list(a)))(h(a))) (:mcons h rest)) (: filter-trues :fun (:list(a))((xb(:list(:tuple(a)(Bool))))) (:rpipe xb (filter snd) (map fst))) (: compare-length-lists :fun (Ordering) ((x(:list(a)))(y(:list(a)))) (:case (:mtuple x y) ((:ptuple(:nil)(:nil))EQ) ((:ptuple(:nil)(_))LT) ((:ptuple(_)(:nil))GT) ((_)(compare-length-lists (tail x)(tail y))))) (: ordering-to-equality :fun :forall (a) (:fn(Bool)((x(a))(y(a)))) ((compare-function(:fn(Ordering)((x(a))(y(a)))))) (:let (: ret-val :fun (Bool) ((x(a))(y(a))) (:case (compare-function x y) ((EQ)True) ((_)False) )) ret-val)) (: sort-and-group-by :fun (:list(:list(a))) ((compare-function(:fn(Ordering)((x(a))(y(a))))) (l(:list(a)))) (:rpipe l (sortBy compare-function) (groupBy ( ordering-to-equality compare-function)) )) (: compare-list-length-with-unity :fun (Ordering) ((l(:list(a)))) (:case l ((:nil)LT) ((:cons(_)(:nil))EQ) ((_)GT) )) (: choose-from-list-randomly :fun (IO(a)) ((l(:list(a)))) (:case l ((:nil)(error "choose-from-list-randomly called on empty list")) ((_) (:join (randomRIO (:mtuple 0 (pred (length l)))) (:rcompose (!! l) return) ) ))) (: uniform-random-IO :fun (IO(Float)) () (randomRIO (:mtuple 0 1))) (: random-permutation-IO :fun (IO(:list(a))) ((l(:list(a)))) (:join (sequence (replicate (length l) uniform-random-IO)) (:rcompose (zip-check-same-length l) (sortBy (comparing snd)) (map fst) return)) ) (: combine-maybes-in-io :fun :context((Monad(io))) (io(Maybe(a))) ((l-to-do(:list(io(Maybe(a)))))) (:case l-to-do ((:nil)(return Nothing)) ((:cons(h)(rest)) (:join h (:lcase ["there's no generic way to test for failure?"] ((Just(_))h) ((_)(combine-maybes-in-io rest)) )) ) ) ) (: is-singleton-list :fun (Bool)((l(:list(a)))) (:case l ((:cons(_)(:nil))True) ((_)False) )) (: first-last :fun (:tuple(a)(a))((l(:list(a)))) (:mtuple (head l)(last l))) (: list-change-at-index :fun (:list(a))((l(:list(a)))(n(Int))(new-value(a))) (:case l ((:cons(head)(tail)) (:case (compare 0 n) ((EQ)(:mcons new-value tail)) ((LT) (:mcons head (list-change-at-index tail (pred n) new-value)))))) [(:cc (take n l) (:mlist new-value) (drop (+ 1 n) l)) does not fail for out of index ] ) (: backwards-tuple :fun (:tuple(b)(a))((x(:tuple(a)(b)))) (:case x ((:ptuple(i)(j))(:mtuple j i)))) (: mk-1-map-array :fun (Array(Int)(b)) ((fn(:fn(b)((x(a))))) (la(:list(a)))) (listArray (:mtuple 1 (length la)) (map fn la))) (: filter-justs :fun (:fn(:list a) ((ll(:list(Maybe a)))))() (:rcompose (filter isJust) (map fromJust))) (: head-only :fun a ((l(:list a))) (:case l ((:plist(x))x) )) (: tail-assert :fun :context ((Eq a))(:list a) ((x(a))(l(:list a))) (assert (== x (head l)) (tail l))) [(: continue-through :fun b ((pred(Bool))(x(b))) (:case pred ((True)x)))] (: singleton :fun (:list a) ((x a)) (:mlist x)) (: rcs-code :fun(String)() "$Id: chomp-trainer.ll,v 1.86 2017/12/05 23:27:00 kenta Exp $") (: Table :type-synonym () (Map.Map Key-position Gamevalue)) (: Gamevalue :data () ((Lose-in(Int))(Win-in(Int))):deriving(Eq Show)) (: table-lookup :fun (Maybe Gamevalue) ((t Table)(p Position)) (Map.lookup p t)) (: Position :newtype () (Position (:list Int)):deriving (Eq Ord Show)) (: Key-position :type-synonym () Position) (: best :fun Gamevalue ((_direction Bool)(vals(:list Gamevalue))) (flip-gamevalue(minimum vals))) (: flip-gamevalue :fun Gamevalue ((g Gamevalue)) (:case g ((Lose-in(i))(Win-in(succ i))) ((Win-in(i))(Lose-in(succ i))))) (: game-value-generate :fun (ST s Bool) ((ptable(STRef s Table))(direction Bool)(position Position)) (:do (:= table (Table) (readSTRef ptable)) (:case (table-lookup table position) ((Just(_))(return True)) ((_)(:let (: moves :fun (:list Position)() (moves-from position)) (:case (sequence (map (table-lookup table) moves)) ((Just(vals)) (:do (write ptable position(best direction vals)) (return True))) ((Nothing) (:do (mapM- (game-value-generate ptable (not direction)) moves) (return False) )))))))) (:instance Ord (Gamevalue) (: compare :fun :no-sig Bool ((x Gamevalue)(y Gamevalue)) (:case x ((Lose-in(xx))(:case y ((Lose-in(yy))(compare xx yy)) ((Win-in(_))LT))) ((Win-in(xx))(:case y ((Lose-in(_))GT) ((Win-in(yy))(compare yy xx)))))) ) (: extract-Position :fun (:list Int) ((p Position)) (:case p ((Position(x))x))) (: moves-from :fun (:list Position) ((p Position)) (:rpipe p extract-Position bit-create-position clean-m2 (map canonicalize) (map count-position) one-only (map Position))) (: count-line :fun Int ((l(:list Bool))) (:rpipe l (takeWhile id) length)) (: count-position :fun (:list Int) ((l(:list(:list Bool)))) (takeWhile (< 0) (map count-line l))) (: bit-create-position-padded :fun (:list Bool) ((width Int)(this Int)) (take width (++(replicate this True)(repeat False)))) (: bit-create-position :fun (:list(:list Bool)) ((l(:list Int))) (:case l ((:cons(h)(t)) (:mcons (replicate h True) (map (bit-create-position-padded h)t))))) (: canonicalize :fun (:list(:list Bool)) ((p(:list(:list Bool)))) (max p (transpose p))) (: m1 :fun (:list(:list Bool)) ((x(:list Bool))) (:case x ((:nil)(:mlist)) ((:cons(True)(rest)) (:mcons (map (const False) x) (:do (:= m2 (:list Bool) (m1 rest)) (return (:mcons True m2)) ))) ((:cons(False)(rest)) (:do (:= m2 (:list Bool) (m1 rest)) (return (:mcons (error "True after False") m2)) )))) (: m2 :fun (:list(:list(:list Bool))) ((x(:list(:list Bool)))) (:case x ((:nil)(:mlist)) ((:cons(line)(rest)) (++ (:do (:= mask (:list Bool)(m1 line)) (return (map (zipWith && mask) x))) (:do (:= do-rest (:list(:list Bool)) (m2 rest)) (return (:mcons line do-rest)) ))))) (: clean-m2 :fun (:list(:list(:list Bool))) ((x(:list(:list Bool)))) (:do (:= r (:list (:list Bool)) (m2 x)) (guard (head (head r))) (return r))) (: show-position :fun String ((x(Position))) (:rpipe x extract-Position bit-create-position(map (map show-pos-char)) unlines)) (: show-pos-char :fun Char ((x Bool)) ((:case x ((True)(head "X")) ((_)(head "."))))) (: one-only :fun :context ((Ord a))(:list a) ((x(:list a))) (:rpipe x sort group (map head) )) (: l-positions :fun (:list Position) () (map Position (:do (:= x Int (enumFrom 1)) (return (:mcons (+ 1 x) (replicate x 1)))))) (: two-positions :fun (:list Position) () (map Position (:do (:= x Int (enumFrom 3)) [skipping 2 because it is also an L position] (return (:mlist x (pred x)))))) [Proposition 2 from Doron Zeilberger, "Three-Rowed Chomp"] (: three-positions :fun (:list Position)() (map Position (:do (:= x Int (enumFrom 4)) (return (:mlist x (- x 2) 2)) ))) (: lost-positions :fun (:list Position) ((limit Int)) (:let (: within-size :fun Bool ((p Position)) (:case p ((Position(:cons(s)(_)))(<= s limit)))) (concat (:mlist (takeWhile within-size l-positions) (takeWhile within-size two-positions) [possibly omit these, as the winning strategy from the position is not well known] (takeWhile within-size three-positions) )))) (: initial-scores :fun Table ((limit Int)) (Map.fromList (:mcons (:mtuple (Position (:mlist 1)) (Lose-in 0)) (:do (:= p Position (lost-positions limit)) (return (:mtuple p (Lose-in 0))))))) (: write :fun (ST s :unit) ((ptable(STRef s Table))(p Position)(v Gamevalue)) (modifySTRef ptable (:lambda modify Table ((t Table)) (Map.insert p v t)))) (: untilST :fun (ST s :unit) ((body(:fn (ST s Bool)()))) (:do (:= done Bool body) (:case done ((True)(return :nothing)) ((_)(untilST body))))) (: solve-game-st :fun (ST s Table) ((limit Int)) (:do (:= ptable (STRef s Table) (newSTRef (initial-scores limit))) (untilST (game-value-generate ptable True (Position (replicate limit limit)))) (readSTRef ptable)) ) (: solve-game :fun Table ((limit Int)) (runST (solve-game-st limit)) ) (: go :fun (IO :unit) ((limit Int)) (:rpipe limit solve-game (Map.toList) show-list putStr)) (: find-move :fun (IO :unit) ((t Table)(f(:list Int))) (:rpipe f Position moves-from (zip-map (table-lookup t)) (sortBy (comparing snd)) show-list putStrLn)) (: positions-with-n-pieces-1 :fun (:list(:list Int)) ((maxwidth Int)(n Int)) (:mcons (:mlist) (:case (|| (== 0 n) (== 0 maxwidth)) ((True)mzero) ((_) (:do (:= x Int (enumFromTo 1 (min maxwidth n))) (:= l (:list Int) (positions-with-n-pieces-1 x (- n x))) (return (:mcons x l)) ))))) (: positions-with-n-pieces-slow :fun (:list Position) ((n Int)) (:rpipe (positions-with-n-pieces-1 n n) tail [omit the empty position] (map Position) (filter is-canonical) )) (: is-canonical :fun Bool ((p Position)) (:rpipe p extract-Position bit-create-position canonicalize count-position Position (== p) )) (: positions-with-n-pieces :fun (:list(:list Int)) ((maxwidth Int)(maxheight Int)(n Int)) (:mcons (:mlist) (:case (or (:mlist (== 0 n) (== 0 maxwidth) (== 0 maxheight))) ((True)mzero) ((_) (:do (:= x Int (enumFromTo 1 (min maxwidth n))) (:= l (:list Int) (positions-with-n-pieces x (pred maxheight) (- n x))) (return (:mcons x l)) ))))) (: positions-with-n-pieces-fast :fun (:list Position) ((n Int)) (:do (:= x Int (enumFromTo 1 n)) (:= l (:list Int) (positions-with-n-pieces x (pred x) (- n x))) (:let (: p :fun Position () (Position (:mcons x l))) (:do (guard (is-canonical p)) (return p) )))) [https;//oeis.org/A046682 gives numbers with exactly N pieces ( not up to N pieces as we have calculated here)] [n=120 answer=8635240371, 9 hours] )