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);
94 function sp_load(file, game)
97 json_load(file, game);
100 sp_suit = game["suit"];
101 sp_piles = game["piles"];
102 sp_acopy(sp_pile, game["pile"]);
105 sp_state = game["state"];
106 sp_broken = game["broken"];
107 sp_acopy(sp_looked, game["looked"]);
108 sp_acopy(sp_bids, game["bids"]);
109 sp_acopy(sp_nil, game["nil"]);
110 sp_acopy(sp_pass, game["pass"]);
111 sp_acopy(sp_tricks, game["tricks"]);
114 sp_channel = game["channel"];
115 sp_owner = game["owner"];
116 sp_playto = game["playto"];
117 sp_dealer = game["dealer"];
118 sp_turn = game["turn"];
119 sp_player = game["player"];
120 sp_acopy(sp_hands, game["hands"]);
121 sp_acopy(sp_players, game["players"]);
122 sp_acopy(sp_order, game["order"]);
123 sp_acopy(sp_scores, game["scores"]);
127 function sp_pretty(cards, who)
130 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
131 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
132 gsub(/s/, "\002♠", cards)
133 gsub(/h/, "\002♥", cards)
134 gsub(/d/, "\002♦", cards)
135 gsub(/c/, "\002♣", cards)
140 function sp_next(who, prev)
143 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
144 if (length(sp_order) == 4)
145 sp_player = sp_order[sp_turn]
149 function sp_deal( shuf)
151 say("/me deals the cards")
152 asorti(sp_deck, shuf, "sp_usort")
153 for (i=1; i<=52; i++)
154 sp_hands[sp_order[i%4]][shuf[i]] = 1
156 sp_dealer = (sp_dealer+1)%4
158 sp_player = sp_order[sp_turn]
159 say("Bidding starts with " sp_player "!")
162 function sp_hand(who, sort, str)
164 asorti(sp_hands[who], sort, "sp_csort")
165 for (i=0; i<length(sort); i++)
166 str = str "" sprintf("%4s", sort[i])
167 gsub(/^ +| +$/, "", str)
168 return sp_pretty(str, who)
171 function sp_hasa(who, expr)
173 for (c in sp_hands[who]) {
180 function sp_type(card)
182 return substr(card, length(card))
185 function sp_usort(a,b,c,d) {
189 function sp_csort(i1,v1,i2,v2) {
190 return sp_deck[i1] > sp_deck[i2] ? +1 :
191 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
194 function sp_winner( card, tmp)
196 for (card in sp_pile)
197 if (card !~ sp_suit && card !~ /s/)
199 asorti(sp_pile, tmp, "sp_csort")
200 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
206 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
207 return sp_order[i+0] "/" sp_order[i+2]
210 function sp_bags(i, bags)
212 bags = sp_scores[i] % 10
218 function sp_bidders( i, turn, bid, bids)
220 for (i = 0; i < 4; i++) {
221 turn = (sp_dealer + i) % 4
222 if (sp_bids[turn] && !sp_nil[turn]) {
223 bid = sp_order[turn] ":" sp_bids[turn]
227 gsub(/^ +| +$/, "", bids)
231 function sp_score( bids, tricks)
233 for (i=0; i<2; i++) {
234 bids = sp_bids[i] + sp_bids[i+2]
235 tricks = sp_tricks[i] + sp_tricks[i+2]
237 if (sp_bags(i) + bags >= 10) {
238 say(sp_team(i) " bag out")
241 if (tricks >= bids) {
242 say(sp_team(i) " make their bid: " tricks "/" bids)
243 sp_scores[i] += bids*10 + bags;
245 say(sp_team(i) " go bust: " tricks "/" bids)
246 sp_scores[i] -= bids*10;
249 for (i=0; i<4; i++) {
252 say(sp_order[i] " " \
253 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
254 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
255 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
256 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
258 sp_scores[i%2] += 100 * sp_nil[i] * \
259 (sp_tricks[i] == 0 ? 1 : -1)
263 function sp_play(card, winner, pi)
265 delete sp_hands[FROM][card]
266 sp_pile[card] = sp_player
267 sp_piles = sp_piles (sp_piles?",":"") card
274 if (length(sp_pile) == 1)
275 sp_suit = sp_type(card)
278 if (length(sp_pile) == 4) {
280 pi = sp_players[sp_pile[winner]]
282 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
283 " (" sp_pretty(sp_piles, FROM) ")")
284 sp_next(sp_pile[winner])
289 if (sp_tricks[0] + sp_tricks[1] + \
290 sp_tricks[2] + sp_tricks[3] == 13) {
293 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
294 sp_scores[0] != sp_scores[1]) {
296 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
298 say(sp_team(winner) " wins the game " \
299 sp_scores[winner] " to " sp_scores[looser])
300 say(sp_order[winner+0] "++")
301 say(sp_order[winner+2] "++")
302 say(sp_order[looser+0] "--")
303 say(sp_order[looser+2] "--")
307 if (sp_scores[0] == sp_scores[1] &&
308 sp_scores[0] >= sp_playto)
309 say("It's tie! Playing an extra round!");
318 cmd = "od -An -N4 -td4 /dev/random"
327 sp_valid = (FROM && FROM == sp_player)
332 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
337 sp_save("var/spades.json");
342 sp_load("var/spades.json");
346 /^\.help [Ss]pades$/ {
347 say("Spades -- play a game of spades")
349 say(".newgame [score] -- start a game to <score> points, default 500")
350 say(".endgame -- abort the current game")
351 say(".savegame -- save the current game to disk")
352 say(".loadgame -- load the previously saved game")
353 say(".join -- join the current game")
354 say(".look -- look at your cards")
355 say(".bid n -- bid for <n> tricks")
356 say(".play [card] -- play a card")
357 say(".score -- check the score")
358 say(".tricks -- check how many trick have been taken")
359 say(".bids -- check what everyone bid")
365 /^\.deal (\w+) (.*)/ {
367 for (i=3; i<=NF; i++)
369 say(sp_channel, FROM " is cheating for " $2)
374 /^\.newgame ?([0-9]+)?/ {
375 if (sp_state != "new") {
376 reply("There is already a game in progress.")
379 sp_playto = $2 ? $2 : 200
382 say(sp_owner " starts a game of Spades to " sp_playto "!")
383 #say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
387 (FROM == sp_owner || FROM == OWNER) &&
389 if (sp_state == "new") {
390 reply("There is no game in progress.")
392 say(FROM " ends the game")
398 if (sp_state == "new") {
399 reply("There is no game in progress")
401 else if (sp_state == "play") {
402 reply("The game has already started")
404 else if (sp_state == "join" && FROM in sp_players) {
405 reply("You are already playing")
407 else if (sp_state == "join") {
411 say(FROM " joins the game!")
413 if (sp_state == "join" && sp_turn == 0)
418 (sp_state "bid" || sp_state == "play") &&
420 if (FROM in sp_players)
421 say(".slap " FROM ", it is not your turn.")
423 say(".slap " FROM ", you are not playing.")
429 if ($2 < 0 || $2 > 13) {
430 say("You can only bid from 0 to 13")
434 if ($2 == 0 && !sp_looked[i]) {
435 say(FROM " goes blind nil!")
437 } else if ($2 == 0) {
438 say(FROM " goes nil!")
443 if (sp_turn != sp_dealer) {
444 say("Bidding goes to " sp_player "!")
446 for (p in sp_players)
447 say(p, "You have: " sp_hand(p))
449 for (i=0; i<2; i++) {
450 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
451 say(sp_team(i) ": select a card to pass " \
452 "(/msg " NICK " .pass <card>)")
456 if (sp_state == "play")
457 say("Play starts with " sp_player "!")
462 sp_state == "pass" &&
465 team = sp_players[FROM] % 2
466 if (!(FROM in sp_players)) {
467 say(".slap " FROM ", you are not playing.")
469 else if (sp_nil[team] != 2 && sp_nil[team+2] != 2) {
470 reply("Your team did not go blind")
472 else if (sp_pass[sp_players[FROM]]) {
473 reply("You have already passed a card")
475 else if (!(card in sp_deck)) {
476 reply("Invalid card")
478 else if (!(card in sp_hands[FROM])) {
479 reply("You do not have that card")
482 sp_pass[sp_players[FROM]] = $2
483 say(sp_channel, FROM " passes a card")
485 if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
486 ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
490 delete sp_hands[sp_order[i]][card]
491 sp_hands[sp_order[partner]][card] = 1
493 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
494 for (p in sp_players)
495 say(p, "You have: " sp_hand(p))
500 sp_state ~ "(play|bid)" &&
502 if (!(FROM in sp_players)) {
503 say(".slap " FROM ", you are not playing.")
505 sp_looked[sp_players[FROM]] = 1
506 say(FROM, "You have: " sp_hand(FROM))
511 sp_state == "play" &&
514 if (!(card in sp_deck)) {
515 reply("Invalid card")
517 else if (!(card in sp_hands[FROM])) {
518 reply("You do not have that card")
520 else if (sp_suit && card !~ sp_suit && sp_hasa(FROM, sp_suit)) {
521 reply("You must follow suit (" sp_suit ")")
523 else if (card ~ /s/ && length(sp_hands[FROM]) == 13 && sp_hasa(FROM, "[^s]$")) {
524 reply("You cannot trump on the first hand")
526 else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(FROM, "[^s]$") && !sp_broken) {
527 reply("Spades have not been broken")
531 if (sp_state == "play") {
532 if (length(sp_hands[FROM]))
533 say(FROM, "You have: " sp_hand(FROM))
535 say(sp_player ": it is your turn! " \
536 "(" sp_pretty(sp_piles, sp_player) ")")
538 say(sp_player ": it is your turn!")
543 /^\.bids$/ && sp_state == "play" {
544 say(sp_order[0] " bid " sp_bids[0] ", " \
545 sp_order[2] " bid " sp_bids[2] ", " \
546 "total: " sp_bids[0] + sp_bids[2])
547 say(sp_order[1] " bid " sp_bids[1] ", " \
548 sp_order[3] " bid " sp_bids[3] ", " \
549 "total: " sp_bids[1] + sp_bids[3])
552 /^\.tricks$/ && sp_state == "play" {
553 say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
554 sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
555 say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
556 sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
559 /\.turn/ && sp_state ~ "(play|bid)" {
561 _pile = sp_pretty(sp_piles, FROM)
562 if (sp_state == "bid" && !_bids)
563 say("It is " sp_player "'s bid!")
564 if (sp_state == "bid" && _bids)
565 say("It is " sp_player "'s bid! (" _bids ")")
566 if (sp_state == "play" && !_pile)
567 say("It is " sp_player "'s turn!")
568 if (sp_state == "play" && _pile)
569 say("It is " sp_player "'s turn! (" _pile ")")
572 (TO == NICK || DST == sp_channel) &&
573 /^\.(score|status)$/ {
574 if (sp_state == "new") {
575 say("There is no game in progress")
577 if (sp_state == "join") {
578 say("Waiting for players: " \
579 sp_order[0] " " sp_order[1] " " \
580 sp_order[2] " " sp_order[3])
582 if (sp_state == "bid" || sp_state == "play") {
583 say(sp_team(0) ": " \
584 int(sp_scores[0]) " points, " \
585 int(sp_bags(0)) " bags")
586 say(sp_team(1) ": " \
587 int(sp_scores[1]) " points, " \
588 int(sp_bags(1)) " bags")
593 #/^\.playfor [^ ]*$/ {
596 #/^\.standin [^ ]*$/ {
597 # if (p in sp_players) {
599 # for (p in sp_standin) {
600 # if ($2 in sp_standin)
601 # say(here " is already playing for " sp_standin[p]);
603 # sp_standin[away] = here