Explorar el Código

Updates for EOE

Cadel Watson hace 4 meses
padre
commit
fcb0557ada
Se han modificado 8 ficheros con 110 adiciones y 26 borrados
  1. 2 1
      .idea/drafter-elm.iml
  2. 31 8
      README.md
  3. 1 1
      data/generate_card_ratings.py
  4. 1 1
      js/app.js
  5. 32 1
      src/Card.elm
  6. 21 12
      src/Database.elm
  7. 20 1
      tests/TestCard.elm
  8. 2 1
      tests/TestDatabase.elm

+ 2 - 1
.idea/drafter-elm.iml

@@ -2,9 +2,10 @@
 <module type="PYTHON_MODULE" version="4">
   <component name="NewModuleRootManager">
     <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.venv" />
       <excludeFolder url="file://$MODULE_DIR$/venv" />
     </content>
-    <orderEntry type="jdk" jdkName="Python 3.11 (drafter-elm)" jdkType="Python SDK" />
+    <orderEntry type="jdk" jdkName="Python 3.12 (drafter)" jdkType="Python SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
   </component>
 </module>

+ 31 - 8
README.md

@@ -1,15 +1,38 @@
-# Parcel, Tailwind CSS and Elm boilerplate
+# Drafter
 
-The corresponding blog post can be found [on my blog: Using Parcel JS with Tailwind CSS, Elm Lang and Elm Spa](https://vincent.jousse.org/blog/en/2021-09-21-parcel-tailwind-css-elm-lang-elm-spa).
+# UI
 
-## Installing
+Install with `npm install`.
 
-    npm install
+Run with `npm run start`.
 
-## Running DEV env
+Build with `npm run build`.
 
-    npm run start
+## Backend
 
-## Building
+## Adding a new set
 
-    npm run build
+0. Create a new folder in data/sets
+
+Named after the set code, e.g. `data/sets/eoe`.
+
+1. Download card ratings
+
+Log in to 17lands, go to card data, select the set, premier draft format, and top users, then switch to table view.
+
+Click export and download the CSV file.
+
+Save to `data/sets/<CODE>/card-ratings-all.csv`
+
+2. Download updated card data from Scryfall
+
+Go to https://scryfall.com/docs/api/bulk-data and download the Oracle Cards JSON file.
+
+Move it to `data/cards/oracle-cards.json`.
+
+3. Generate the set data
+
+```bash
+cd data
+python generate_card_ratings.py
+```

+ 1 - 1
data/generate_card_ratings.py

@@ -32,7 +32,7 @@ def find_card_with_dual_faces(all_card_data, name):
 
 
 def main():
-    with open("oracle-cards-20250222221022.json") as f:
+    with open("cards/oracle-cards.json") as f:
         all_card_data = json.load(f)
 
     for set in discover_sets():

+ 1 - 1
js/app.js

@@ -1,4 +1,4 @@
-import draftData from "../data/draft_dft.json";
+import draftData from "../data/drafts/draft_tdm_bad.json";
 
 import {Elm} from '../src/Main.elm';
 

+ 32 - 1
src/Card.elm

@@ -14,10 +14,11 @@ module Card exposing
     , iwd
     , manaCostToSymbol
     , parseManaCost
+    , parsePower
     , pickRate
     )
 
-import Parser as P exposing ((|.), Parser, Trailing(..))
+import Parser as P exposing ((|.), (|=), Parser, Trailing(..))
 import Stats exposing (NormalDistribution)
 
 
@@ -43,6 +44,7 @@ type CardType
 
 type Power
     = ConstantPower Int
+    | ConstantPlusVariablePower Int
     | VariablePower
 
 
@@ -368,3 +370,32 @@ manaCostToSymbol c =
 
         _ ->
             ""
+
+
+parsePower : String -> Maybe Power
+parsePower str =
+    case P.run powerP str of
+        Ok result ->
+            Just result
+
+        Err _ ->
+            Nothing
+
+
+powerP : Parser Power
+powerP =
+    let
+        variablePowerP =
+            P.succeed VariablePower |. P.backtrackable (P.keyword "*")
+
+        constantPlusVariablePowerP =
+            P.succeed ConstantPlusVariablePower |= P.backtrackable P.int |. P.backtrackable (P.keyword "+*")
+
+        constantPowerP =
+            P.succeed ConstantPower |= P.int
+    in
+    P.oneOf
+        [ variablePowerP
+        , constantPlusVariablePowerP
+        , constantPowerP
+        ]

+ 21 - 12
src/Database.elm

