Playable game, only end of game isn't handled yet
This commit is contained in:
parent
4cd6842c01
commit
dc49f4eb0e
7 changed files with 248 additions and 48 deletions
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
35
www/game.css
35
www/game.css
|
@ -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;
|
||||||
|
}
|
||||||
|
|
116
www/game.js
116
www/game.js
|
@ -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,6 +143,7 @@ function Game(modules) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HandCard.prototype.onClick = function() {
|
HandCard.prototype.onClick = function() {
|
||||||
|
if(status.playing && status.step == "ToPlay") {
|
||||||
var card = this;
|
var card = this;
|
||||||
return function() {
|
return function() {
|
||||||
if(selected != undefined) {
|
if(selected != undefined) {
|
||||||
|
@ -78,12 +152,15 @@ function Game(modules) {
|
||||||
card.play();
|
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});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]];});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue