Bunco Simulator

Diff

Differences From Artifact [22520d]:

To Artifact [929d7a]:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
# Test
import csv, random

teammate = {
    1: 3,
    2: 4,
    3: 1,
    4: 2
}

def TurnInProgress():
    return -1

def roll_dice():
    dice = []
    for _ in range(3):
        dice.append(random.randint(1,6))
    return dice

class Player:
    fuzzydie_holder = None


    def __init__(self, name, dex, math, speed):
        self.name = name
        self.dex = dex
        self.math_comprehension = math
        self.roll_speed = speed
        self.max_streak = 0



|
<
<
<
<
<












>







1
2
3
4





5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Test
import csv, random

teammate_lookup = { 0: 2, 1: 3, 2: 0, 3: 1 }






def TurnInProgress():
    return -1

def roll_dice():
    dice = []
    for _ in range(3):
        dice.append(random.randint(1,6))
    return dice

class Player:
    fuzzydie_holder = None
    current_round = 1

    def __init__(self, name, dex, math, speed):
        self.name = name
        self.dex = dex
        self.math_comprehension = math
        self.roll_speed = speed
        self.max_streak = 0
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    def prep_new_round(self):
        self.round_scores.append(0)
        self.round_roll_counts.append(0)
        self.personal_roll_scores.append(0)
        self.turn_progress = 0
        self.current_streak = 0

    def score_last_roll(self, current_round):
        desired_num = current_round % 6
        desired_num = 6 if desired_num == 0 else desired_num
    
        roll_score = 0
        
        if all(die == desired_num for die in self.current_roll):
            # Bunco!
            roll_score = 21
        elif all(die == self.current_roll[0] for die in self.current_roll):
            # All three dice match, but not Bunco
            roll_score = 5
        else:
            for die in self.current_roll:
                roll_score += 1 if die == desired_num else 0

        if roll_score > 0:
            self.current_streak += 1
            self.max_streak = max(self.current_streak, self.max_streak)
            self.round_scores[current_round - 1] += roll_score
            self.personal_roll_scores[current_round - 1] += roll_score
            if roll_score == 21:
                self.bunco_count += 1
                self.rolled_bunco = True
        else:
            self.current_streak = 0
        
        return roll_score

    def tick(self, current_round):
        result = TurnInProgress()

        if self.fuzzydie_holder is self:
            self.current_fuzzydie_streak += 1
            self.max_fuzzydie_streak = max(self.max_fuzzydie_streak, self.current_fuzzydie_streak)
        else:
            self.current_fuzzydie_streak = 0







|
|

















|
|








|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    def prep_new_round(self):
        self.round_scores.append(0)
        self.round_roll_counts.append(0)
        self.personal_roll_scores.append(0)
        self.turn_progress = 0
        self.current_streak = 0

    def score_last_roll(self):
        desired_num = self.current_round % 6
        desired_num = 6 if desired_num == 0 else desired_num
    
        roll_score = 0
        
        if all(die == desired_num for die in self.current_roll):
            # Bunco!
            roll_score = 21
        elif all(die == self.current_roll[0] for die in self.current_roll):
            # All three dice match, but not Bunco
            roll_score = 5
        else:
            for die in self.current_roll:
                roll_score += 1 if die == desired_num else 0

        if roll_score > 0:
            self.current_streak += 1
            self.max_streak = max(self.current_streak, self.max_streak)
            self.round_scores[self.current_round - 1] += roll_score
            self.personal_roll_scores[self.current_round - 1] += roll_score
            if roll_score == 21:
                self.bunco_count += 1
                self.rolled_bunco = True
        else:
            self.current_streak = 0
        
        return roll_score

    def tick(self):
        result = TurnInProgress()

        if self.fuzzydie_holder is self:
            self.current_fuzzydie_streak += 1
            self.max_fuzzydie_streak = max(self.max_fuzzydie_streak, self.current_fuzzydie_streak)
        else:
            self.current_fuzzydie_streak = 0
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126




127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
            # TODO: Incorporate ROLL SPEED stat
            self.turn_progress += random.randint(12,25)
        elif self.turn_progress < 75:
            # Reading the numbers
            # TODO: Incorporate MATH COMPREHENSION stat
            if not self.current_roll:
                self.current_roll = roll_dice()
                self.round_roll_counts[current_round - 1] += 1
            self.turn_progress += random.randint(12,25)
        else:
            # Finished reading the numbers -- good job, eyeballs and brain!
            result = self.score_last_roll(current_round)
            self.current_roll = []
            self.turn_progress = 0
        return result

