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
142 gsub(/s/, "\002♠", cards)
143 gsub(/h/, "\002♥", cards)
144 gsub(/d/, "\002♦", cards)
145 gsub(/c/, "\002♣", cards)
150 function sp_next(who, prev)
153 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
154 if (length(sp_order) == 4)
155 sp_player = sp_order[sp_turn]
159 function sp_deal( shuf)
161 say("/me deals the cards")
162 asorti(sp_deck, shuf, "sp_usort")
163 for (i=1; i<=52; i++)
164 sp_hands[sp_order[i%4]][shuf[i]] = 1
166 sp_dealer = (sp_dealer+1)%4
168 sp_player = sp_order[sp_turn]
169 say("Bidding starts with " sp_player "!")
172 function sp_hand(to, who, sort, str)
174 asorti(sp_hands[who], sort, "sp_csort")
175 for (i=0; i<length(sort); i++)
176 str = str "" sprintf("%4s", sort[i])
177 gsub(/^ +| +$/, "", str)
178 return sp_pretty(str, to)
181 function sp_hasa(who, expr)
183 for (c in sp_hands[who]) {
190 function sp_type(card)
192 return substr(card, length(card))
195 function sp_usort(a,b,c,d) {
199 function sp_csort(i1,v1,i2,v2) {
200 return sp_deck[i1] > sp_deck[i2] ? +1 :
201 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
204 function sp_winner( card, tmp)
206 for (card in sp_pile)
207 if (card !~ sp_suit && card !~ /s/)
209 asorti(sp_pile, tmp, "sp_csort")
210 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
216 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
217 return sp_order[i+0] "/" sp_order[i+2]
220 function sp_bags(i, bags)
222 bags = sp_scores[i] % sp_limit
228 function sp_bidders( i, turn, bid, bids)
230 for (i = 0; i < 4; i++) {
231 turn = (sp_dealer + i) % 4
232 if (sp_bids[turn] && !sp_nil[turn]) {
233 bid = sp_order[turn] ":" sp_bids[turn]
237 gsub(/^ +| +$/, "", bids)
241 function sp_score( bids, tricks)
243 for (i=0; i<2; i++) {
244 bids = sp_bids[i] + sp_bids[i+2]
245 tricks = sp_tricks[i] + sp_tricks[i+2]
247 if (sp_bags(i) + bags >= sp_limit) {
248 say(sp_team(i) " bag out")
249 sp_scores[i] -= sp_limit * 10
251 if (tricks >= bids) {
252 say(sp_team(i) " make their bid: " tricks "/" bids)
253 sp_scores[i] += bids*10 + bags;
255 say(sp_team(i) " go bust: " tricks "/" bids)
256 sp_scores[i] -= bids*10;
259 for (i=0; i<4; i++) {
262 say(sp_order[i] " " \
263 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
264 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
265 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
266 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
268 sp_scores[i%2] += 100 * sp_nil[i] * \
269 (sp_tricks[i] == 0 ? 1 : -1)
273 function sp_play(card, winner, pi)
275 delete sp_hands[sp_from][card]
276 sp_pile[card] = sp_player
277 sp_piles = sp_piles (sp_piles?",":"") card
284 if (length(sp_pile) == 1)
285 sp_suit = sp_type(card)
288 if (length(sp_pile) == 4) {
290 pi = sp_players[sp_pile[winner]]
292 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
293 " (" sp_pretty(sp_piles, FROM) ")")
294 sp_next(sp_pile[winner])
299 if (sp_tricks[0] + sp_tricks[1] + \
300 sp_tricks[2] + sp_tricks[3] == 13) {
303 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
304 sp_scores[0] != sp_scores[1]) {
306 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
308 say(sp_team(winner) " wins the game " \
309 sp_scores[winner] " to " sp_scores[looser])
310 say(sp_order[winner+0] "++")
311 say(sp_order[winner+2] "++")
312 say(sp_order[looser+0] "--")
313 say(sp_order[looser+2] "--")
317 if (sp_scores[0] == sp_scores[1] &&
318 sp_scores[0] >= sp_playto)
319 say("It's tie! Playing an extra round!");
328 cmd = "od -An -N4 -td4 /dev/random"
334 sp_load("var/sp_cur.json");
336 # say(sp_channel, "Game restored.")
340 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : FROM
341 sp_valid = sp_from && sp_from == sp_player
347 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
352 sp_save("var/sp_save.json");
358 sp_load("var/sp_save.json");
363 /^\.help [Ss]pades$/ {
364 say("Spades -- play a game of spades")
366 say(".newgame [score] -- start a game to <score> points, default 500")
367 say(".endgame -- abort the current game")
368 say(".savegame -- save the current game to disk")
369 say(".loadgame -- load the previously saved game")
370 say(".join -- join the current game")
371 say(".look -- look at your cards")
372 say(".bid n -- bid for <n> tricks")
373 say(".play [card] -- play a card")
374 say(".score -- check the score")
375 say(".tricks -- check how many trick have been taken")
376 say(".bids -- check what everyone bid")
382 /^\.deal (\w+) (.*)/ {
384 for (i=3; i<=NF; i++)
386 say(sp_channel, FROM " is cheating for " $2)
391 /^\.newgame ?([0-9]+)?/ {
392 if (sp_state != "new") {
393 reply("There is already a game in progress.")
396 sp_playto = $2 ? $2 : 200
397 sp_limit = sp_playto > 200 ? 10 : 5;
400 say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
401 #say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
405 (sp_from == sp_owner || AUTH == OWNER) &&
407 if (sp_state == "new") {
408 reply("There is no game in progress.")
410 say(FROM " ends the game")
416 if (sp_state == "new") {
417 reply("There is no game in progress")
419 else if (sp_state == "play") {
420 reply("The game has already started")
422 else if (sp_state == "join" && sp_from in sp_players) {
423 reply("You are already playing")
425 else if (sp_state == "join") {
429 sp_auths[AUTH] = FROM
431 say(FROM " joins the game!")
433 if (sp_state == "join" && sp_turn == 0)
438 (sp_state "bid" || sp_state == "play") &&
440 if (sp_from in sp_players)
441 say(".slap " FROM ", it is not your turn.")
443 say(".slap " FROM ", you are not playing.")
449 if ($2 < 0 || $2 > 13) {
450 say("You can only bid from 0 to 13")
454 if ($2 == 0 && !sp_looked[i]) {
455 say(FROM " goes blind nil!")
457 } else if ($2 == 0) {
458 say(FROM " goes nil!")
463 if (sp_turn != sp_dealer) {
464 say("Bidding goes to " sp_player "!")
466 for (p in sp_players)
467 say(p, "You have: " sp_hand(p, p))
469 for (i=0; i<2; i++) {
470 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
471 say(sp_team(i) ": select a card to pass " \
472 "(/msg " NICK " .pass <card>)")
476 if (sp_state == "play")
477 say("Play starts with " sp_player "!")
482 sp_state == "pass" &&
485 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
487 # check validity and pass
488 if (!(sp_from in sp_players)) {
489 say(".slap " FROM ", you are not playing.")
491 else if (sp_nil[_team] != 2 && sp_nil[_team+2] != 2) {
492 reply("Your team did not go blind")
494 else if (sp_pass[sp_players[sp_from]]) {
495 reply("You have already passed a card")
497 else if (!(_card in sp_deck)) {
498 reply("Invalid card")
500 else if (!(_card in sp_hands[sp_from])) {
501 reply("You do not have that card")
504 sp_pass[sp_players[sp_from]] = $2
505 say(sp_channel, FROM " passes a card")
508 # check for end of passing
509 if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
510 ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
514 delete sp_hands[sp_order[i]][_card]
515 sp_hands[sp_order[_partner]][_card] = 1
517 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
518 for (p in sp_players)
519 say(p, "You have: " sp_hand(p, p))
524 sp_state ~ "(bid|pass|play)" &&
526 if (!(sp_from in sp_players)) {
527 say(".slap " FROM ", you are not playing.")
529 sp_looked[sp_players[sp_from]] = 1
530 say(FROM, "You have: " sp_hand(FROM, sp_from))
535 sp_state == "play" &&
538 if (!(card in sp_deck)) {
539 reply("Invalid card")
541 else if (!(card in sp_hands[sp_from])) {
542 reply("You do not have that card")
544 else if (sp_suit && card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
545 reply("You must follow suit (" sp_suit ")")
547 else if (card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
548 reply("You cannot trump on the first hand")
550 else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
551 reply("Spades have not been broken")
555 if (sp_state == "play") {
556 if (length(sp_hands[sp_from]))
557 say(FROM, "You have: " sp_hand(FROM, sp_from))
559 say(sp_player ": it is your turn! " \
560 "(" sp_pretty(sp_piles, sp_player) ")")
562 say(sp_player ": it is your turn!")
567 /^\.bids$/ && sp_state == "play" {
568 say(sp_order[0] " bid " sp_bids[0] ", " \
569 sp_order[2] " bid " sp_bids[2] ", " \
570 "total: " sp_bids[0] + sp_bids[2])
571 say(sp_order[1] " bid " sp_bids[1] ", " \
572 sp_order[3] " bid " sp_bids[3] ", " \
573 "total: " sp_bids[1] + sp_bids[3])
576 /^\.tricks$/ && sp_state == "play" {
577 say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
578 sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
579 say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
580 sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
583 /^\.turn/ && sp_state ~ "(play|bid)" {
585 _pile = sp_pretty(sp_piles, FROM)
586 if (sp_state == "bid" && !_bids)
587 say("It is " sp_player "'s bid!")
588 if (sp_state == "bid" && _bids)
589 say("It is " sp_player "'s bid! (" _bids ")")
590 if (sp_state == "play" && !_pile)
591 say("It is " sp_player "'s turn!")
592 if (sp_state == "play" && _pile)
593 say("It is " sp_player "'s turn! (" _pile ")")
596 (TO == NICK || DST == sp_channel) &&
597 /^\.(score|status)$/ {
598 if (sp_state == "new") {
599 say("There is no game in progress")
601 if (sp_state == "join") {
602 say("Waiting for players: " \
603 sp_order[0] " " sp_order[1] " " \
604 sp_order[2] " " sp_order[3])
606 if (sp_state == "bid" || sp_state == "play") {
608 sp_playto " points, " \
610 say(sp_team(0) ": " \
611 int(sp_scores[0]) " points, " \
612 int(sp_bags(0)) " bags")
613 say(sp_team(1) ": " \
614 int(sp_scores[1]) " points, " \
615 int(sp_bags(1)) " bags")
619 /^\.((new|end|load)game|join|look|bid|play)/ {
620 sp_save("var/sp_cur.json");
624 #/^\.playfor [^ ]*$/ {
627 #/^\.standin [^ ]*$/ {
628 # if (p in sp_players) {
630 # for (p in sp_standin) {
631 # if ($2 in sp_standin)
632 # say(here " is already playing for " sp_standin[p]);
634 # sp_standin[away] = here