Compare commits

...

2 commits

Author SHA1 Message Date
4e8d9a543b
Add sorting and better styling for decklist
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
2019-09-12 10:55:59 +02:00
8bd3e372bf
Refactor sorting helpers to mlpccg 2019-09-12 10:42:10 +02:00
3 changed files with 204 additions and 77 deletions

View file

@ -1,20 +1,25 @@
<template> <template>
<section class="decklist"> <section class="decklist">
<article <section class="card-section" v-for="section in sections" :key="section">
class="ccgcard" <header>
@click="() => _drop(card)" <h1>{{ section }}</h1>
v-for="(card, i) in cards" </header>
:key="i" <article
> class="ccgcard"
<img :src="imageURL(card.data.ID)" class="cardbg" /> @click="() => _drop(card)"
<div class="amt">{{ card.howmany }}</div> v-for="(card, i) in getCards(section, true)"
<div class="fullname"> :key="i"
<div class="name">{{ card.data.Name }}</div> >
<div class="subname"> <img :src="imageURL(card.data.ID)" class="cardbg" />
{{ card.data.Subname ? card.data.Subname : "" }} <div class="amt">{{ card.howmany }}</div>
<div class="fullname">
<div class="name">{{ card.data.Name }}</div>
<div class="subname">
{{ card.data.Subname ? card.data.Subname : "" }}
</div>
</div> </div>
</div> </article>
</article> </section>
</section> </section>
</template> </template>
@ -26,6 +31,16 @@
flex-direction: column; flex-direction: column;
} }
.card-section {
header {
h1 {
padding: 5px 10px;
font-family: $fantasy;
font-size: 10pt;
}
}
}
.ccgcard { .ccgcard {
display: flex; display: flex;
align-content: space-between; align-content: space-between;
@ -59,12 +74,11 @@
} }
.amt { .amt {
margin: 0 10pt; margin: 0 6pt 0 10pt;
font-weight: bold; font-weight: bold;
font-size: 13pt; font-size: 13pt;
padding-bottom: 5px;
&:after { &:after {
content: " x"; content: " ×";
font-weight: 300; font-weight: 300;
} }
} }
@ -84,7 +98,102 @@
<script lang="ts"> <script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator"; import { Component, Vue, Prop } from "vue-property-decorator";
import { cardFullName, CardSlot, Card, cardImageURL } from "@/mlpccg"; import {
cardFullName,
CardSlot,
Card,
cardImageURL,
multiElemStr,
typeNames
} from "@/mlpccg";
function sortCards(a: CardSlot, b: CardSlot): number {
// Sort by element
// (Cards are guaranteed to be the same type)
switch (a.data.Type) {
case "Friend":
{
// Sort by requirement
if (a.data.Requirement && b.data.Requirement) {
const reqA = multiElemStr(Object.keys(a.data.Requirement));
const reqB = multiElemStr(Object.keys(b.data.Requirement));
if (reqA > reqB) {
return 1;
}
if (reqB > reqA) {
return -1;
}
}
// Sort by cost
if (a.data.Cost && b.data.Cost) {
if (a.data.Cost > b.data.Cost) {
return 1;
}
if (a.data.Cost < b.data.Cost) {
return -1;
}
}
// Sort by element
const elemA = multiElemStr(a.data.Element);
const elemB = multiElemStr(b.data.Element);
if (elemA > elemB) {
return 1;
}
if (elemB > elemA) {
return -1;
}
}
break;
case "Problem":
if (a.data.ProblemRequirement && b.data.ProblemRequirement) {
const preqA = multiElemStr(Object.keys(a.data.ProblemRequirement));
const preqB = multiElemStr(Object.keys(b.data.ProblemRequirement));
if (preqA > preqB) {
return 1;
}
if (preqB > preqA) {
return -1;
}
}
break;
case "Event":
case "Resource":
if (a.data.Requirement && b.data.Requirement) {
const reqA = multiElemStr(Object.keys(a.data.Requirement));
const reqB = multiElemStr(Object.keys(b.data.Requirement));
if (reqA > reqB) {
return 1;
}
if (reqB > reqA) {
return -1;
}
}
break;
}
// Sort by power
if (a.data.Power && b.data.Power) {
if (a.data.Power > b.data.Power) {
return 1;
}
if (a.data.Power < b.data.Power) {
return -1;
}
}
// If all else fail, sort by name
const nameA = cardFullName(a.data);
const nameB = cardFullName(b.data);
if (nameA > nameB) {
return 1;
}
if (nameA < nameB) {
return -1;
}
return 0;
}
@Component({ @Component({
components: {} components: {}
@ -104,5 +213,17 @@ export default class DeckList extends Vue {
private imageURL(id: string) { private imageURL(id: string) {
return cardImageURL(id); return cardImageURL(id);
} }
private getCards(section: string, sort: boolean): CardSlot[] {
let cards = this.cards.filter(c => c.data.Type == section);
if (!sort) {
return cards;
}
return cards.sort(sortCards);
}
private get sections(): string[] {
return typeNames.filter(s => this.getCards(s, false).length > 0);
}
} }
</script> </script>

View file

@ -11,3 +11,61 @@ export function createPonyheadURL(cards: Card[]): string {
const cardlist = cards.map(c => `${c.ID}x1`); const cardlist = cards.map(c => `${c.ID}x1`);
return "https://ponyhead.com/deckbuilder?v1code=" + cardlist.join("-"); return "https://ponyhead.com/deckbuilder?v1code=" + cardlist.join("-");
} }
export const colorNames = [
"Loyalty",
"Honesty",
"Laughter",
"Magic",
"Generosity",
"Kindness",
"None"
];
export const typeNames = [
"Mane Character",
"Friend",
"Event",
"Resource",
"Troublemaker",
"Problem"
];
export const rarityNames = ["C", "U", "R", "SR", "UR", "RR", "F"];
// Trasform string from list to a number that can be used for comparison/sorting
function arrIndex(arr: string[]) {
return function(comp: string) {
const idx = arr.indexOf(comp);
if (idx < 0) {
return arr.length;
}
return idx;
};
}
export const elemIndex = arrIndex(colorNames);
export const typeIndex = arrIndex(typeNames);
export const rarityIndex = arrIndex(rarityNames);
// Convert Element[] to number by scaling elements for fair comparisons
// Example: ["Loyalty", "Kindness"] -> [0, 5] -> [1, 6] -> 16
export function multiElemStr(elems: string[]): number {
return elems
.map(elemIndex)
.reduce(
(acc, elem, idx, arr) => acc + (elem + 1) * 10 ** (arr.length - idx - 1),
0
);
}
export function cardLimit(type: string) {
switch (type) {
case "Mane Character":
return 1;
case "Problem":
return 2;
default:
return 3;
}
}

View file

@ -191,56 +191,15 @@ import {
getCards, getCards,
allSets, allSets,
cardFullName, cardFullName,
createPonyheadURL createPonyheadURL,
multiElemStr,
typeIndex,
rarityIndex,
colorNames,
typeNames,
cardLimit
} from "@/mlpccg"; } from "@/mlpccg";
const colorNames = [
"Loyalty",
"Honesty",
"Laughter",
"Magic",
"Generosity",
"Kindness",
"None"
];
const typeNames = [
"Mane Character",
"Friend",
"Event",
"Resource",
"Troublemaker",
"Problem"
];
const rarityNames = ["C", "U", "R", "SR", "UR", "RR", "F"];
// Trasform string from list to a number that can be used for comparison/sorting
function arrIndex(arr: string[]) {
return function(comp: string) {
const idx = arr.indexOf(comp);
if (idx < 0) {
return arr.length;
}
return idx;
};
}
const elemIndex = arrIndex(colorNames);
const typeIndex = arrIndex(typeNames);
const rarityIndex = arrIndex(rarityNames);
// Convert Element[] to number by scaling elements for fair comparisons
// Example: ["Loyalty", "Kindness"] -> [0, 5] -> [1, 6] -> 16
function multiElemStr(elems: string[]): number {
return elems
.map(elemIndex)
.reduce(
(acc, elem, idx, arr) => acc + (elem + 1) * 10 ** (arr.length - idx - 1),
0
);
}
// Sort function for sorting cards // Sort function for sorting cards
function sortByColor(a: Card, b: Card) { function sortByColor(a: Card, b: Card) {
const typeA = typeIndex(a.Type); const typeA = typeIndex(a.Type);
@ -314,17 +273,6 @@ function sortByColor(a: Card, b: Card) {
return 0; return 0;
} }
function cardLimit(type: string) {
switch (type) {
case "Mane Character":
return 1;
case "Problem":
return 2;
default:
return 3;
}
}
@Component({ @Component({
components: { components: {
DeckList, DeckList,