class Table:
    table_count = 0

    def __init__(self):
        self.table_count += 1
        self.table_number = self.table_count
        self.team1_score = 0
        self.team2_score = 0
        self.players = []
        self.active_player = -1

    def __repr__(self):
        names = ", ".join([p.name for p in self.players])
        return f"<Table {self.table_number}: {names}>"





    def tick(self, current_round):
        if self.active_player == -1:
            # First tick for the table this round
            self.active_player = random.randint(1, len(self.players)) - 1

        result = self.players[self.active_player].tick(current_round)

        if result != TurnInProgress():
            # Player rolled
            if result > 0:
                if (self.active_player % 2) == 0:
                    self.team1_score += result
                else:
                    self.team2_score += result

                self.players[teammate[self.active_player + 1]-1].round_scores[current_round - 1] += result
            else:
                self.active_player += 1
                if self.active_player > (len(self.players) - 1): self.active_player = 0
    
    def roll_off(self, current_round):
        """Attempt to settle a tie by going round the table once"""
        self.active_player = 0
        
        # Let the first player go until they roll for 0 points
        while self.active_player == 0:
            self.tick(current_round)
        # Now let the rest do the same
        while self.active_player != 0:
            self.tick(current_round)

    def losers(self):
        if self.team1_score > self.team2_score:
            return self.players[1::2]
        else:
            return self.players[0::2]
    







|



|



















>
>
>
>
|




|









|




|





|


|







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
            # TODO: Incorporate ROLL SPEED stat
            self.turn_progress += random.randint(12,25)
        elif self.turn_progress < 75:
            # Reading the numbers
            # TODO: Incorporate MATH COMPREHENSION stat
            if not self.current_roll:
                self.current_roll = roll_dice()
                self.round_roll_counts[self.current_round - 1] += 1
            self.turn_progress += random.randint(12,25)
        else:
            # Finished reading the numbers -- good job, eyeballs and brain!
            result = self.score_last_roll()
            self.current_roll = []
            self.turn_progress = 0
        return result

class Table:
    table_count = 0

    def __init__(self):
        self.table_count += 1
        self.table_number = self.table_count
        self.team1_score = 0
        self.team2_score = 0
        self.players = []
        self.active_player = -1

    def __repr__(self):
        names = ", ".join([p.name for p in self.players])
        return f"<Table {self.table_number}: {names}>"

    def update_teammate_score(self, score):
        teammate = self.players[teammate_lookup[self.active_player]]
        teammate.round_scores[Player.current_round - 1] += score

    def tick(self):
        if self.active_player == -1:
            # First tick for the table this round
            self.active_player = random.randint(1, len(self.players)) - 1

        result = self.players[self.active_player].tick()

        if result != TurnInProgress():
            # Player rolled
            if result > 0:
                if (self.active_player % 2) == 0:
                    self.team1_score += result
                else:
                    self.team2_score += result

                self.update_teammate_score(result)
            else:
                self.active_player += 1
                if self.active_player > (len(self.players) - 1): self.active_player = 0
    
    def roll_off(self):
        """Attempt to settle a tie by going round the table once"""
        self.active_player = 0
        
        # Let the first player go until they roll for 0 points
        while self.active_player == 0:
            self.tick()
        # Now let the rest do the same
        while self.active_player != 0:
            self.tick()

    def losers(self):
        if self.team1_score > self.team2_score:
            return self.players[1::2]
        else:
            return self.players[0::2]
    
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    def prep_new_round(self):
        self.team1_score = 0
        self.team2_score = 0
        self.active_player = -1
        for player in self.players:
            player.prep_new_round()


def assign_teams(player_list):
    players_per_table = 4
    tables = []
    random.seed()

    if len(player_list) % players_per_table != 0:
        print("Wrong number of players!")







<







200
201
202
203
204
205
206

207
208
209
210
211
212
213
    def prep_new_round(self):
        self.team1_score = 0
        self.team2_score = 0
        self.active_player = -1
        for player in self.players:
            player.prep_new_round()


def assign_teams(player_list):
    players_per_table = 4
    tables = []
    random.seed()

    if len(player_list) % players_per_table != 0:
        print("Wrong number of players!")
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    
    return players

