Feed Aggregator Page 649
Rendered on Mon, 21 Sep 2020 20:33:28 GMT
Rendered on Mon, 21 Sep 2020 20:33:28 GMT
via Elm - Latest posts by @tibastral Thibaut Assus on Mon, 21 Sep 2020 15:37:10 GMT
As hovering over elements is a behavior I prefer to handle that in elm
via Elm - Latest posts by @dillonkearns Dillon Kearns on Mon, 21 Sep 2020 14:07:31 GMT
In this episode, we discuss two game-changing Richard Feldman talks, and how to apply those ideas to your codebase. It was a lot of fun to revisit the talks and do a deep dive on these topics. Hope you enjoy!
And of course, if you haven’t seen the talks, they’re well worth a watch!
via Elm - Latest posts by @razze Kolja Lampe on Mon, 21 Sep 2020 12:43:51 GMT
Totally subjective, but it seems, like we currently get this every week. I think I saw three people mention in slack, that they renamed themselves on github, not sure why that’s so popular right now.
via Elm - Latest posts by @klemola Matias Klemola on Mon, 21 Sep 2020 07:38:11 GMT
Ouch. I saw Robin’s PSA about the name change, but I didn’t consider that his projects could be indirect dependencies. Luckiy elm.json is flexible enough to make those deps into proper deps, at least temporarily.
via Elm - Latest posts by @system system on Sun, 20 Sep 2020 12:59:25 GMT
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
via Planet Lisp by on Sun, 20 Sep 2020 04:25:30 GMT
Dawn of the second day.
According to the internet, the thing I intend to build is called a Roguelikelike, teetering on the very edge of being a Roguelike. So it goes; we'll see if I end up taking the title or not.
Last time, we laid out the basics of prisoner
s, their interactions and their strategies. This time, lets get some different scenarios and some player interaction going.
Payoff matrices involve deciding who gets what bonus or penalty as a result of an interaction. Given a pair of defect
/cooperate
choices, a payoff-matrix
will return the scores to be delivered to each player in turn.
(defun payoff-matrix (cc-a cc-b cd-a cd-b dc-a dc-b dd-a dd-b)
(let ((tbl {(cons :cooperate :cooperate) (list cc-a cc-b)
(cons :defect :cooperate) (list dc-a dc-b)
(cons :cooperate :defect) (list cd-a cd-b)
(cons :defect :defect) (list dd-a dd-b)}))
(lambda (a b) (lookup tbl (cons a b)))))
Now we can define some basic scenarios. A dilemma
is the name I'll pick for the situation where co-operating is better for the group, and both defecting is the worst thing for everyone, but a single defector will end out better off by defecting.
(defparameter dilemma
(payoff-matrix
3 3 1 5
5 1 0 0))
A stag-hunt
is a situation where a pair of players can pool their resources for a greater prize, and ignore each other for the lesser. If either player attempts to hunt the stag alone, they get nothing, while their defecting partner still gets a rabbit.
(defparameter stag-hunt
(payoff-matrix
3 3 0 1
1 0 1 1))
A trade
is one in which both parties benefit, but to which both parties must agree.
(defparameter trade
(payoff-matrix
3 3 0 0
0 0 0 0))
A theft
is one where a player takes from the other. But if both players cooperate, or both try to rob each other, they come to an impasse.
(defparameter theft
(payoff-matrix
0 0 -3 3
3 -3 0 0))
A trap
is a situation where cooperating leads to disaster, ignoring the situation leads to no gain, and defect
ing to make it clear to your partner that you don't intend to follow ends up benefiting both players.
(defparameter trap
(payoff-matrix
-3 -3 2 2
2 2 0 0))
The last scenario I'll concern myself with is the mutual-prediction
. Where guessing what your partner/opponent will choose benefits you, and failing to do so does nothing.
(defparameter mutual-prediction
(payoff-matrix
3 3 0 0
0 0 3 3))
In order to move through the world, our prisoner
s need a world to move through. Let us begin at the ending.
(defparameter ending
{:description "You have come to the end of your long, perilous journey."})
There is nothing to do at the end other than display this fact.
(defun repl! (adventure)
(format t "~%~%~a~%~%" (lookup adventure :description)))
THE-PRISONERS> (repl! ending)
You have come to the end of your long, perilous journey.
NIL
THE-PRISONERS>
But what led us here was a choice. An adventure is more than a description, it's also the options, a prisoner
, the scenario
, and a way to continue
the action. continue
ing means making a choice and effectively playing the opposing/cooperating prisoner
and abiding by the results.
(defun mk-adventure ()
(let ((prisoner (polo)))
{:description
"A stranger approaches. \"I see you have baubles. Would you like to trade, that we both may enrich ourselves?\""
:cooperate "accept" :defect "refuse" :prisoner prisoner :scenario trade
:continue (lambda (choice)
(let ((their-choice (play prisoner)))
(update! prisoner choice)
(funcall trade choice their-choice)
ending))}))
This sort of adventure also takes a bit more machinery to run from the repl
. We need to present the description
, but also get an appropriate choice from the user. Getting that choice is a bit more complicated than you might think at first.
(defun get-by-prefix (lst prefix)
(let ((l (length prefix)))
(loop for elem in lst
when (and (>= (length elem) l)
(== (subseq elem 0 l) prefix))
do (return elem))))
(defun get-repl-choice (adventure)
(let* ((responses (mapcar #'string-downcase (list (lookup adventure :cooperate) (lookup adventure :defect))))
(r-map {(string-downcase (lookup adventure :cooperate)) :cooperate
(string-downcase (lookup adventure :defect)) :defect})
(by-pref nil)
(resp ""))
(loop until (and (symbolp resp)
(setf by-pref
(get-by-prefix
responses
(string-downcase (symbol-name resp)))))
do (format
t "~a/~a:"
(lookup adventure :cooperate)
(lookup adventure :defect))
do (setf resp (read)))
(lookup r-map by-pref)))
Well behaved players are easy to deal with, true...
THE-PRISONERS> (get-repl-choice (mk-adventure))
Accept/Refuse:acc
:COOPERATE
T
THE-PRISONERS> (get-repl-choice (mk-adventure))
Accept/Refuse:ref
:DEFECT
T
THE-PRISONERS> (get-repl-choice (mk-adventure))
Accept/Refuse:a
:COOPERATE
T
... but we want to be a bit more general than that.
THE-PRISONERS> (get-repl-choice (mk-adventure))
Accept/Refuse:fuck you
Accept/Refuse:Accept/Refuse:boo
Accept/Refuse: (error 'error)
Accept/Refuse: (quit)
Accept/Refuse:r
:DEFECT
T
THE-PRISONERS>
That's the only hard par though. Interacting with the game once we're sure we have valid input from our player is relatively simple.
(defun repl! (adventure)
(format t "~%~%~a~%~%" (lookup adventure :description))
(when (contains? adventure :continue)
(let ((choice (get-repl-choice adventure)))
(repl! (funcall (lookup adventure :continue) choice)))))
THE-PRISONERS> (repl! (mk-adventure))
A stranger approaches. "I see you have baubles. Would you like to trade, that we both may enrich ourselves?"
Accept/Refuse:acc
You have come to the end of your long, perilous journey.
NIL
THE-PRISONERS>
This is obviously not the perilous journey being spoken of. At least, not all of it. The simplest way to extend it into one is to wrap scenario
s around our existing adventure
.
(defun mk-adventure ()
(let ((def (defector)))
{:description "A muscled street thug approachs, knife drawn."
:cooperate "surrender" :defect "run" :prisoner def :scenario theft
:continue (lambda (choice)
(let ((their-choice (play def)))
(update! def choice)
(funcall theft choice their-choice))
(let ((prisoner (polo)))
{:description
"A stranger approaches. \"I see you have baubles. Would you like to trade, that we both may enrich ourselves?\""
:cooperate "accept" :defect "refuse" :prisoner prisoner :scenario trade
:continue (lambda (choice)
(let ((their-choice (play prisoner)))
(update! prisoner choice)
(funcall trade choice their-choice)
ending))}))}))
THE-PRISONERS> (repl! (mk-adventure))
A muscled street thug approachs, knife drawn.
Surrender/Run:run
A stranger approaches. "I see you have baubles. Would you like to trade, that we both may enrich ourselves?"
Accept/Refuse:acc
You have come to the end of your long, perilous journey.
NIL
THE-PRISONERS>
Of course, since we want it to be much longer and more perilous, we'll want that process automated to at least some degree.
(defun wrap-scenario (adventure scenario)
(insert
scenario
(cons
:continue
(lambda (choice)
(let* ((them (lookup scenario :prisoner))
(their-choice (play them)))
(update! them choice)
(funcall (lookup scenario :scenario) choice their-choice)
adventure)))))
(defun mk-adventure ()
(wrap-scenario
(wrap-scenario
ending
{:description
"A stranger approaches. \"I see you have baubles. Would you like to trade, that we both may enrich ourselves?\""
:cooperate "accept" :defect "refuse" :prisoner (polo) :scenario trade})
{:description
"A muscled street thug approachs, knife drawn. \"Yer money or yer life, fop!\""
:cooperate "surrender" :defect "run" :prisoner (defector) :scenario theft}))
This isn't enough for the Roguelikelike title, and I don't think I'll get there today, but I do want the ability to make an arbitrarily long adventure. The dumbest way of doing this is to make a list of scenarios, and pick from them when the need arises.
(defun random-scenario ()
(pick
(list
{:description
"A stranger approaches. \"I see you have baubles. Would you like to trade, that we both may enrich ourselves?\""
:cooperate "accept" :defect "refuse" :prisoner (polo) :scenario trade}
{:description
"A muscled street thug approachs, knife drawn. \"Yer money or yer life, fop!\""
:cooperate "surrender" :defect "run" :prisoner (defector) :scenario theft})))
(defun mk-adventure (&key (scenarios 5))
(let ((adventure ending))
(loop repeat scenarios
do (setf adventure (wrap-scenario adventure (random-scenario))))
adventure))
An adventure of even 5 scenarios will end up being repetitive since we currently only have a grand total of two. But we can do something about that...
(defun random-scenario ()
(pick
(list
{:description
"A stranger approaches. \"I see you have baubles. Would you like to trade, that we both may enrich ourselves?\""
:cooperate "accept" :defect "refuse" :prisoner (polo) :scenario trade}
{:description
"A muscled street thug approachs, knife drawn. \"Yer money or yer life, fop!\""
:cooperate "surrender" :defect "run" :prisoner (defector) :scenario theft}
{:description
"As you walk through an expansive market square, a gambler motions you over. \"Fancy your chances at evens or odds?"
:cooperate "Evens!" :defect "Odds!" :prisoner (gambler) :scenario mutual-prediction}
{:description
"A hunter approaches you in a forest clearing. \"Hallo there, young one. Would you help me hunt a deer? I've had enough hares for now, but I promise we'll eat well if we work together!\""
:cooperate "<Nocks bow>" :defect "Rather go my own way" :prisoner (dantes) :scenario stag-hunt}
{:description
"\"Hey follow me into this bear trap!\""
:cooperate "Sure; I've grown tired of living" :defect "No. No, I'd rather not."
:prisoner (robin) :scenario trap}
{:description
"You see a merchant ahead of you, paying little attention to his overfull coin purse. You could cut it and run."
:cooperate "It's too tempting" :defect "No; I hold strong"
:prisoner (dantes) :scenario theft}
{:description
"At the end of your travails with your co-conspirator, you get to the treasure first and can pocket some if you want."
:cooperate "Take it" :defect "No, we split fairly"
:prisoner (gambler :defect 5) :scenario dilemma})))
This gives me some ideas about how to go about generating scenarios a lot more programmatically, but I'll leave that for later, when I'm in the right frame of mind to do cosmetic improvements.
THE-PRISONERS> (repl! (mk-adventure))
At the end of your travails with your co-conspirator, you get to the treasure first and can pocket some if you want.
Take it/Split fairly:split
You see a merchant ahead of you, paying little attention to his overfull coin purse. You could cut it and run.
It's too tempting/No:it's
"Hey follow me into this bear trap!"
Sure; I've grown tired of living/No. No, I'd rather not.:no
You see a merchant ahead of you, paying little attention to his overfull coin purse. You could cut it and run.
It's too tempting/No:it's
A stranger approaches. "I see you have baubles. Would you like to trade, that we both may enrich ourselves?"
accept/refuse:accept
You have come to the end of your long, perilous journey.
NIL
THE-PRISONERS>
This is about as far as I'm going today, and I'm not entirely sure how far I'm going during my next session.
As always, I'll let you know.
via Elm - Latest posts by @system system on Sun, 20 Sep 2020 07:16:40 GMT
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
via Elm - Latest posts by @Yannick971 Yannick on Sat, 19 Sep 2020 23:17:42 GMT
Thanks a lot, very nice solution, I will try this… (its a public API I don’t have access to the backend).
Maybe the title of my post should be changed to something more in tune with the topic actually, I don’t have the required permission.
via Elm - Latest posts by @pdamoc Peter Damoc on Sat, 19 Sep 2020 05:04:28 GMT
First, if you have 5 sets of data it would be better to model each as a remote data. You can take a look remotedata-http for more information. This assumes that you might want to display partial data (data from some of the 5 endpoints as it arrives). If you want an all or nothing approach, you might also look into Http.task
and Task.sequence
.
Now, on to the filtering. This logic looks to me like it belongs in the backend BUT, if you don’t have access to the backend and there is no way to call it with some timestamp parameter, you can still do the filtering in the decoding step.
import Json.Decode as Json
type alias Timestamp =
{ timestamp : Int
, value : Int
}
oneHour : Int
oneHour = 3600000
timestampDecoder : Decoder Timestamp
timestampDecoder =
Json.map2 Timestamp
(Json.field "timestamp" Json.int)
(Json.field "value" Json.int)
oneHourFilter : List Timestamp -> List Timestamp
oneHourFilter timestamps =
List.filter (\t -> now + oneHour > t.timestamp ) timestamps
timestampListDecoder : Int -> Decoder (List Timestamp)
timestampListDecoder now =
Json.list timestampDecoder
|> Json.map oneHourFilter
You would then get the current time and call the endpoints using (timestampListDecoder now)
getTimestamps : Int -> Cmd Msg
getTimestamps now =
Http.get
{ url = "https://your-host.com/api/some-timestamps"
, expect = Http.expectJson GotTimestamps (timestampListDecoder now)
}
via Planet Lisp by on Sat, 19 Sep 2020 00:19:48 GMT
Ok, so I guess I'm doing this.
In hopes of participating in the Autumn Lisp 2020 Game Jam, I'm going to write a multiplayer game. It's going to deal with players in several ways, implement 1FA, and probably end up being asymmetric and heavily infulenced by some readings that The Cabal have been doing lately.
But don't worry about that for the moment.
(in-package #:the-prisoners)
(named-readtables:in-readtable clj:syntax)
I'm using clj
. You can find it on my github, and it'll be included as part of the asd
file.Ahem.
Prisoners can do two things. They can cooperate
or they can defect
.
(defun coop? (res) (eq :cooperate res))
(defun defe? (res) (eq :defect res))
In order to play a game, you take the game
function and apply
it to the ordered list of prisoners
that will be playing.
(defun play! (game &rest players)
(apply game players))
A two-player, one-time game looks like this:
prisoner
scooperate
or defect
To start with, we're going with a payoff matrix that looks like
| Cooperate | Defect
------------------------------
Cooperate | 3, 3 | 1, 5
------------------------------
Defect | 5, 1 | 0, 0
------------------------------
We might play with this later, but lets pretend we won't have the time.
(defun one-time (player-a player-b)
(let ((a (funcall (lookup player-a :strategy)))
(b (funcall (lookup player-b :strategy))))
(if-let (update (lookup player-a :update))
(funcall update b))
(if-let (update (lookup player-b :update))
(funcall update a))
(cond ((and (coop? a) (coop? b))
(list 3 3))
((and (coop? a) (defe? b))
(list 1 5))
((and (defe? a) (coop? b))
(list 5 1))
(t
(list 0 0)))))
The two simplest possible prisoners we can have are one who always :cooperate
s, and one who always :defect
s. A prisoner
needs to be able to take into account what their opponent did last time, and separately, do something.
(defun defector ()
{:name :defector :strategy (lambda () :defect)})
(defun cooperator ()
{:name :cooperator :strategy (lambda () :cooperate)})
We can now play. Would you like to play a game?
THE-PRISONERS> (play! #'one-time (defector) (cooperator))
(5 1)
THE-PRISONERS> (play! #'one-time (cooperator) (defector))
(1 5)
THE-PRISONERS> (play! #'one-time (cooperator) (cooperator))
(3 3)
THE-PRISONERS> (play! #'one-time (defector) (defector))
(0 0)
THE-PRISONERS>
There are other, simple kinds of prisoners. One is the prisoner who tosses a coin and does what it tells them to.
(defun gambler ()
{:name :gambler :strategy (lambda () (nth (random 2) (list :cooperate :defect)))})
The more general case doesn't necessarily flip a coin, but can weigh either :cooperate
or :defect
more strongly.
(defun gambler (&key (cooperate 1) (defect 1))
(let ((total (+ cooperate defect))
(moves (concatenate
'list
(loop repeat cooperate collect :cooperate)
(loop repeat defect collect :defect))))
{:name (intern (format nil "GAMBLER~a/~a" cooperate defect) :keyword)
:strategy (lambda () (nth (random total) moves))}))
This way, we can get a true coin-flipper.
THE-PRISONERS> (gambler)
{:NAME :GAMBLER1/1 :STRATEGY #<CLOSURE (LAMBDA () :IN GAMBLER) {1003B5824B}>}
THE-PRISONERS>
Or someone who mostly cooperates/defects, but sometimes defects/cooperates.
THE-PRISONERS> (gambler :cooperate 5)
{:NAME :GAMBLER5/1 :STRATEGY #<CLOSURE (LAMBDA () :IN GAMBLER) {1003B69F0B}>}
THE-PRISONERS> (gambler :defect 5)
{:NAME :GAMBLER1/5 :STRATEGY #<CLOSURE (LAMBDA () :IN GAMBLER) {1003B6C38B}>}
THE-PRISONERS>
How do they play against each of the others? Lets find out.
(defun matches (elems &key (mirror? t))
(loop for (a . rest) on elems while rest
if mirror? collect (cons a a)
append (loop for b in rest collect (cons a b))))
(defun all-against-all! (game matches)
(reduce
(lambda (memo res)
(merge-by #'+ memo res))
(loop for (a . b) in matches
collect (let ((res (play! game a b)))
{(lookup a :name) (first res) (lookup b :name) (second res)}))))
This lets us see who does better against everyone.
THE-PRISONERS> (all-against-all! #'one-time (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5))))
{:GAMBLER1/5 13 :GAMBLER1/1 9 :GAMBLER5/1 8 :DEFECTOR 10 :COOPERATOR 8}
THE-PRISONERS> (all-against-all! #'one-time (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5))))
{:GAMBLER1/5 8 :GAMBLER1/1 7 :GAMBLER5/1 8 :DEFECTOR 15 :COOPERATOR 10}
THE-PRISONERS> (all-against-all! #'one-time (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5))))
{:GAMBLER1/5 10 :GAMBLER1/1 7 :GAMBLER5/1 8 :DEFECTOR 15 :COOPERATOR 8}
THE-PRISONERS> (all-against-all! #'one-time (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5))))
{:GAMBLER1/5 11 :GAMBLER1/1 10 :GAMBLER5/1 11 :DEFECTOR 10 :COOPERATOR 6}
THE-PRISONERS>
The defector
comes out on top here. And the mostly-defecting gambler
doesn't do bad either. Of course, this is what we would expect from the one-time
game.
An iterated
game is like a series of one-time
games, and it keeps a running total of the score.
(defun iterated (&key (iterations 10))
(lambda (player-a player-b)
(loop repeat iterations
for (a b) = (one-time player-a player-b)
sum a into a-sum sum b into b-sum
finally (return (list a-sum b-sum)))))
It plays about how you'd expect
THE-PRISONERS> (play! (iterated) (defector) (cooperator))
(50 10)
THE-PRISONERS> (play! (iterated) (cooperator) (cooperator))
(30 30)
THE-PRISONERS> (play! (iterated) (defector) (defector))
(0 0)
THE-PRISONERS>
And setting the world at its' own throat works the way you'd expect of this process so far.
THE-PRISONERS> (all-against-all! (iterated) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5))))
{:GAMBLER1/5 119 :GAMBLER1/1 117 :GAMBLER5/1 105 :DEFECTOR 135 :COOPERATOR 100}
THE-PRISONERS> (all-against-all! (iterated) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5))))
{:GAMBLER1/5 132 :GAMBLER1/1 109 :GAMBLER5/1 103 :DEFECTOR 120 :COOPERATOR 100}
THE-PRISONERS> (all-against-all! (iterated) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5))))
{:GAMBLER1/5 100 :GAMBLER1/1 124 :GAMBLER5/1 92 :DEFECTOR 130 :COOPERATOR 96}
THE-PRISONERS>
There are more elaborate strategies we can call upon. I won't implement them all here, but these have been thought of.
Robin alternates between cooperating and defecting.
(defun robin ()
(let ((prev :cooperate))
{:name :robin
:strategy (lambda ()
(if (coop? prev)
(setf prev :defect)
(setf prev :cooperate)))}))
And then, there are the simplest strategies that consider their opponent.
(defun polo ()
(let ((prev nil))
{:name :polo
:update (lambda (opponent-action) (setf prev opponent-action))
:strategy (lambda () (or prev :cooperate))}))
(defun dantes ()
(let ((plan :cooperate))
{:name :dantes
:update (lambda (action) (when (defe? action) (setf plan :defect)))
:strategy (lambda () plan)}))
With the addition of these, it's no longer obviously a defector
s game.
THE-PRISONERS> (all-against-all! (iterated) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 164 :DANTES 131 :GAMBLER1/1 150 :GAMBLER5/1 169 :DEFECTOR 150 :COOPERATOR 184 :POLO 120 :ROBIN 147}
THE-PRISONERS> (all-against-all! (iterated) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 168 :DANTES 126 :GAMBLER1/1 176 :GAMBLER5/1 159 :DEFECTOR 165 :COOPERATOR 184 :POLO 129 :ROBIN 136}
THE-PRISONERS> (all-against-all! (iterated) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 158 :DANTES 121 :GAMBLER1/1 154 :GAMBLER5/1 156 :DEFECTOR 150 :COOPERATOR 184 :POLO 123 :ROBIN 154}
THE-PRISONERS> (all-against-all! (iterated) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 163 :DANTES 131 :GAMBLER1/1 163 :GAMBLER5/1 161 :DEFECTOR 175 :COOPERATOR 184 :POLO 117 :ROBIN 146}
THE-PRISONERS> (all-against-all! (iterated :iterations 50) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 789 :DANTES 656 :GAMBLER1/1 940 :GAMBLER5/1 964 :DEFECTOR 720 :COOPERATOR 1056 :POLO 585 :ROBIN 752}
THE-PRISONERS> (all-against-all! (iterated :iterations 50) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 845 :DANTES 651 :GAMBLER1/1 892 :GAMBLER5/1 959 :DEFECTOR 775 :COOPERATOR 1054 :POLO 609 :ROBIN 719}
THE-PRISONERS> (all-against-all! (iterated :iterations 50) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 788 :DANTES 651 :GAMBLER1/1 929 :GAMBLER5/1 946 :DEFECTOR 775 :COOPERATOR 1044 :POLO 609 :ROBIN 744}
THE-PRISONERS> (all-against-all! (iterated :iterations 50) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 859 :DANTES 651 :GAMBLER1/1 867 :GAMBLER5/1 952 :DEFECTOR 765 :COOPERATOR 1048 :POLO 609 :ROBIN 729}
THE-PRISONERS> (all-against-all! (iterated :iterations 50) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 833 :DANTES 666 :GAMBLER1/1 920 :GAMBLER5/1 953 :DEFECTOR 775 :COOPERATOR 1046 :POLO 603 :ROBIN 720}
THE-PRISONERS> (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 8325 :DANTES 6436 :GAMBLER1/1 9255 :GAMBLER5/1 9544 :DEFECTOR 7565 :COOPERATOR 10508 :POLO 8976 :ROBIN 7383}
THE-PRISONERS> (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 8365 :DANTES 6531 :GAMBLER1/1 9289 :GAMBLER5/1 9531 :DEFECTOR 7645 :COOPERATOR 10486 :POLO 6018 :ROBIN 7379}
THE-PRISONERS> (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 8407 :DANTES 6546 :GAMBLER1/1 9139 :GAMBLER5/1 9574 :DEFECTOR 7590 :COOPERATOR 10554 :POLO 6117 :ROBIN 7389}
THE-PRISONERS> (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 8063 :DANTES 6371 :GAMBLER1/1 9231 :GAMBLER5/1 9492 :DEFECTOR 7555 :COOPERATOR 10508 :POLO 6084 :ROBIN 7412}
THE-PRISONERS> (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 8068 :DANTES 6456 :GAMBLER1/1 9165 :GAMBLER5/1 9614 :DEFECTOR 7395 :COOPERATOR 10516 :POLO 6003 :ROBIN 7451}
THE-PRISONERS> (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin))))
{:GAMBLER1/5 8241 :DANTES 6356 :GAMBLER1/1 9150 :GAMBLER5/1 9579 :DEFECTOR 7545 :COOPERATOR 10480 :POLO 9021 :ROBIN 7392}
THE-PRISONERS>
When it's a prisoner against the world, the makeup of the world makes a difference in which prisoner ultimately wins.
(defun winner (results)
(let ((max nil)
(score nil))
(loop for (k . v) in (as-list results)
do (if (or (not score) (> v score))
(setf score v
max (cons k v))))
max))
Currently, with mirror matches happening, the world is tilted towards cooperator
s.
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10554)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10532)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10486)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10536)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10478)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10502)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10540)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10516)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)))))
(:COOPERATOR . 10476)
THE-PRISONERS>
Without mirror matches, it's still mostly a cooperator
s' game, but not quite so strongly.
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:DEFECTOR . 7665)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:ROBIN . 7497)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:COOPERATOR . 7512)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:COOPERATOR . 7580)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:COOPERATOR . 7516)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:COOPERATOR . 7528)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:DEFECTOR . 7615)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:DEFECTOR . 7610)
THE-PRISONERS> (winner (all-against-all! (iterated :iterations 500) (matches (list (cooperator) (defector) (gambler) (gambler :cooperate 5) (gambler :defect 5) (polo) (dantes) (robin)) :mirror? nil)))
(:COOPERATOR . 7550)
THE-PRISONERS>
This wasn't the end. It was step one.
via Elm - Latest posts by @Yannick971 Yannick on Sat, 19 Sep 2020 00:21:36 GMT
Thanks @pdamoc and @joelq for your help! The way I tried to design this is so messy that its hard to explain, huge red flag! I am still experimenting with Elm and FP.
So maybe its better to explain what I would like to do and maybe you can share with me how you’d design this?
Main.Model holds data decoded from 5 different HTTP requests, that I got it to work well thanks to your advice in this chat:
type Model =
Loading {
dataA: Maybe DataA
,dataB: Maybe DataB
, ....etc...
}
| Success {
dataA: DataA
,dataB: DataB
, .... etc...
}
| Error String
That works beautifully… but of course I don’t want to hold the whole API response or data I dont need in Main.Model.
So, Main.init
initiates the API calls, then I import the decoders from the respective modules DataA.elm
etc… to parse the responses.
The responses I will get back are nested timeseries data, with hourly timestamps, and for each I am only interested in the value matching the next hour’s timestamp.
... [
{timestamp: 1231243124, value: 23},
{timestamp: 1231243453, value: 12},
]
So I get this array back, at the decoder level, now how can I “filter in” only the value I am interested in, (the one corresponding to the next hour after I ran the app) ? I just want to update the model with, lets say, 23.
First I will have to first compute the timestamp corresponding to the next hour in my local timezone. I think I am good with that part but where should this timestamp be computed? Main or separate module?
And then, most importantly, how do I share this timestamp with all the 5 decoders. Is it possible or a good idea to pass it as an argument to the decoders? or should I make a function that takes the time and return a Decoder?
I guess that is what really confuses me… I feel that the filtering should happen at the decoder level, so I have a very clean model, but I don’t know how to do this more advanced decoding using an outside parameter… the only way I would be able to do it now is to store the whole lists of data in Model and then filter it before Main.view
, but that’s nasty :).
I hope it’s more clear… thank you.
via Planet Lisp by on Fri, 18 Sep 2020 20:52:26 GMT
This template engine is interesting because it allows mixing lisp code blocks and HTML in a way simple enough to be used by non-lisp developers and designers.
It's interesting feature is that each template definition includes the arguments list.
Here is how we can define templates for user list from the previous post about cl-emb:
POFTHEDAY> (eco:compile-string
"
<% deftemplate user (nickname name) () %>
<a href=\"/users/<%= nickname %>\"><%= name %></a>
<% end %>
")
POFTHEDAY> (eco:compile-string "
<% deftemplate user-list (users) () %>
<ul>
<% loop for (nickname name) in users do %>
<li><%- user nickname name %><% end %></li>
<% end %>
</ul>
<% end %>
")
POFTHEDAY> (eco-template:user-list
'(("bob" "Bob Hopkins")
("alice" "Alice Cooker")))
"
<ul>
<li>
<a href=\"/users/bob\">Bob Hopkins</a>
</li>
<li>
<a href=\"/users/alice\">Alice Cooker</a>
</li>
</ul>
"
Also, there is a way to load templates from the files with .eco
extensions. There is an ASDF extension which allows defining these templates as components of your ASDF system.
Documentation does not cover this, but the template components should be defined like this:
(defsystem mysite
:defsystem-depends-on (eco)
:components ((:module "src"
:depends-on "templates"
:components ((:file "backend-code")
(:file "utils")))
(:module "templates"
:components ((:eco-template "index-page")
(:eco-template "users")))))
Well, let's measure Eco's performance!
POFTHEDAY> (eco:compile-string "
<% deftemplate perform (title items) () %>
<title><%= title %></title>
<ul>
<% loop for item in items do %>
<li><%= item %></li>
<% end %>
</ul>
<% end %>
")
POFTHEDAY> (time
(loop repeat 1000000
do (eco-template:perform "Foo Bar"
'("One" "Two" "Three"))))
Evaluation took:
2.135 seconds of real time
2.144360 seconds of total run time (2.121050 user, 0.023310 system)
[ Run times consist of 0.141 seconds GC time, and 2.004 seconds non-GC time. ]
100.42% CPU
4,713,480,570 processor cycles
1,008,017,904 bytes consed
This is slower than half of the tested template engines. It took place between cl-who
and print-html
. I've expected it will be faster :(
via Elm - Latest posts by @hexedhash Giorgio on Fri, 18 Sep 2020 15:46:09 GMT
@francescortiz Thanks for the suggestion. However I need the bounding box to also reduce in size throughout the CSS transition
via Elm - Latest posts by @hexedhash Giorgio on Fri, 18 Sep 2020 15:45:11 GMT
I’m beginning to think that I’m going to need to add an animation library. But because of the optimizations that elm does to reduce asset size, I think my concerns are less relevant - as long as the API for Alert
remains simple and intiutive.
via Elm - Latest posts by @hexedhash Giorgio on Fri, 18 Sep 2020 15:38:01 GMT
Thanks @evancz!
For transparency, this was the fix for me:
Which included elm-css’s change.
murmur3 was an indirect dependency via elm-css. I had to manually update my elm.json to remove the stale reference to murmur3.
via Elm - Latest posts by @system system on Fri, 18 Sep 2020 15:23:44 GMT
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
via Elm - Latest posts by @joelq Joël Quenneville on Fri, 18 Sep 2020 14:45:59 GMT
Reading between the lines, it sounds like you are trying to build your project using a “fractal architecture” with a bunch of modules that each define init
/update
/view
, etc. Most extracted modules in Elm apps are not structured this way. Instead, they are usually just a data structure and some functions that act upon it (think the Elm core library). The init
/update
/view
functions are not magic framework functions and modules don’t need to implement them.
It’s hard to make an definite recommendations without more context on what you are doing but most solutions likely involve passing in the time as an argument as suggested by @pdamoc.
For example you might create some sort of constructor for your custom data structure in the module like:
MyModule.fromTime : Posix -> MyModule.Structure
which you could call from Main
like:
module Main exposing(main)
import MyModule
init : Flags -> (Model, Cmd Msg)
init flags =
(initialModel, Task.perform GotInitialTime Time.now)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
GotInitialTime time ->
({ model | structure = MyModule.fromTime time }, Cmd.none)
via Elm - Latest posts by @rupert Rupert Smith on Fri, 18 Sep 2020 12:25:58 GMT
So I feel like I am now making some good progress with this. I have taken Matt’s TolerantParser
as a starting point, the current WIP is here:
https://github.com/the-sett/parser-recoverable
Don’t get too excited, but I created a little example to start trying it out:
cd examples
elm-live src/Main.elm
I didn’t like that the result of run
is going to yield a double wrapped Result
, the outer one with DeadEnd
s but the inner one with just problem
.
type alias Parser context problem data =
Parser.Parser context problem (Result (List problem) data)
outcome : Result (List (DeadEnd c x)) (Result (List x) data)
outcome = Parser.Advaned.run someParser someInput
So I changed the inner error representation to be (DeadEnd c x)
too. Only problem with that is that Parser.Advanced
has no getContext
function, so I could not give a context stack. Errors resulting from inside the extended parser will therefore have not have the full context - perhaps there is a way to do it by carrying around a second copy of the context stack with the parser? I guess I’ll try and fix that when it actually looks like it is needed.
The other thing is that I didn’t think Result
was the right output for this parser to give. If the parser does recover succesfully it will still yield some AST, but it should also give errors for the bits it had to gloss over to get it. So the outcome should be more like a tuple.
I decided to use this rather than (List (DeadEnd c x), Maybe data)
, to avoid the case where there are no errors and no data!
{-| Describes the possible outcomes from running a parser.
- `Success` means that the parsing completed with no syntax errors at all.
- `Partial` means that the parsing was able to complete by recovering from
syntax errors. The syntax errors are listed along with the parsed result.
- `Failure` means that the parsing could not complete, so there is no parsed
result, only a list of errors.
-}
type Outcome context problem value
= Success value
| Partial (List (DeadEnd context problem)) value
| Failure (List (DeadEnd context problem))
The run function is then:
run : Parser c x a -> String -> Outcome c x a
Similar to the TolerantParser
, I defined a set of actions to guide the parser when it fails.
{-| Describes the possible ways the parser should act when it encounters
something that it cannot parse.
- `Fail` stop parsing and return a `Failure` outcome.
- `Warn` ignore the error, but add a problem and use a `Partial` outcome.
- `Ignore` ignore the error and continue with a `Success` outcome.
- `ChompForMatch` try chomping to find a matching character. If succesfull
add a problem but continue with a `Partial` outcome. If this does not work
then `Fail`.
-}
type RecoveryTactic x
= Fail
| Warn x
| Ignore
| ChompForMatch (List Char) x
The default behaviour is to Fail
.
The current recovery tactic can be attached to a parser with this function:
withRecovery : RecoveryTactic x -> Parser c x a -> Parser c x a
The idea is that this will be passed down to all subsequent parsers (chained with ignore
, keep
, map
, andThen
, and so on), and not just for one particular token. So if parsing a List Int
, but some of the Int
s are expressions, the parser could keep its strategy of chomping to the end of the list or next comma, in the event that it sees a malformed expression. Not totally sure this is the right thing, but it feels right for now.
This is what I am going to work on next, by evolving the problem
type.
When a string gets chomped to recover, I will add the start position of the string, and the string itself to the problem. The idea is that an editor can check if a problem overlaps the current cursor position, and if so, it knows what String
to cut out of the source and offer context sensitive suggestions to replace it with.
via Elm - Latest posts by @eimfach Robin G. on Fri, 18 Sep 2020 11:58:18 GMT
Using CSS Transitions on Auto Dimensions
According to the Mozilla Developer Network docs, auto values have been intentionally excluded from the CSS transitions spec. It looks like it’s been requested by a few people, but when you think about it, it makes at least a little sense that it hasn’t been included. The browser process that re-calculates the sizes and positions of all elements based on their content and the way they interact with each other (known as “reflow”) is expensive. If you were to transition an element into a
height
ofauto
, the browser would have to perform a reflow for every stage of that animation, to determine how all the other elements should move. This couldn’t be cached or calculated in a simple way, since it doesn’t know the starting and/or ending values until the moment the transition happens. This would significantly complicate the math that has to be done under the hood and probably degrade performance in a way that might not be obvious to the developer.
via Elm - Latest posts by @system system on Fri, 18 Sep 2020 11:09:43 GMT
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.