5 function sp_init(cards, tmp0, tmp1)
8 cards ="As Ks Qs Js 10s 9s 8s 7s 6s 5s 4s 3s 2s "\
9 "Ah Kh Qh Jh 10h 9h 8h 7h 6h 5h 4h 3h 2h "\
10 "Ac Kc Qc Jc 10c 9c 8c 7c 6c 5c 4c 3c 2c "\
11 "Ad Kd Qd Jd 10d 9d 8d 7d 6d 5d 4d 3d 2d"
13 for (i=1; i<=length(tmp0); i++)
17 function sp_reset(type)
21 sp_suit = "" # The lead suit {s,h,d,c}
22 sp_piles = "" # [x] Played cards this turn
23 delete sp_pile # [x] Played cards this turn
28 sp_state = "bid" # {new,join,bid,pass,play}
29 sp_broken = 0 # Whether spades are broken
30 delete sp_looked # [i] Whether a player has looked a their cards
31 delete sp_bids # [i] Each players bid
32 delete sp_nil # [i] Nil multiplier 0=regular, 1=nil, 2=blind
33 delete sp_pass # [i] Cards to pass
34 delete sp_tricks # [i] Tricks this round
39 sp_channel = "" # channel to play in
40 sp_state = "new" # {new,join,bid,play}
41 sp_owner = "" # Who started the game
42 sp_playto = 0 # Score the game will go to
43 sp_dealer =-1 # Who is dealing this round
44 sp_turn = 0 # Index of who's turn it is
45 sp_player = "" # Who's turn it is
46 sp_valid = 0 # Message sent from sp_player
47 delete sp_hands # [p] Each players cards
48 delete sp_players # [p] Player names players["name"] -> i
49 delete sp_order # [i] Player order order[i] -> "name"
50 delete sp_scores # [i] Teams score
54 function sp_acopy(dst, src, key)
58 json_copy(dst, key, src[key])
61 function sp_save(file, game)
64 game["suit"] = sp_suit;
65 game["piles"] = sp_piles;
66 json_copy(game, "pile", sp_pile);
69 game["state"] = sp_state;
70 game["broken"] = sp_broken;
71 json_copy(game, "looked", sp_looked);
72 json_copy(game, "bids", sp_bids);
73 json_copy(game, "nil", sp_nil);
74 json_copy(game, "pass", sp_pass);
75 json_copy(game, "tricks", sp_tricks);
78 game["channel"] = sp_channel;
79 game["owner"] = sp_owner;
80 game["playto"] = sp_playto;
81 game["dealer"] = sp_dealer;
82 game["turn"] = sp_turn;
83 game["player"] = sp_player;
84 json_copy(game, "hands", sp_hands);
85 json_copy(game, "players", sp_players);
86 json_copy(game, "order", sp_order);
87 json_copy(game, "scores", sp_scores);
90 json_save(file, game);
93 function sp_load(file, game)
96 json_load(file, game);
99 sp_suit = game["suit"];
100 sp_piles = game["piles"];
101 sp_acopy(sp_pile, game["pile"]);
104 sp_state = game["state"];
105 sp_broken = game["broken"];
106 sp_acopy(sp_looked, game["looked"]);
107 sp_acopy(sp_bids, game["bids"]);
108 sp_acopy(sp_nil, game["nil"]);
109 sp_acopy(sp_pass, game["pass"]);
110 sp_acopy(sp_tricks, game["tricks"]);
113 sp_channel = game["channel"];
114 sp_owner = game["owner"];
115 sp_playto = game["playto"];
116 sp_dealer = game["dealer"];
117 sp_turn = game["turn"];
118 sp_player = game["player"];
119 sp_acopy(sp_hands, game["hands"]);
120 sp_acopy(sp_players, game["players"]);
121 sp_acopy(sp_order, game["order"]);
122 sp_acopy(sp_scores, game["scores"]);
125 function sp_pretty(cards, who)
128 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
129 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
130 gsub(/s/, "\002♠", cards)
131 gsub(/h/, "\002♥", cards)
132 gsub(/d/, "\002♦", cards)
133 gsub(/c/, "\002♣", cards)
138 function sp_next(who, prev)
141 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
142 if (length(sp_order) == 4)
143 sp_player = sp_order[sp_turn]
147 function sp_deal( shuf)
149 say("/me deals the cards")
150 asorti(sp_deck, shuf, "sp_usort")
151 for (i=1; i<=52; i++)
152 sp_hands[sp_order[i%4]][shuf[i]] = 1
154 sp_dealer = (sp_dealer+1)%4
156 sp_player = sp_order[sp_turn]
157 say("Bidding starts with " sp_player "!")
160 function sp_hand(who, sort, str)
162 asorti(sp_hands[who], sort, "sp_csort")
163 for (i=0; i<length(sort); i++)
164 str = str "" sprintf("%4s", sort[i])
165 gsub(/^ +| +$/, "", str)
166 return sp_pretty(str, who)
169 function sp_hasa(who, expr)
171 for (c in sp_hands[who]) {
178 function sp_type(card)
180 return substr(card, length(card))
183 function sp_usort(a,b,c,d) {
187 function sp_csort(i1,v1,i2,v2) {
188 return sp_deck[i1] > sp_deck[i2] ? +1 :
189 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
192 function sp_winner( card, tmp)
194 for (card in sp_pile)
195 if (card !~ sp_suit && card !~ /s/)
197 asorti(sp_pile, tmp, "sp_csort")
198 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
204 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
205 return sp_order[i+0] "/" sp_order[i+2]
208 function sp_bags(i, bags)
210 bags = sp_scores[i] % 10
216 function sp_bidders( i, turn, bid, bids)
218 for (i = 0; i < 4; i++) {
219 turn = (sp_dealer + i) % 4
220 if (sp_bids[turn] && !sp_nil[turn]) {
221 bid = sp_order[turn] ":" sp_bids[turn]
225 gsub(/^ +| +$/, "", bids)
229 function sp_score( bids, tricks)
231 for (i=0; i<2; i++) {
232 bids = sp_bids[i] + sp_bids[i+2]
233 tricks = sp_tricks[i] + sp_tricks[i+2]
235 if (sp_bags(i) + bags >= 10) {
236 say(sp_team(i) " bag out")
239 if (tricks >= bids) {
240 say(sp_team(i) " make their bid: " tricks "/" bids)
241 sp_scores[i] += bids*10 + bags;
243 say(sp_team(i) " go bust: " tricks "/" bids)
244 sp_scores[i] -= bids*10;
247 for (i=0; i<4; i++) {
250 say(sp_order[i] " " \
251 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
252 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
253 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
254 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
256 sp_scores[i%2] += 100 * sp_nil[i] * \
257 (sp_tricks[i] == 0 ? 1 : -1)
261 function sp_play(card, winner, pi)
263 delete sp_hands[FROM][card]
264 sp_pile[card] = sp_player
265 sp_piles = sp_piles (sp_piles?",":"") card
272 if (length(sp_pile) == 1)
273 sp_suit = sp_type(card)
276 if (length(sp_pile) == 4) {
278 pi = sp_players[sp_pile[winner]]
280 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
281 " (" sp_pretty(sp_piles, FROM) ")")
282 sp_next(sp_pile[winner])
287 if (sp_tricks[0] + sp_tricks[1] + \
288 sp_tricks[2] + sp_tricks[3] == 13) {
291 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
292 sp_scores[0] != sp_scores[1]) {
294 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
296 say(sp_team(winner) " wins the game " \
297 sp_scores[winner] " to " sp_scores[looser])
298 say(sp_order[winner+0] "++")
299 say(sp_order[winner+2] "++")
300 say(sp_order[looser+0] "--")
301 say(sp_order[looser+2] "--")
305 if (sp_scores[0] == sp_scores[1] &&
306 sp_scores[0] >= sp_playto)
307 say("It's tie! Playing an extra round!");
316 cmd = "od -An -N4 -td4 /dev/random"
322 sp_load("var/sp_cur.json");
324 say(sp_channel, "Game restored.")
328 sp_valid = (FROM && FROM == sp_player)
333 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
338 sp_save("var/sp_save.json");
344 sp_load("var/sp_save.json");
349 /^\.help [Ss]pades$/ {
350 say("Spades -- play a game of spades")
352 say(".newgame [score] -- start a game to <score> points, default 500")
353 say(".endgame -- abort the current game")
354 say(".savegame -- save the current game to disk")
355 say(".loadgame -- load the previously saved game")
356 say(".join -- join the current game")
357 say(".look -- look at your cards")
358 say(".bid n -- bid for <n> tricks")
359 say(".play [card] -- play a card")
360 say(".score -- check the score")
361 say(".tricks -- check how many trick have been taken")
362 say(".bids -- check what everyone bid")
368 /^\.deal (\w+) (.*)/ {
370 for (i=3; i<=NF; i++)
372 say(sp_channel, FROM " is cheating for " $2)
377 /^\.newgame ?([0-9]+)?/ {
378 if (sp_state != "new") {
379 reply("There is already a game in progress.")
382 sp_playto = $2 ? $2 : 200
385 say(sp_owner " starts a game of Spades to " sp_playto "!")
386 #say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
390 (FROM == sp_owner || FROM == OWNER) &&
392 if (sp_state == "new") {
393 reply("There is no game in progress.")
395 say(FROM " ends the game")
401 if (sp_state == "new") {
402 reply("There is no game in progress")
404 else if (sp_state == "play") {
405 reply("The game has already started")
407 else if (sp_state == "join" && FROM in sp_players) {
408 reply("You are already playing")
410 else if (sp_state == "join") {
414 say(FROM " joins the game!")
416 if (sp_state == "join" && sp_turn == 0)
421 (sp_state "bid" || sp_state == "play") &&
423 if (FROM in sp_players)
424 say(".slap " FROM ", it is not your turn.")
426 say(".slap " FROM ", you are not playing.")
432 if ($2 < 0 || $2 > 13) {
433 say("You can only bid from 0 to 13")
437 if ($2 == 0 && !sp_looked[i]) {
438 say(FROM " goes blind nil!")
440 } else if ($2 == 0) {
441 say(FROM " goes nil!")
446 if (sp_turn != sp_dealer) {
447 say("Bidding goes to " sp_player "!")
449 for (p in sp_players)
450 say(p, "You have: " sp_hand(p))
452 for (i=0; i<2; i++) {
453 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
454 say(sp_team(i) ": select a card to pass " \
455 "(/msg " NICK " .pass <card>)")
459 if (sp_state == "play")
460 say("Play starts with " sp_player "!")
465 sp_state == "pass" &&
468 team = sp_players[FROM] % 2
469 if (!(FROM in sp_players)) {
470 say(".slap " FROM ", you are not playing.")
472 else if (sp_nil[team] != 2 && sp_nil[team+2] != 2) {
473 reply("Your team did not go blind")
475 else if (sp_pass[sp_players[FROM]]) {
476 reply("You have already passed a card")
478 else if (!(card in sp_deck)) {
479 reply("Invalid card")
481 else if (!(card in sp_hands[FROM])) {
482 reply("You do not have that card")
485 sp_pass[sp_players[FROM]] = $2
486 say(sp_channel, FROM " passes a card")
488 if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
489 ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
493 delete sp_hands[sp_order[i]][card]
494 sp_hands[sp_order[partner]][card] = 1
496 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
497 for (p in sp_players)
498 say(p, "You have: " sp_hand(p))
503 sp_state ~ "(play|bid)" &&
505 if (!(FROM in sp_players)) {
506 say(".slap " FROM ", you are not playing.")
508 sp_looked[sp_players[FROM]] = 1
509 say(FROM, "You have: " sp_hand(FROM))
514 sp_state == "play" &&
517 if (!(card in sp_deck)) {
518 reply("Invalid card")
520 else if (!(card in sp_hands[FROM])) {
521 reply("You do not have that card")
523 else if (sp_suit && card !~ sp_suit && sp_hasa(FROM, sp_suit)) {
524 reply("You must follow suit (" sp_suit ")")
526 else if (card ~ /s/ && length(sp_hands[FROM]) == 13 && sp_hasa(FROM, "[^s]$")) {
527 reply("You cannot trump on the first hand")
529 else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(FROM, "[^s]$") && !sp_broken) {
530 reply("Spades have not been broken")
534 if (sp_state == "play") {
535 if (length(sp_hands[FROM]))
536 say(FROM, "You have: " sp_hand(FROM))
538 say(sp_player ": it is your turn! " \
539 "(" sp_pretty(sp_piles, sp_player) ")")
541 say(sp_player ": it is your turn!")
546 /^\.bids$/ && sp_state == "play" {
547 say(sp_order[0] " bid " sp_bids[0] ", " \
548 sp_order[2] " bid " sp_bids[2] ", " \
549 "total: " sp_bids[0] + sp_bids[2])
550 say(sp_order[1] " bid " sp_bids[1] ", " \
551 sp_order[3] " bid " sp_bids[3] ", " \
552 "total: " sp_bids[1] + sp_bids[3])
555 /^\.tricks$/ && sp_state == "play" {
556 say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
557 sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
558 say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
559 sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
562 /^\.turn/ && sp_state ~ "(play|bid)" {
564 _pile = sp_pretty(sp_piles, FROM)
565 if (sp_state == "bid" && !_bids)
566 say("It is " sp_player "'s bid!")
567 if (sp_state == "bid" && _bids)
568 say("It is " sp_player "'s bid! (" _bids ")")
569 if (sp_state == "play" && !_pile)
570 say("It is " sp_player "'s turn!")
571 if (sp_state == "play" && _pile)
572 say("It is " sp_player "'s turn! (" _pile ")")
575 (TO == NICK || DST == sp_channel) &&
576 /^\.(score|status)$/ {
577 if (sp_state == "new") {
578 say("There is no game in progress")
580 if (sp_state == "join") {
581 say("Waiting for players: " \
582 sp_order[0] " " sp_order[1] " " \
583 sp_order[2] " " sp_order[3])
585 if (sp_state == "bid" || sp_state == "play") {
586 say(sp_team(0) ": " \
587 int(sp_scores[0]) " points, " \
588 int(sp_bags(0)) " bags")
589 say(sp_team(1) ": " \
590 int(sp_scores[1]) " points, " \
591 int(sp_bags(1)) " bags")
595 /^\.((new|end|load)game|join|look|bid|play)/ {
596 sp_save("var/sp_cur.json");
600 #/^\.playfor [^ ]*$/ {
603 #/^\.standin [^ ]*$/ {
604 # if (p in sp_players) {
606 # for (p in sp_standin) {
607 # if ($2 in sp_standin)
608 # say(here " is already playing for " sp_standin[p]);
610 # sp_standin[away] = here