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_from = "" # The speakers player name
22 sp_valid = "" # It is the speaker turn
27 sp_suit = "" # The lead suit {s,h,d,c}
28 sp_piles = "" # [x] Played cards this turn
29 delete sp_pile # [x] Played cards this turn
34 sp_state = "bid" # {new,join,bid,pass,play}
35 sp_broken = 0 # Whether spades are broken
36 delete sp_looked # [i] Whether a player has looked a their cards
37 delete sp_bids # [i] Each players bid
38 delete sp_nil # [i] Nil multiplier 0=regular, 1=nil, 2=blind
39 delete sp_pass # [i] Cards to pass
40 delete sp_tricks # [i] Tricks this round
45 sp_channel = "" # channel to play in
46 sp_state = "new" # {new,join,bid,play}
47 sp_owner = "" # Who started the game
48 sp_playto = 0 # Score the game will go to
49 sp_dealer =-1 # Who is dealing this round
50 sp_turn = 0 # Index of who's turn it is
51 sp_player = "" # Who's turn it is
52 sp_limit = 10 # Bag out limit
53 delete sp_hands # [p] Each players cards
54 delete sp_players # [p] Player names players["name"] -> i
55 delete sp_auths # [c] Player auth names auths["auth"] -> "name"
56 delete sp_order # [i] Player order order[i] -> "name"
57 delete sp_scores # [i] Teams score
61 function sp_acopy(dst, src, key)
65 json_copy(dst, key, src[key])
68 function sp_save(file, game)
71 game["suit"] = sp_suit;
72 game["piles"] = sp_piles;
73 json_copy(game, "pile", sp_pile);
76 game["state"] = sp_state;
77 game["broken"] = sp_broken;
78 json_copy(game, "looked", sp_looked);
79 json_copy(game, "bids", sp_bids);
80 json_copy(game, "nil", sp_nil);
81 json_copy(game, "pass", sp_pass);
82 json_copy(game, "tricks", sp_tricks);
85 game["channel"] = sp_channel;
86 game["owner"] = sp_owner;
87 game["playto"] = sp_playto;
88 game["dealer"] = sp_dealer;
89 game["turn"] = sp_turn;
90 game["player"] = sp_player;
91 game["limit"] = sp_limit;
92 json_copy(game, "hands", sp_hands);
93 json_copy(game, "players", sp_players);
94 json_copy(game, "auths", sp_auths);
95 json_copy(game, "order", sp_order);
96 json_copy(game, "scores", sp_scores);
99 json_save(file, game);
102 function sp_load(file, game)
105 if (!json_load(file, game))
109 sp_suit = game["suit"];
110 sp_piles = game["piles"];
111 sp_acopy(sp_pile, game["pile"]);
114 sp_state = game["state"];
115 sp_broken = game["broken"];
116 sp_acopy(sp_looked, game["looked"]);
117 sp_acopy(sp_bids, game["bids"]);
118 sp_acopy(sp_nil, game["nil"]);
119 sp_acopy(sp_pass, game["pass"]);
120 sp_acopy(sp_tricks, game["tricks"]);
123 sp_channel = game["channel"];
124 sp_owner = game["owner"];
125 sp_playto = game["playto"];
126 sp_dealer = game["dealer"];
127 sp_turn = game["turn"];
128 sp_player = game["player"];
129 sp_limit = game["limit"];
130 sp_acopy(sp_hands, game["hands"]);
131 sp_acopy(sp_players, game["players"]);
132 sp_acopy(sp_auths, game["auths"]);
133 sp_acopy(sp_order, game["order"]);
134 sp_acopy(sp_scores, game["scores"]);
137 function sp_pretty(cards, who)
140 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
141 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
143 if (!nounicode[who]) {
144 gsub(/s/, "\002♠", cards)
145 gsub(/h/, "\002♥", cards)
146 gsub(/d/, "\002♦", cards)
147 gsub(/c/, "\002♣", cards)
152 function sp_next(who, prev)
155 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
156 if (length(sp_order) == 4)
157 sp_player = sp_order[sp_turn]
161 function sp_deal( shuf)
163 say("/me deals the cards")
164 asorti(sp_deck, shuf, "sp_usort")
165 for (i=1; i<=52; i++)
166 sp_hands[sp_order[i%4]][shuf[i]] = 1
168 sp_dealer = (sp_dealer+1)%4
170 sp_player = sp_order[sp_turn]
171 say("Bidding starts with " sp_player "!")
174 function sp_hand(to, who, sort, str)
176 asorti(sp_hands[who], sort, "sp_csort")
177 for (i=0; i<length(sort); i++)
178 str = str "" sprintf("%4s", sort[i])
179 gsub(/^ +| +$/, "", str)
180 return sp_pretty(str, to)
183 function sp_hasa(who, expr)
185 for (c in sp_hands[who]) {
192 function sp_type(card)
194 return substr(card, length(card))
197 function sp_usort(a,b,c,d) {
201 function sp_csort(i1,v1,i2,v2) {
202 return sp_deck[i1] > sp_deck[i2] ? +1 :
203 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
206 function sp_winner( card, tmp)
208 for (card in sp_pile)
209 if (card !~ sp_suit && card !~ /s/)
211 asorti(sp_pile, tmp, "sp_csort")
212 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
218 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
219 return sp_order[i+0] "/" sp_order[i+2]
222 function sp_bags(i, bags)
224 bags = sp_scores[i] % sp_limit
230 function sp_bidders( i, turn, bid, bids)
232 for (i = 0; i < 4; i++) {
233 turn = (sp_dealer + i) % 4
234 if (sp_bids[turn] && !sp_nil[turn])
235 bid = sp_order[turn] ":" sp_bids[turn]
236 else if (sp_nil[turn] == 1)
237 bid = sp_order[turn] ":" "nil"
238 else if (sp_nil[turn] == 2)
239 bid = sp_order[turn] ":" "blind"
244 gsub(/^ +| +$/, "", bids)
248 function sp_score( bids, tricks)
250 for (i=0; i<2; i++) {
251 bids = sp_bids[i] + sp_bids[i+2]
252 tricks = sp_tricks[i] + sp_tricks[i+2]
254 if (sp_bags(i) + bags >= sp_limit) {
255 say(sp_team(i) " bag out")
256 sp_scores[i] -= sp_limit * 10
258 if (tricks >= bids) {
259 say(sp_team(i) " make their bid: " tricks "/" bids)
260 sp_scores[i] += bids*10 + bags;
262 say(sp_team(i) " go bust: " tricks "/" bids)
263 sp_scores[i] -= bids*10;
266 for (i=0; i<4; i++) {
269 say(sp_order[i] " " \
270 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
271 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
272 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
273 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
275 sp_scores[i%2] += 100 * sp_nil[i] * \
276 (sp_tricks[i] == 0 ? 1 : -1)
280 function sp_play(card, winner, pi)
282 delete sp_hands[sp_from][card]
283 sp_pile[card] = sp_player
284 sp_piles = sp_piles (sp_piles?",":"") card
291 if (length(sp_pile) == 1)
292 sp_suit = sp_type(card)
295 if (length(sp_pile) == 4) {
297 pi = sp_players[sp_pile[winner]]
299 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
300 " (" sp_pretty(sp_piles, FROM) ")")
301 sp_next(sp_pile[winner])
306 if (sp_tricks[0] + sp_tricks[1] + \
307 sp_tricks[2] + sp_tricks[3] == 13) {
310 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
311 sp_scores[0] != sp_scores[1]) {
313 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
315 say(sp_team(winner) " wins the game " \
316 sp_scores[winner] " to " sp_scores[looser])
317 say(sp_order[winner+0] "++")
318 say(sp_order[winner+2] "++")
319 say(sp_order[looser+0] "--")
320 say(sp_order[looser+2] "--")
324 if (sp_scores[0] == sp_scores[1] &&
325 sp_scores[0] >= sp_playto)
326 say("It's tie! Playing an extra round!");
335 cmd = "od -An -N4 -td4 /dev/random"
341 sp_load("var/sp_cur.json");
343 # say(sp_channel, "Game restored.")
347 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : FROM
348 sp_valid = sp_from && sp_from == sp_player
354 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
359 sp_save("var/sp_save.json");
365 sp_load("var/sp_save.json");
370 /^\.help [Ss]pades$/ {
371 say("Spades -- play a game of spades")
373 say(".newgame [score] -- start a game to <score> points, default 500")
374 say(".endgame -- abort the current game")
375 say(".savegame -- save the current game to disk")
376 say(".loadgame -- load the previously saved game")
377 say(".join -- join the current game")
378 say(".look -- look at your cards")
379 say(".bid n -- bid for <n> tricks")
380 say(".play [card] -- play a card")
381 say(".score -- check the score")
382 say(".tricks -- check how many trick have been taken")
383 say(".bids -- check what everyone bid")
389 /^\.deal (\w+) (.*)/ {
391 for (i=3; i<=NF; i++)
393 say(sp_channel, FROM " is cheating for " $2)
398 /^\.newgame ?([0-9]+)?/ {
399 if (sp_state != "new") {
400 reply("There is already a game in progress.")
403 sp_playto = $2 ? $2 : 200
404 sp_limit = sp_playto > 200 ? 10 : 5;
407 say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
408 #say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
412 (sp_from == sp_owner || AUTH == OWNER) &&
414 if (sp_state == "new") {
415 reply("There is no game in progress.")
417 say(FROM " ends the game")
423 if (sp_state == "new") {
424 reply("There is no game in progress")
426 else if (sp_state == "play") {
427 reply("The game has already started")
429 else if (sp_state == "join" && sp_from in sp_players) {
430 reply("You are already playing")
432 else if (sp_state == "join") {
436 sp_auths[AUTH] = FROM
438 say(FROM " joins the game!")
440 if (sp_state == "join" && sp_turn == 0)
445 (sp_state "bid" || sp_state == "play") &&
447 if (sp_from in sp_players)
448 say(".slap " FROM ", it is not your turn.")
450 say(".slap " FROM ", you are not playing.")
456 if ($2 < 0 || $2 > 13) {
457 say("You can only bid from 0 to 13")
461 if ($2 == 0 && !sp_looked[i]) {
462 say(FROM " goes blind nil!")
464 } else if ($2 == 0) {
465 say(FROM " goes nil!")
470 if (sp_turn != sp_dealer) {
471 say("Bidding goes to " sp_player "!")
473 for (p in sp_players)
474 say(p, "You have: " sp_hand(p, p))
476 for (i=0; i<2; i++) {
477 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
478 say(sp_team(i) ": select a card to pass " \
479 "(/msg " NICK " .pass <card>)")
483 if (sp_state == "play")
484 say("Play starts with " sp_player "!")
489 sp_state == "pass" &&
492 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
494 # check validity and pass
495 if (!(sp_from in sp_players)) {
496 say(".slap " FROM ", you are not playing.")
498 else if (sp_nil[_team] != 2 && sp_nil[_team+2] != 2) {
499 reply("Your team did not go blind")
501 else if (sp_pass[sp_players[sp_from]]) {
502 reply("You have already passed a card")
504 else if (!(_card in sp_deck)) {
505 reply("Invalid card")
507 else if (!(_card in sp_hands[sp_from])) {
508 reply("You do not have that card")
511 sp_pass[sp_players[sp_from]] = $2
512 say(sp_channel, FROM " passes a card")
515 # check for end of passing
516 if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
517 ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
521 delete sp_hands[sp_order[i]][_card]
522 sp_hands[sp_order[_partner]][_card] = 1
524 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
525 for (p in sp_players)
526 say(p, "You have: " sp_hand(p, p))
531 sp_state ~ "(bid|pass|play)" &&
533 if (!(sp_from in sp_players)) {
534 say(".slap " FROM ", you are not playing.")
536 sp_looked[sp_players[sp_from]] = 1
537 say(FROM, "You have: " sp_hand(FROM, sp_from))
542 sp_state == "play" &&
545 if (!(card in sp_deck)) {
546 reply("Invalid card")
548 else if (!(card in sp_hands[sp_from])) {
549 reply("You do not have that card")
551 else if (sp_suit && card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
552 reply("You must follow suit (" sp_suit ")")
554 else if (card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
555 reply("You cannot trump on the first hand")
557 else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
558 reply("Spades have not been broken")
562 if (sp_state == "play") {
563 if (length(sp_hands[sp_from]))
564 say(FROM, "You have: " sp_hand(FROM, sp_from))
566 say(sp_player ": it is your turn! " \
567 "(" sp_pretty(sp_piles, sp_player) ")")
569 say(sp_player ": it is your turn!")
574 /^\.bids$/ && sp_state ~ "(pass|play)" {
575 say(sp_order[0] " bid " sp_bids[0] ", " \
576 sp_order[2] " bid " sp_bids[2] ", " \
577 "total: " sp_bids[0] + sp_bids[2])
578 say(sp_order[1] " bid " sp_bids[1] ", " \
579 sp_order[3] " bid " sp_bids[3] ", " \
580 "total: " sp_bids[1] + sp_bids[3])
583 /^\.tricks$/ && sp_state == "play" {
584 say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
585 sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
586 say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
587 sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
590 /^\.turn/ && sp_state ~ "(bid|pass|play)" {
592 _pile = sp_pretty(sp_piles, FROM)
593 if (sp_state == "bid" && !_bids)
594 say("It is " sp_player "'s bid!")
595 if (sp_state == "bid" && _bids)
596 say("It is " sp_player "'s bid! (" _bids ")")
597 if (sp_state == "play" && !_pile)
598 say("It is " sp_player "'s turn!")
599 if (sp_state == "play" && _pile)
600 say("It is " sp_player "'s turn! (" _pile ")")
601 for (_i=0; sp_state == "pass" && _i<4; _i++)
602 if ((sp_nil[_i%2+0]==2 || sp_nil[_i%2+2]==2) && !sp_pass[_i])
603 say("Waiting for " sp_order[_i] " to pass a card!")
606 (TO == NICK || DST == sp_channel) &&
607 /^\.(score|status)$/ {
608 if (sp_state == "new") {
609 say("There is no game in progress")
611 if (sp_state == "join") {
612 say("Waiting for players: " \
613 sp_order[0] " " sp_order[1] " " \
614 sp_order[2] " " sp_order[3])
616 if (sp_state ~ "bid|pass|play") {
618 sp_playto " points, " \
620 say(sp_team(0) ": " \
621 int(sp_scores[0]) " points, " \
622 int(sp_bags(0)) " bags")
623 say(sp_team(1) ": " \
624 int(sp_scores[1]) " points, " \
625 int(sp_bags(1)) " bags")
629 /^\.((new|end|load)game|join|look|bid|play)/ {
630 sp_save("var/sp_cur.json");
634 #/^\.playfor [^ ]*$/ {
637 #/^\.standin [^ ]*$/ {
638 # if (p in sp_players) {
640 # for (p in sp_standin) {
641 # if ($2 in sp_standin)
642 # say(here " is already playing for " sp_standin[p]);
644 # sp_standin[away] = here