class Game:
    def __init__(self, playerfile):
        self.players = load_players(playerfile)
        self.tables = assign_teams(self.players)
        self.current_round = 1

    def tick(self):
        for table in self.tables:
            table.tick(self.current_round)
        
        bunco_rollers = [p for p in self.players if p.rolled_bunco is True]
        
        # If multiple people rolled Bunco this tick, and one of them already has the
        # fuzzy die, they retain it.
        # Otherwise, the last person in the list gets the fuzzy die.
        if bunco_rollers and Player.fuzzydie_holder not in bunco_rollers:
            Player.fuzzydie_holder = bunco_rollers[-1]
            for player in bunco_rollers:
                player.rolled_bunco = False # Reset flag

    def print_status(self):
        for n, table in enumerate(self.tables):
            print(f"== TABLE {n+1} == Team 1:{table.team1_score} pts, Team 2:{table.team2_score} pts")
            for player in table.players:
                print(f"    {player.name} {player.round_scores[self.current_round - 1]} points, streak {player.max_streak} buncos {player.bunco_count}")

    def prep_next_round(self):
        # losers from head table move to next table
        headtable_losers = self.tables[0].losers()
        round_winners = self.tables[1].swap_for_winners(headtable_losers)

        # winners from other tables move to next table
        for n in range(2, len(self.tables)):
            round_winners = self.tables[n].swap_for_winners(round_winners)
        # last set of winners moves to head table
        self.tables[0].swap_for_losers(round_winners)

        for table in self.tables:
            table.prep_new_round()

        self.current_round += 1

    def play_one_round(self):
        # Go until one of the head table teams reaches 21 pts
        while max(self.tables[0].team1_score, self.tables[0].team2_score) < 21:
            self.tick()

        print("\n\n\t\tB U N C O !!!\n\n")
        
        # Finish up scoring for any players that have unscored rolls
        for player in self.players:
            if player.current_roll:
                print(f"Finishing up: {player}")
                while player.current_roll:
                    player.tick(self.current_round)
        
        # Settle ties at each table by doing a roll-off as many times as needed
        for table in self.tables:
            while table.team1_score == table.team2_score:
                print(f"Roll off! {table}")
                table.roll_off(self.current_round)

        self.print_status()







|



|















|















|













|





|


234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
    
    return players

class Game:
    def __init__(self, playerfile):
        self.players = load_players(playerfile)
        self.tables = assign_teams(self.players)
        Player.current_round = 1

    def tick(self):
        for table in self.tables:
            table.tick()
        
        bunco_rollers = [p for p in self.players if p.rolled_bunco is True]
        
        # If multiple people rolled Bunco this tick, and one of them already has the
        # fuzzy die, they retain it.
        # Otherwise, the last person in the list gets the fuzzy die.
        if bunco_rollers and Player.fuzzydie_holder not in bunco_rollers:
            Player.fuzzydie_holder = bunco_rollers[-1]
            for player in bunco_rollers:
                player.rolled_bunco = False # Reset flag

    def print_status(self):
        for n, table in enumerate(self.tables):
            print(f"== TABLE {n+1} == Team 1:{table.team1_score} pts, Team 2:{table.team2_score} pts")
            for player in table.players:
                print(f"    {player.name} {player.round_scores[Player.current_round - 1]} points, streak {player.max_streak} buncos {player.bunco_count}")

    def prep_next_round(self):
        # losers from head table move to next table
        headtable_losers = self.tables[0].losers()
        round_winners = self.tables[1].swap_for_winners(headtable_losers)

        # winners from other tables move to next table
        for n in range(2, len(self.tables)):
            round_winners = self.tables[n].swap_for_winners(round_winners)
        # last set of winners moves to head table
        self.tables[0].swap_for_losers(round_winners)

        for table in self.tables:
            table.prep_new_round()

        Player.current_round += 1

    def play_one_round(self):
        # Go until one of the head table teams reaches 21 pts
        while max(self.tables[0].team1_score, self.tables[0].team2_score) < 21:
            self.tick()

        print("\n\n\t\tB U N C O !!!\n\n")
        
        # Finish up scoring for any players that have unscored rolls
        for player in self.players:
            if player.current_roll:
                print(f"Finishing up: {player}")
                while player.current_roll:
                    player.tick()
        
        # Settle ties at each table by doing a roll-off as many times as needed
        for table in self.tables:
            while table.team1_score == table.team2_score:
                print(f"Roll off! {table}")
                table.roll_off()

        self.print_status()