Playable game, only end of game isn't handled yet

This commit is contained in:
Sasha 2018-05-16 22:59:22 +02:00
parent 4cd6842c01
commit dc49f4eb0e
7 changed files with 248 additions and 48 deletions

View File

@ -35,7 +35,7 @@ executable hanafudapi
build-depends: base >=4.10 && <4.11 build-depends: base >=4.10 && <4.11
, bytestring , bytestring
, containers , containers
, hanafuda >= 0.2.1 , hanafuda >= 0.3.0
, http-types , http-types
, aeson , aeson
, mtl , mtl

View File

@ -5,7 +5,8 @@ function Fun() {
map: map, map: map,
mapFilter: mapFilter, mapFilter: mapFilter,
isSet: isSet, isSet: isSet,
of: of of: of,
proj: proj
}; };
function insert(obj, t, compare, min, max) { function insert(obj, t, compare, min, max) {
@ -44,6 +45,10 @@ function Fun() {
return function(key) {return o[key];}; return function(key) {return o[key];};
} }
function proj(key) {
return function(o) {return o[key];};
}
function mapFilter(mapper, predicate) { function mapFilter(mapper, predicate) {
return function(array) { return function(array) {
return array.reduce(function(accumulator, elem) { return array.reduce(function(accumulator, elem) {

View File

@ -2,17 +2,27 @@
clear: both; clear: both;
} }
li.card { #game ul {
padding: 0;
}
#game .card {
background: #fff;
display: inline-block; display: inline-block;
border-radius: 0.5em; border-radius: 0.5em;
border: 1px solid #555; border: 1px solid #555;
width: 6em; width: 5em;
height: 10em; height: 8em;
max-height: 10%;
float: left; float: left;
margin: 0.5em; margin: 0.5em;
} }
#river li.card.candidate, #hand li.card { #turned.hidden {
display: none;
}
#river li.card.candidate, #hand.yourTurn li.card {
cursor: pointer; cursor: pointer;
} }
@ -23,3 +33,20 @@ li.card {
#hand li.card.selected { #hand li.card.selected {
margin-top: -1em; margin-top: -1em;
} }
#opponent, #own {
position: absolute;
right: 0;
}
#opponent {
top: 0;
}
#own {
bottom: 0;
}
#opponent .card, #own .card {
margin-left: -2em;
}

View File

