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 json_load(file, game);
108 sp_suit = game["suit"];
109 sp_piles = game["piles"];
110 sp_acopy(sp_pile, game["pile"]);
113 sp_state = game["state"];
114 sp_broken = game["broken"];
115 sp_acopy(sp_looked, game["looked"]);
116 sp_acopy(sp_bids, game["bids"]);
117 sp_acopy(sp_nil, game["nil"]);
118 sp_acopy(sp_pass, game["pass"]);
119 sp_acopy(sp_tricks, game["tricks"]);
122 sp_channel = game["channel"];
123 sp_owner = game["owner"];
124 sp_playto = game["playto"];
125 sp_dealer = game["dealer"];
126 sp_turn = game["turn"];
127 sp_player = game["player"];
128 sp_limit = game["limit"];
129 sp_acopy(sp_hands, game["hands"]);
130 sp_acopy(sp_players, game["players"]);
131 sp_acopy(sp_auths, game["auths"]);
132 sp_acopy(sp_order, game["order"]);
133 sp_acopy(sp_scores, game["scores"]);
136 function sp_pretty(cards, who)
139 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
140 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
141 gsub(/s/, "\002♠", cards)
142 gsub(/h/, "\002♥", cards)
143 gsub(/d/, "\002♦", cards)
144 gsub(/c/, "\002♣", cards)
149 function sp_next(who, prev)
152 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
153 if (length(sp_order) == 4)
154 sp_player = sp_order[sp_turn]
158 function sp_deal( shuf)
160 say("/me deals the cards")
161 asorti(sp_deck, shuf, "sp_usort")
162 for (i=1; i<=52; i++)
163 sp_hands[sp_order[i%4]][shuf[i]] = 1
165 sp_dealer = (sp_dealer+1)%4
167 sp_player = sp_order[sp_turn]
168 say("Bidding starts with " sp_player "!")
171 function sp_hand(who, sort, str)
173 asorti(sp_hands[who], sort, "sp_csort")
174 for (i=0; i<length(sort); i++)
175 str = str "" sprintf("%4s", sort[i])
176 gsub(/^ +| +$/, "", str)
177 return sp_pretty(str, who)
180 function sp_hasa(who, expr)
182 for (c in sp_hands[who]) {
189 function sp_type(card)
191 return substr(card, length(card))
194 function sp_usort(a,b,c,d) {
198 function sp_csort(i1,v1,i2,v2) {
199 return sp_deck[i1] > sp_deck[i2] ? +1 :
200 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
203 function sp_winner( card, tmp)
205 for (card in sp_pile)
206 if (card !~ sp_suit && card !~ /s/)
208 asorti(sp_pile, tmp, "sp_csort")
209 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
215 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
216 return sp_order[i+0] "/" sp_order[i+2]
219 function sp_bags(i, bags)
221 bags = sp_scores[i] % sp_limit
227 function sp_bidders( i, turn, bid, bids)
229 for (i = 0; i < 4; i++) {
230 turn = (sp_dealer + i) % 4
231 if (sp_bids[turn] && !sp_nil[turn]) {
232 bid = sp_order[turn] ":" sp_bids[turn]
236 gsub(/^ +| +$/, "", bids)
240 function sp_score( bids, tricks)
242 for (i=0; i<2; i++) {
243 bids = sp_bids[i] + sp_bids[i+2]
244 tricks = sp_tricks[i] + sp_tricks[i+2]
246 if (sp_bags(i) + bags >= sp_limit) {
247 say(sp_team(i) " bag out")
248 sp_scores[i] -= sp_limit * 10
250 if (tricks >= bids) {
251 say(sp_team(i) " make their bid: " tricks "/" bids)
252 sp_scores[i] += bids*10 + bags;
254 say(sp_team(i) " go bust: " tricks "/" bids)
255 sp_scores[i] -= bids*10;
258 for (i=0; i<4; i++) {
261 say(sp_order[i] " " \
262 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
263 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
264 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
265 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
267 sp_scores[i%2] += 100 * sp_nil[i] * \
268 (sp_tricks[i] == 0 ? 1 : -1)
272 function sp_play(card, winner, pi)
274 delete sp_hands[sp_from][card]
275 sp_pile[card] = sp_player
276 sp_piles = sp_piles (sp_piles?",":"") card
283 if (length(sp_pile) == 1)
284 sp_suit = sp_type(card)
287 if (length(sp_pile) == 4) {
289 pi = sp_players[sp_pile[winner]]
291 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
292 " (" sp_pretty(sp_piles, FROM) ")")
293 sp_next(sp_pile[winner])
298 if (sp_tricks[0] + sp_tricks[1] + \
299 sp_tricks[2] + sp_tricks[3] == 13) {
302 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
303 sp_scores[0] != sp_scores[1]) {
305 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
307 say(sp_team(winner) " wins the game " \
308 sp_scores[winner] " to " sp_scores[looser])
309 say(sp_order[winner+0] "++")
310 say(sp_order[winner+2] "++")
311 say(sp_order[looser+0] "--")
312 say(sp_order[looser+2] "--")
316 if (sp_scores[0] == sp_scores[1] &&
317 sp_scores[0] >= sp_playto)
318 say("It's tie! Playing an extra round!");
327 cmd = "od -An -N4 -td4 /dev/random"
333 sp_load("var/sp_cur.json");
335 # say(sp_channel, "Game restored.")
339 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : FROM
340 sp_valid = sp_from && sp_from == sp_player
346 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
351 sp_save("var/sp_save.json");
357 sp_load("var/sp_save.json");
362 /^\.help [Ss]pades$/ {
363 say("Spades -- play a game of spades")
365 say(".newgame [score] -- start a game to <score> points, default 500")
366 say(".endgame -- abort the current game")
367 say(".savegame -- save the current game to disk")
368 say(".loadgame -- load the previously saved game")
369 say(".join -- join the current game")
370 say(".look -- look at your cards")
371 say(".bid n -- bid for <n> tricks")
372 say(".play [card] -- play a card")
373 say(".score -- check the score")
374 say(".tricks -- check how many trick have been taken")
375 say(".bids -- check what everyone bid")
381 /^\.deal (\w+) (.*)/ {
383 for (i=3; i<=NF; i++)
385 say(sp_channel, FROM " is cheating for " $2)
390 /^\.newgame ?([0-9]+)?/ {
391 if (sp_state != "new") {
392 reply("There is already a game in progress.")
395 sp_playto = $2 ? $2 : 200
396 sp_limit = sp_playto > 200 ? 10 : 5;
399 say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
400 #say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
404 (sp_from == sp_owner || FROM == OWNER) &&
406 if (sp_state == "new") {
407 reply("There is no game in progress.")
409 say(FROM " ends the game")
415 if (sp_state == "new") {
416 reply("There is no game in progress")
418 else if (sp_state == "play") {
419 reply("The game has already started")
421 else if (sp_state == "join" && sp_from in sp_players) {
422 reply("You are already playing")
424 else if (sp_state == "join") {
428 sp_auths[AUTH] = FROM
430 say(FROM " joins the game!")
432 if (sp_state == "join" && sp_turn == 0)
437 (sp_state "bid" || sp_state == "play") &&
439 if (sp_from in sp_players)
440 say(".slap " FROM ", it is not your turn.")
442 say(".slap " FROM ", you are not playing.")
448 if ($2 < 0 || $2 > 13) {
449 say("You can only bid from 0 to 13")
453 if ($2 == 0 && !sp_looked[i]) {
454 say(FROM " goes blind nil!")
456 } else if ($2 == 0) {
457 say(FROM " goes nil!")
462 if (sp_turn != sp_dealer) {
463 say("Bidding goes to " sp_player "!")
465 for (p in sp_players)
466 say(p, "You have: " sp_hand(p))
468 for (i=0; i<2; i++) {
469 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
470 say(sp_team(i) ": select a card to pass " \
471 "(/msg " NICK " .pass <card>)")
475 if (sp_state == "play")
476 say("Play starts with " sp_player "!")
481 sp_state == "pass" &&
484 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
486 # check validity and pass
487 if (!(sp_from in sp_players)) {
488 say(".slap " FROM ", you are not playing.")
490 else if (sp_nil[_team] != 2 && sp_nil[_team+2] != 2) {
491 reply("Your team did not go blind")
493 else if (sp_pass[sp_players[sp_from]]) {
494 reply("You have already passed a card")
496 else if (!(_card in sp_deck)) {
497 reply("Invalid card")
499 else if (!(_card in sp_hands[sp_from])) {
500 reply("You do not have that card")
503 sp_pass[sp_players[sp_from]] = $2
504 say(sp_channel, FROM " passes a card")
507 # check for end of passing
508 if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
509 ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
513 delete sp_hands[sp_order[i]][_card]
514 sp_hands[sp_order[_partner]][_card] = 1
516 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
517 for (p in sp_players)
518 say(p, "You have: " sp_hand(p))
523 sp_state ~ "(play|bid)" &&
525 if (!(sp_from in sp_players)) {
526 say(".slap " FROM ", you are not playing.")
528 sp_looked[sp_players[sp_from]] = 1
529 say(FROM, "You have: " sp_hand(sp_from))
534 sp_state == "play" &&
537 if (!(card in sp_deck)) {
538 reply("Invalid card")
540 else if (!(card in sp_hands[sp_from])) {
541 reply("You do not have that card")
543 else if (sp_suit && card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
544 reply("You must follow suit (" sp_suit ")")
546 else if (card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
547 reply("You cannot trump on the first hand")
549 else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
550 reply("Spades have not been broken")
554 if (sp_state == "play") {
555 if (length(sp_hands[sp_from]))
556 say(FROM, "You have: " sp_hand(sp_from))
558 say(sp_player ": it is your turn! " \
559 "(" sp_pretty(sp_piles, sp_player) ")")
561 say(sp_player ": it is your turn!")
566 /^\.bids$/ && sp_state == "play" {
567 say(sp_order[0] " bid " sp_bids[0] ", " \
568 sp_order[2] " bid " sp_bids[2] ", " \
569 "total: " sp_bids[0] + sp_bids[2])
570 say(sp_order[1] " bid " sp_bids[1] ", " \
571 sp_order[3] " bid " sp_bids[3] ", " \
572 "total: " sp_bids[1] + sp_bids[3])
575 /^\.tricks$/ && sp_state == "play" {
576 say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
577 sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
578 say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
579 sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
582 /^\.turn/ && sp_state ~ "(play|bid)" {
584 _pile = sp_pretty(sp_piles, FROM)
585 if (sp_state == "bid" && !_bids)
586 say("It is " sp_player "'s bid!")
587 if (sp_state == "bid" && _bids)
588 say("It is " sp_player "'s bid! (" _bids ")")
589 if (sp_state == "play" && !_pile)
590 say("It is " sp_player "'s turn!")
591 if (sp_state == "play" && _pile)
592 say("It is " sp_player "'s turn! (" _pile ")")
595 (TO == NICK || DST == sp_channel) &&
596 /^\.(score|status)$/ {
597 if (sp_state == "new") {
598 say("There is no game in progress")
600 if (sp_state == "join") {
601 say("Waiting for players: " \
602 sp_order[0] " " sp_order[1] " " \
603 sp_order[2] " " sp_order[3])
605 if (sp_state == "bid" || sp_state == "play") {
606 say(sp_team(0) ": " \
607 int(sp_scores[0]) " points, " \
608 int(sp_bags(0)) " bags")
609 say(sp_team(1) ": " \
610 int(sp_scores[1]) " points, " \
611 int(sp_bags(1)) " bags")
615 /^\.((new|end|load)game|join|look|bid|play)/ {
616 sp_save("var/sp_cur.json");
620 #/^\.playfor [^ ]*$/ {
623 #/^\.standin [^ ]*$/ {
624 # if (p in sp_players) {
626 # for (p in sp_standin) {
627 # if ($2 in sp_standin)
628 # say(here " is already playing for " sp_standin[p]);
630 # sp_standin[away] = here