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_score( bids, tricks)
220 for (i=0; i<2; i++) {
221 bids = sp_bids[i] + sp_bids[i+2]
222 tricks = sp_tricks[i] + sp_tricks[i+2]
224 if (sp_bags(i) + bags >= 10) {
225 say(sp_team(i) " bag out")
228 if (tricks >= bids) {
229 say(sp_team(i) " make their bid: " tricks "/" bids)
230 sp_scores[i] += bids*10 + bags;
232 say(sp_team(i) " go bust: " tricks "/" bids)
233 sp_scores[i] -= bids*10;
236 for (i=0; i<4; i++) {
239 say(sp_order[i] " " \
240 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
241 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
242 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
243 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
245 sp_scores[i%2] += 100 * sp_nil[i] * \
246 (sp_tricks[i] == 0 ? 1 : -1)
250 function sp_play(card, winner, pi)
252 delete sp_hands[FROM][card]
253 sp_pile[card] = sp_player
254 sp_piles = sp_piles (sp_piles?",":"") card
261 if (length(sp_pile) == 1)
262 sp_suit = sp_type(card)
265 if (length(sp_pile) == 4) {
267 pi = sp_players[sp_pile[winner]]
269 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
270 " (" sp_pretty(sp_piles, FROM) ")")
271 sp_next(sp_pile[winner])
276 if (sp_tricks[0] + sp_tricks[1] + \
277 sp_tricks[2] + sp_tricks[3] == 13) {
280 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
281 sp_scores[0] != sp_scores[1]) {
283 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
285 say(sp_team(winner) " wins the game " \
286 sp_scores[winner] " to " sp_scores[looser])
287 say(sp_order[winner+0] "++")
288 say(sp_order[winner+2] "++")
289 say(sp_order[looser+0] "--")
290 say(sp_order[looser+2] "--")
294 if (sp_scores[0] == sp_scores[1] &&
295 sp_scores[0] >= sp_playto)
296 say("It's tie! Playing an extra round!");
305 cmd = "od -An -N4 -td4 /dev/random"
314 sp_valid = (FROM && FROM == sp_player)
319 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
324 sp_save("var/spades.json");
329 sp_load("var/spades.json");
333 /^\.help [Ss]pades$/ {
334 say("Spades -- play a game of spades")
336 say(".newgame [score] -- start a game to <score> points, default 500")
337 say(".endgame -- abort the current game")
338 say(".savegame -- save the current game to disk")
339 say(".loadgame -- load the previously saved game")
340 say(".join -- join the current game")
341 say(".look -- look at your cards")
342 say(".bid n -- bid for <n> tricks")
343 say(".play [card] -- play a card")
344 say(".score -- check the score")
345 say(".tricks -- check how many trick have been taken")
346 say(".bids -- check what everyone bid")
352 /^\.deal (\w+) (.*)/ {
354 for (i=3; i<=NF; i++)
356 say(sp_channel, FROM " is cheating for " $2)
361 /^\.newgame ?([0-9]+)?/ {
362 if (sp_state != "new") {
363 reply("There is already a game in progress.")
366 sp_playto = $2 ? $2 : 200
369 say(sp_owner " starts a game of Spades to " sp_playto "!")
370 #say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
374 (FROM == sp_owner || FROM == OWNER) &&
376 if (sp_state == "new") {
377 reply("There is no game in progress.")
379 say(FROM " ends the game")
385 if (sp_state == "new") {
386 reply("There is no game in progress")
388 else if (sp_state == "play") {
389 reply("The game has already started")
391 else if (sp_state == "join" && FROM in sp_players) {
392 reply("You are already playing")
394 else if (sp_state == "join") {
398 say(FROM " joins the game!")
400 if (sp_state == "join" && sp_turn == 0)
405 (sp_state "bid" || sp_state == "play") &&
407 if (FROM in sp_players)
408 say(".slap " FROM ", it is not your turn.")
410 say(".slap " FROM ", you are not playing.")
416 if ($2 < 0 || $2 > 13) {
417 say("You can only bid from 0 to 13")
421 if ($2 == 0 && !sp_looked[i]) {
422 say(FROM " goes blind nil!")
424 } else if ($2 == 0) {
425 say(FROM " goes nil!")
430 if (sp_turn != sp_dealer) {
431 say("Bidding goes to " sp_player "!")
433 for (p in sp_players)
434 say(p, "You have: " sp_hand(p))
436 for (i=0; i<2; i++) {
437 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
438 say(sp_team(i) ": select a card to pass " \
439 "(/msg " NICK " .pass <card>)")
443 if (sp_state == "play")
444 say("Play starts with " sp_player "!")
449 sp_state == "pass" &&
452 team = sp_players[FROM] % 2
453 if (!(FROM in sp_players)) {
454 say(".slap " FROM ", you are not playing.")
456 else if (sp_nil[team] != 2 && sp_nil[team+2] != 2) {
457 reply("Your team did not go blind")
459 else if (sp_pass[sp_players[FROM]]) {
460 reply("You have already passed a card")
462 else if (!(card in sp_deck)) {
463 reply("Invalid card")
465 else if (!(card in sp_hands[FROM])) {
466 reply("You do not have that card")
469 sp_pass[sp_players[FROM]] = $2
470 say(sp_channel, FROM " passes a card")
472 if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
473 ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
477 delete sp_hands[sp_order[i]][card]
478 sp_hands[sp_order[partner]][card] = 1
480 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
481 for (p in sp_players)
482 say(p, "You have: " sp_hand(p))
487 sp_state ~ "(play|bid)" &&
489 if (!(FROM in sp_players)) {
490 say(".slap " FROM ", you are not playing.")
492 sp_looked[sp_players[FROM]] = 1
493 say(FROM, "You have: " sp_hand(FROM))
498 sp_state == "play" &&
501 if (!(card in sp_deck)) {
502 reply("Invalid card")
504 else if (!(card in sp_hands[FROM])) {
505 reply("You do not have that card")
507 else if (sp_suit && card !~ sp_suit && sp_hasa(FROM, sp_suit)) {
508 reply("You must follow suit (" sp_suit ")")
510 else if (card ~ /s/ && length(sp_hands[FROM]) == 13 && sp_hasa(FROM, "[^s]$")) {
511 reply("You cannot trump on the first hand")
513 else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(FROM, "[^s]$") && !sp_broken) {
514 reply("Spades have not been broken")
518 if (sp_state == "play") {
519 if (length(sp_hands[FROM]))
520 say(FROM, "You have: " sp_hand(FROM))
522 say(sp_player ": it is your turn! " \
523 "(" sp_pretty(sp_piles, sp_player) ")")
525 say(sp_player ": it is your turn!")
530 /^\.bids$/ && sp_state == "play" {
531 say(sp_order[0] " bid " sp_bids[0] ", " \
532 sp_order[2] " bid " sp_bids[2] ", " \
533 "total: " sp_bids[0] + sp_bids[2])
534 say(sp_order[1] " bid " sp_bids[1] ", " \
535 sp_order[3] " bid " sp_bids[3] ", " \
536 "total: " sp_bids[1] + sp_bids[3])
539 /^\.tricks$/ && sp_state == "play" {
540 say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
541 sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
542 say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
543 sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
546 /\.turn/ && sp_state ~ "(play|bid)" {
551 _bids = (t>0 ? ( sp_order[(d+0)%4] ": " sp_bids[(d+0)%4]) : "") \
552 (t>1 ? (", " sp_order[(d+1)%4] ": " sp_bids[(d+1)%4]) : "") \
553 (t>2 ? (", " sp_order[(d+2)%4] ": " sp_bids[(d+2)%4]) : "") \
554 (t>3 ? (", " sp_order[(d+3)%4] ": " sp_bids[(d+3)%4]) : "")
555 _pile = sp_pretty(sp_piles, sp_player)
557 if (sp_state == "bid" && sp_turn <= 0)
558 say("It is " sp_player "'s bid!")
559 if (sp_state == "bid" && sp_turn > 0)
560 say("It is " sp_player "'s bid! (" _bids ")")
561 if (sp_state == "play" && sp_turn <= 0)
562 say("It is " sp_player "'s turn!")
563 if (sp_state == "play" && sp_turn > 0)
564 say("It is " sp_player "'s turn! (" _pile ")")
567 (TO == NICK || DST == sp_channel) &&
568 /^\.(score|status)$/ {
569 if (sp_state == "new") {
570 say("There is no game in progress")
572 if (sp_state == "join") {
573 say("Waiting for players: " \
574 sp_order[0] " " sp_order[1] " " \
575 sp_order[2] " " sp_order[3])
577 if (sp_state == "bid" || sp_state == "play") {
578 say(sp_team(0) ": " \
579 int(sp_scores[0]) " points, " \
580 int(sp_bags(0)) " bags")
581 say(sp_team(1) ": " \
582 int(sp_scores[1]) " points, " \
583 int(sp_bags(1)) " bags")
588 #/^\.playfor [^ ]*$/ {
591 #/^\.standin [^ ]*$/ {
592 # if (p in sp_players) {
594 # for (p in sp_standin) {
595 # if ($2 in sp_standin)
596 # say(here " is already playing for " sp_standin[p]);
598 # sp_standin[away] = here