@ -1,26 +1,52 @@
function Game(modules) { function Game(modules) {
var turned = document.getElementById('turned');
var status = {
dom: document.getElementById('status'),
playing: false,
step: null,
month: null
};
var sets = { var sets = {
river : cardSet('river'), river: cardSet('river'),
hand : cardSet('hand'), hand: cardSet('hand'),
}; };
var selected = null; var selected = null;
modules.messaging.addEventListener(["NewGame"], function(o) { modules.messaging.addEventListener(["Game"], function(o) {
o.game.river.forEach(function(cardName) { status.step = o.game.step.tag;
var card = new RiverCard(cardName); setStatus(o.game);
sets.river.card[card.value] = card; setCaptures(o.game);
sets.river.dom.appendChild(card.dom); [
}); {name: 'river', cards: o.game.river},
o.game.players[modules.session.getKey()].hand.forEach(function(cardName) { {name: 'hand', cards: o.game.players[modules.session.getKey()].hand}
var card = new HandCard(cardName); ].forEach(setCardSet);
sets.hand.card[card.value] = card; if(status.step == "Turned") {
sets.hand.dom.appendChild(card.dom); turned.textContent = o.game.step.contents;
}); turned.classList.remove("hidden");
if(status.playing) {
selected = o.game.step.contents;
showCandidates(modules.hanafuda.Card[selected], true);
}
} else {
turned.classList.add("hidden");
}
if(status.playing && status.step == "Scored") {
play({koiKoi: confirm(
"You scored ! Do you want to go on ? Press cancel to just get your points and end current month"
)});
}
}); });
function play(move) {
modules.messaging.send({
tag: "Play",
move: move
});
}
function cardSet(id) { function cardSet(id) {
return { return {
card: {}, card: null,
dom: document.getElementById(id) dom: document.getElementById(id)
}; };
} }
@ -29,7 +55,53 @@ function Game(modules) {
return modules.fun.mapFilter( return modules.fun.mapFilter(
modules.fun.of(sets.river.card), modules.fun.of(sets.river.card),
modules.fun.isSet modules.fun.isSet
)(modules.hanafuda.sameMonth(card)); )(modules.hanafuda.sameMonth(card).map(modules.fun.proj('name')));
}
function setStatus(game) {
modules.dom.clear(status.dom);
status.month = game.month;
var month = document.createElement('li');
month.textContent = "This month's flower is the " + status.month;
status.dom.appendChild(month);
var playing = document.createElement('li');
status.playing = modules.session.is(game.playing);
if(status.playing) {
sets.hand.dom.classList.toggle("yourTurn", status.step == "ToPlay");
playing.textContent = "Your turn";
} else {
sets.hand.dom.classList.remove("yourTurn");
playing.textContent = modules.room.name(game.playing) + " is playing";
}
status.dom.appendChild(playing);
}
function setCaptures(game) {
for(var key in game.players) {
var elem = document.getElementById(modules.session.is(key) ? "own" : "opponent");
elem.getElementsByClassName('score')[0].textContent = game.scores[key] + " pts";
Array.prototype.forEach.call(elem.getElementsByTagName('ul'), modules.dom.clear);
game.players[key].meld.forEach(function(cardName) {
var card = new Card(cardName);
elem.getElementsByClassName(card.value.family.class)[0].appendChild(card.dom);
});
}
}
function setCardSet(conf) {
var set = sets[conf.name];
var constructor = conf.name == "river" ? RiverCard : HandCard;
modules.dom.clear(set.dom);
set.card = {};
conf.cards.forEach(function(cardName) {
var card = new constructor(cardName);
set.card[cardName] = card;
set.dom.appendChild(card.dom);
});
}
function showCandidates(card, yes) {
matchingInRiver(card).forEach(function(riverCard) {riverCard.setCandidate(yes);});
} }
function Card(name) { function Card(name) {
@ -52,10 +124,11 @@ function Game(modules) {
var card = this; var card = this;
return function() { return function() {
if(card.candidate) { if(card.candidate) {
modules.messaging.send({ var withCard = selected;
tag: "Play", selected = null;
move: {capture: [sets.hand.card[selected].name, card.name]} play(
}); status.step == 'ToPlay' ? {capture: [withCard, card.name]} : {choose: card.name}
);
} }
}; };
}; };
@ -70,20 +143,24 @@ function Game(modules) {
} }
HandCard.prototype.onClick = function() { HandCard.prototype.onClick = function() {
var card = this; if(status.playing && status.step == "ToPlay") {
return function() { var card = this;
if(selected != undefined) { return function() {
sets.hand.card[selected].setSelected(false); if(selected != undefined) {
} else { sets.hand.card[selected].setSelected(false);
card.play(); } else {
} card.play();
}; }
};
} else {
return function() {};
}
}; };
HandCard.prototype.setSelected = function(yes) { HandCard.prototype.setSelected = function(yes) {
selected = yes ? this.value : null; selected = yes ? this.name : null;
this.dom.classList.toggle('selected', yes); this.dom.classList.toggle('selected', yes);
matchingInRiver(this.value).forEach(function(card) {card.setCandidate(yes);}); showCandidates(this.value, yes);
} }
HandCard.prototype.play = function() { HandCard.prototype.play = function() {
@ -91,8 +168,7 @@ function Game(modules) {
if(matching.length > 1) { if(matching.length > 1) {
this.setSelected(true); this.setSelected(true);
} else { } else {
modules.messaging.send({tag: "Play", move: {play: this.name}}) play({play: this.name});
} }
} }
} }

View File