@@ -1,9 +1,9 @@
 module Database exposing (Database, decode, decoder, encode, fromCardData, get, getAll)
 
-import Card exposing (CardData, CardDetails, CardPerformanceData, CardType(..), ManaColor(..), Power(..), parseManaCost)
+import Card exposing (CardData, CardDetails, CardPerformanceData, CardType(..), ManaColor(..), Power(..), parseManaCost, parsePower)
 import Dict exposing (Dict)
 import Json.Decode as Decode exposing (Decoder, decodeString)
-import Json.Decode.Pipeline exposing (optional, required)
+import Json.Decode.Pipeline exposing (custom, optional, required)
 import Json.Encode as Encode
 import Tuple exposing (pair)
 
@@ -122,10 +122,20 @@ decodeCardPerformance =
             |> required "ATA" decodeMaybeFloatString
             |> required "ALSA" decodeMaybeFloatString
             |> required "GIH WR" decodeMaybePercentageString
-            |> required "IWD" decodeImprovementWhenDrawn
+            -- The improvement when drawn changed to improvement in hand in newer set data
+            -- from 17lands
+            |> custom decodeIIHOrIWD
         )
 
 
+decodeIIHOrIWD : Decoder (Maybe Float)
+decodeIIHOrIWD =
+    Decode.oneOf
+        [ Decode.at [ "IIH" ] decodeImprovementWhenDrawn
+        , Decode.at [ "IWD" ] decodeImprovementWhenDrawn
+        ]
+
+
 decodeImprovementWhenDrawn : Decoder (Maybe Float)
 decodeImprovementWhenDrawn =
     Decode.string
@@ -277,6 +287,9 @@ encodePower p =
         Just (ConstantPower i) ->
             Encode.string (String.fromInt i)
 
+        Just (ConstantPlusVariablePower i) ->
+            Encode.string (String.fromInt i ++ "+*")
+
         Just VariablePower ->
             Encode.string "*"
 
@@ -289,16 +302,12 @@ decodePower =
     Decode.string
         |> Decode.andThen
             (\s ->
-                if s == "*" then
-                    Decode.succeed VariablePower
+                case parsePower s of
+                    Just p ->
+                        Decode.succeed p
 
-                else
-                    case String.toInt s of
-                        Just i ->
-                            Decode.succeed (ConstantPower i)
-
-                        Nothing ->
-                            Decode.fail "Invalid integer"
+                    Nothing ->
+                        Decode.fail ("Could not parse power: " ++ s)
             )
 
 

+ 20 - 1
tests/TestCard.elm

@@ -1,6 +1,6 @@
 module TestCard exposing (..)
 
-import Card exposing (ManaCost(..))
+import Card exposing (ManaCost(..), ManaColor(..))
 import Expect exposing (Expectation)
 import Fuzz exposing (Fuzzer, int, list, string)
 import Signals
@@ -19,4 +19,23 @@ suite =
         , test "parseManaCost ('{X}{Y}')" <|
             \_ ->
                 Expect.equal (Card.parseManaCost "{X}{Y}") (Just [ X, Y ])
+
+        , test "parseManaCost ('{2/G}{2/U}{2/R}')" <|
+            \_ ->
+                Expect.equal (Card.parseManaCost "{2/G}{2/U}{2/R}") (Just [ TwoOrColor Green, TwoOrColor Blue, TwoOrColor Red ])
+        , test "parsePower ('')" <|
+            \_ ->
+                Expect.equal (Card.parsePower "") Nothing
+        , test "parsePower ('1')" <|
+            \_ ->
+                Expect.equal (Card.parsePower "1") (Just (Card.ConstantPower 1))
+        , test "parsePower ('0')" <|
+            \_ ->
+                Expect.equal (Card.parsePower "0") (Just (Card.ConstantPower 0))
+        , test "parsePower ('*')" <|
+            \_ ->
+                Expect.equal (Card.parsePower "*") (Just (Card.VariablePower))
+        , test "parsePower ('1+*')" <|
+            \_ ->
+                Expect.equal (Card.parsePower "1+*") (Just (Card.ConstantPlusVariablePower 1))
         ]

+ 2 - 1
tests/TestDatabase.elm

@@ -75,7 +75,8 @@ fuzzPower : Fuzzer Power
 fuzzPower =
     Fuzz.oneOf
         [ Fuzz.constant VariablePower
-        , Fuzz.int |> Fuzz.map ConstantPower
+        , Fuzz.intAtLeast 0 |> Fuzz.map ConstantPower
+        , Fuzz.intAtLeast 0 |> Fuzz.map ConstantPlusVariablePower
         ]