@ -1,4 +1,4 @@
function Hanafuda() { function Hanafuda(modules) {
var Flower = Object.freeze({ var Flower = Object.freeze({
Pine: 0, Pine: 0,
Plum: 1, Plum: 1,
@ -13,7 +13,54 @@ function Hanafuda() {
Willow: 10, Willow: 10,
Paulownia: 11 Paulownia: 11
}); });
var Card = Object.freeze({
var Family = Object.freeze(
["Kasu", "Tan", "Tane", "Hikari"].reduce(function(o, name) {
o[name] = {class: name[0].toLowerCase() + name.slice(1)};
return o;
}, {})
);
var CardNames = [
"Pine0", "Pine1", "PinePoetry", "Crane",
"Plum0", "Plum1", "PlumPoetry", "BushWarbler",
"Cherry0", "Cherry1", "CherryPoetry", "CampCurtain",
"Wisteria0", "Wisteria1", "WisteriaRed", "Cuckoo",
"Iris0", "Iris1", "IrisRed", "EightPlankBridge",
"Peony0", "Peony1", "PeonyBlue", "Butterflies",
"BushClover0", "BushClover1", "BushCloverRed", "Boar",
"SusukiGrass0", "SusukiGrass1", "Geese", "FullMoon",
"Chrysanthemum0", "Chrysanthemum1", "ChrysanthemumBlue", "SakeCup",
"Maple0", "Maple1", "MapleBlue", "Deer",
"Lightning", "WillowRed", "Swallow", "RainMan",
"Paulownia0", "Paulownia1", "Sand", "Phoenix"
];
var Card = Object.freeze(
CardNames.reduce(function(o, name, i) {
o[name] = {
id: i,
family: findFamily(name, i),
flower: Math.floor(i / 4),
name: name
};
return o;
}, {})
);
function findFamily(name, i) {
if((i % 4 < 2 && i < 41) || (i > 43 && i < 47)) {
return Family.Kasu;
} else if(name.match(/(Blue|Poetry|Red)/)) {
return Family.Tan;
} else if(["Crane", "CampCurtain", "FullMoon", "RainMan", "Phoenix"].includes(name)) {
return Family.Hikari;
} else {
return Family.Tane;
}
}
/*
Pine0: 0, Pine1: 1, PinePoetry: 2, Crane: 3, Pine0: 0, Pine1: 1, PinePoetry: 2, Crane: 3,
Plum0: 4, Plum1: 5, PlumPoetry: 6, BushWarbler: 7, Plum0: 4, Plum1: 5, PlumPoetry: 6, BushWarbler: 7,
Cherry0: 8, Cherry1: 9, CherryPoetry: 10, CampCurtain: 11, Cherry0: 8, Cherry1: 9, CherryPoetry: 10, CampCurtain: 11,
@ -28,20 +75,49 @@ function Hanafuda() {
Paulownia0: 44, Paulownia1: 45, Sand: 46, Phoenix: 47 Paulownia0: 44, Paulownia1: 45, Sand: 46, Phoenix: 47
}); });
var kasu = Object.freeze(
Array.apply(null, Array(10)).reduce(
function(t, _, i) {return t.concat(4*i, 4*i + 1);}, []
).concat(
["Lightning", "Paulownia0", "Paulownia1", "Sand"].map(modules.fun.of(Card))
).reduce(setKey, {})
);
var tan = Object.freeze(
["Pine", "Plum", "Cherry"].map(function(name) {return name+"Poetry";}).concat(
["Wisteria", "Iris", "BushClover"].map(function(name) {return name+"Red";}),
["Peony", "Chrysanthemum", "Maple"].map(function(name) {return name+"Blue";})
)
.map(modules.fun.of(Card))
.reduce(setKey, {})
);
var tane = Object.freeze(
[
"BushWarbler", "Cuckoo", "EightPlankBridge", "Butterflies",
"Boar", "Geese", "SakeCup", "Deer", "Swallow"
]
.map(modules.fun.of(Card))
.reduce(setKey, {})
);
var light = Object.freeze(
["Crane", "CampCurtain", "FullMoon", "RainMan", "Phoenix"]
.map(modules.fun.of(Card))
.reduce(setKey, {})
);
*/
return { return {
Flower: Flower, Flower: Flower,
Family: Family,
Card: Card, Card: Card,
flower: flower,
sameMonth: sameMonth sameMonth: sameMonth
}; };
function flower(card) {
return Math.floor(card / 4);
}
function sameMonth(card) { function sameMonth(card) {
var first = 4 * flower(card); var first = 4 * card.flower;
return [0,1,2,3].map(function(i) {return first + i;}); return [0,1,2,3].map(function(i) {return Card[CardNames[first + i]];});
} }
/* /*

View File

@ -36,10 +36,26 @@
</form> </form>
</div> </div>
<div id="game"> <div id="game">
<ul id="status"></ul>
<h2>River</h2> <h2>River</h2>
<ul id="river"></ul> <ul id="river"></ul>
<span id="turned" class="card hidden"></span>
<h2>Hand</h2> <h2>Hand</h2>
<ul id="hand"></ul> <ul id="hand"></ul>
<div id="opponent">
<span class="score"></span>
<ul class="kasu"></ul>
<ul class="tane"></ul>
<ul class="tan"></ul>
<ul class="hikari"></ul>
</div>
<div id="own">
<span class="score"></span>
<ul class="kasu"></ul>
<ul class="tane"></ul>
<ul class="tan"></ul>
<ul class="hikari"></ul>
</div>
</div> </div>
<p id="debug"></p> <p id="debug"></p>
</body> </body>

View File

@ -6,8 +6,8 @@ window.addEventListener('load', function() {
var session = Session({messaging: messaging}); var session = Session({messaging: messaging});
var room = Room({dom: dom, messaging: messaging, session: session, fun: fun}); var room = Room({dom: dom, messaging: messaging, session: session, fun: fun});
var login = Login({dom: dom, messaging: messaging, room: room, screen: screen, session: session}); var login = Login({dom: dom, messaging: messaging, room: room, screen: screen, session: session});
var hanafuda = Hanafuda(); var hanafuda = Hanafuda({fun: fun});
var game = Game({dom: dom, fun: fun, hanafuda: hanafuda, messaging: messaging, session: session}); var game = Game({dom: dom, fun: fun, hanafuda: hanafuda, messaging: messaging, room: room, session: session});
messaging.start(); messaging.start();
}); });