Jump to content

Demonic God

Member
  • Posts

    257
  • Joined

  • Last visited

  • Days Won

    12

Everything posted by Demonic God

  1. I'd also have to add, that some of the strategies might not be very easy to audit. I'll be doing extensive testing to make sure things run as intended, but auditing itself is not something I'd suggest other than for the more straightforward logic.
  2. Random order is what gave rise to our current dilemma, and is the default.
  3. Also - to clarify I guess since the randomized order does give some issue... but well Straight up random is still not allowed. You can try to implement some strange ways to confuse your opponents. Even as far as a fixed list of moves you wanna do. I guess the line between random and strategy kinda blurs there but... I also don't wanna rule lawyer exactly how can you implement your own version of pseudo random. Line's blurry. Is looping 10 choices on repeat "random"? 20? 50? What about changing where you start? Arg. Just keep it reasonable I suppose. Those of you who wish to make use of that info is free to add a revision :3
  4. Ehem, there are some new development during trial runs! Apparently, a lot of you have strategies relying on observation and rounds! And other stuff. Which led to an interesting thing: There's no definite winner. Those strategies works really, really well, and depending on the ordering, can change the winner completely. So I present the following two compromises: We run the simulations 100 times, and tally up! We run it 1 time, and let whoever wins, wins. I've also updated the judging rules a bit on draws and such. As well as how second spots are chosen.
  5. Codes sent to most participants. I'm eager to announce the observations There are some really, really fascinating interaction going on
  6. Mur added lossless transfer for 1SC per
  7. some may have been informal tests done directly on IDLE without being written into reusable unit tests as well :3
  8. player_move.py from enum import Enum, auto class PlayerMove(Enum): ROCK = 'Rock' PAPER = 'Paper' SCISSORS = 'Scissors' def __gt__(self, obj): if isinstance(obj, PlayerMove): return self == PlayerMove.ROCK and obj == PlayerMove.SCISSORS or \ self == PlayerMove.PAPER and obj == PlayerMove.ROCK or \ self == PlayerMove.SCISSORS and obj == PlayerMove.PAPER else: raise TypeError(f'Not instance of PlayerMove{obj}') def __ge__(self,obj): if isinstance(obj, PlayerMove): return self > obj or self == obj else: raise TypeError(f'Not instance of PlayerMove{obj}') def __lt__(self,obj): if isinstance(obj, PlayerMove): return not self >= obj else: raise TypeError(f'Not instance of PlayerMove{obj}') def __le__(self,obj): if isinstance(obj, PlayerMove): return self < obj or self == obj else: raise TypeError(f'Not instance of PlayerMove{obj}') def getCounter(move): if isinstance(move, PlayerMove): return PlayerMove.PAPER if move == PlayerMove.ROCK else PlayerMove.SCISSORS if move == PlayerMove.PAPER else PlayerMove.ROCK else: raise TypeError(f'Not instance of PlayerMove{obj}') def getNotCounter(move): if isinstance(move, PlayerMove): return PlayerMove.PAPER if move == PlayerMove.SCISSORS else PlayerMove.SCISSORS if move == PlayerMove.ROCK else PlayerMove.ROCK else: raise TypeError(f'Not instance of PlayerMove{obj}') Just an enum representing Rock, Paper and Scissors tournament.py from player_move import * import random class Tournament: def __init__(self, *participants, output = 'output.txt'): self.log = open(output, "w", encoding="utf-8") self.participants = {p.name: p for p in participants} self.moveAnnouncer = EventDispatcher() #Announces player moves result (announce what the two picked) self.matchAnnouncer = EventDispatcher() #Announces match (starting match between two players) self.roundAnnouncer = EventDispatcher() #Announces round (list of players) for participant in participants: self.moveAnnouncer.addListener(participant.moveListener) self.matchAnnouncer.addListener(participant.matchListener) self.roundAnnouncer.addListener(participant.roundListener) self.currentPlayers = [p.name for p in participants] self.currentMatches = [] self.currentResults = {} def _generateMatches(self): # I hate myself for writing codes so ugly... but it's soooo convenient self.currentMatches = [[self.currentPlayers[p], self.currentPlayers[q]] for p in range(len(self.currentPlayers)) for q in range(len(self.currentPlayers)) if p < q] random.shuffle(self.currentMatches) self.currentResults = {p: {q: None for q in self.currentPlayers if p is not q} for p in self.currentPlayers} def _executeMove(self, player1, player2, pos): move1 = self.participants[player1].getMove() move2 = self.participants[player2].getMove() self.moveAnnouncer.broadcast({ 'player1': player1, 'player2': player2, 'move1': move1, 'move2': move2, 'pos': pos, }) return move1, move2 def _executeMatch(self, player1, player2): win1 = 0 win2 = 0 draw = 0 movePos = 0 self.log.write(f'Starting match between {player1} and {player2}\n') self.matchAnnouncer.broadcast({ 'player1': player1, 'player2': player2, 'event': 'start', }) while win1 < 10 and win2 < 10: if draw >= 500: self.log.write(f'Stalemate!\n') break # Executing a single move move1, move2 = self._executeMove(player1, player2, movePos) msg = 'ERR' #this should change if move1 > move2: win1 += 1 msg = f'{player1} wins!' elif move1 < move2: win2 += 1 msg = f'{player2} wins!' else: draw += 1 msg = "it's a draw!" self.log.write(f'Turn {movePos}: {player1} plays {move1.value}, {player2} plays {move2.value}, {msg}\n') movePos += 1 result = player1 if win1 == 10 else player2 if win2 == 10 else 'draw' if result == 'draw': self.log.write(f'Match ended in a draw!\n\n') self.currentResults[player1][player2] = 'draw' self.currentResults[player2][player1] = 'draw' else: self.log.write(f'Player {result} won the match!\n\n') self.currentResults[player1][player2] = 'win' if result == player1 else 'lose' self.currentResults[player2][player1] = 'lose' if result == player1 else 'win' self.matchAnnouncer.broadcast({ 'player1': player1, 'player2': player2, 'event': 'end', 'result': result, }) def _executeRound(self): self.roundAnnouncer.broadcast({ 'event': 'start', 'players': self.currentPlayers, }) self.log.write(f"Here's our contestants for this round: {', '.join(self.currentPlayers)}!\n") self._generateMatches() assert len(self.currentMatches) > 0 while self.currentMatches: player1, player2 = self.currentMatches.pop() self._executeMatch(player1,player2) worst = self._findWorst() stats = self._generateStats() self.log.write(f"Round ended! Here's the score!\n") for p in self.currentPlayers: self.log.write(f"{p}: {stats[p]['wins']} wins, {stats[p]['loses']} loses, {stats[p]['draws']} draws\n") self.log.write(f"The following contestants dropped out: {' '.join(worst)}\n\n") self.currentPlayers = [p for p in self.currentPlayers if p not in worst] self.roundAnnouncer.broadcast({ 'event': 'end', 'dropout': worst, }) def _generateStats(self): stats = {p: {'wins': 0, 'loses': 0, 'draws': 0} for p in self.currentPlayers} for p in self.currentPlayers: for r,v in self.currentResults[p].items(): assert v is not None stats[p]['wins'] += 1 if v == 'win' else 0 stats[p]['loses'] += 1 if v == 'lose' else 0 stats[p]['draws'] += 1 if v == 'draw' else 0 return stats def _findWorst(self): stats = self._generateStats() min_win = min([v['wins'] for p,v in stats.items()]) max_lose_in_min_win = max([v['loses'] for p,v in stats.items() if v['wins'] == min_win]) worst_players = [p for p in stats if stats[p]['wins'] == min_win and stats[p]['loses'] == max_lose_in_min_win] assert len(worst_players) > 0 if len(worst_players) == 1: return worst_players worst_of_worst = [] for p in worst_players: for p2 in worst_players: if p is not p2 and self.currentResults[p][p2] == 'win': break else: worst_of_worst.append(p) if len(worst_of_worst) > 0: return worst_of_worst else: return worst_players def executeGame(self): self.log.write(f"The tournament has begun!\n") draws = [] result = None while len(self.currentPlayers) > 1: draws = self.currentPlayers self._executeRound() if len(self.currentPlayers) == 1: self.log.write(f"Congratulations to {self.currentPlayers[0]} for winning the tournament!\n") result = self.currentPlayers if len(self.currentPlayers) == 0: self.log.write(f"Looks like there's no apparent victor! The following players tied for top place: {' '.join(draws)}\n") result = draws self.log.close() return result class EventDispatcher: def __init__(self): self.listeners = [] def addListener(self, listener): self.listeners.append(listener) def removeListener(self, listener): if listener in self.listeners: self.listeners.remove(listener) def broadcast(self, *data): for listener in self.listeners: listener(*data) # try: # except: # print(f'Error broadcasting {data} to {listener}') The current tournament emulator. It outputs text into "output.txt" (customizable). strategies.py from player_move import * # ALL STRATEGIES SHOULD EXTEND BASE STRATEGY. Or at least implement the same thing as base strategy class BaseStrategy: def __init__(self): self.name = 'Scissors' # 'player1': player1 # 'player2': player2 # 'move1': move by player1 # 'move2': move by player2 # 'pos': turn count (position of the "move") def moveListener(self, move): pass # 'player1': player1 # 'player2': player2 # 'event': 'start' or 'end' # 'result': result if event is 'end' def matchListener(self, match): pass # 'event': 'start' or 'end' # 'players': list of players if event is 'start' # 'dropouts': dropouts if event is 'end' def roundListener(self, round): pass # Your main logic def getMove(self): return PlayerMove.SCISSORS class Rock(BaseStrategy): def __init__(self): self.name = 'Rocks' def getMove(self): return PlayerMove.ROCK class Paper(BaseStrategy): def __init__(self): self.name = 'Papers' def getMove(self): return PlayerMove.PAPER class Rand(BaseStrategy): def __init__(self): self.name = 'Rand' def getMove(self): import random r = random.randrange(0,3) return PlayerMove.ROCK if r == 0 else PlayerMove.PAPER if r == 1 else PlayerMove.SCISSORS Where all the strategies are implemented. BaseStrategy should give you an idea of what is provided by the tournament. A few sample strategy is provided here. Note that random is used only for testing purposes - your strategy cannot be random (fixed seed pseudorandom is acceptable) main.py from tournament import * from strategies import * participants = [] participants.append(Rock()) participants.append(Paper()) participants.append(Rand()) participants.append(BaseStrategy()) tournament = Tournament(*participants) tournament.executeGame() simple main to create a tournament instance, and executes it. Have fun! Please report any bugs you spot too I'll be sending over each player individual strategy as I implement them (via PM). You're free to do so yourself (and save me effort!), though you'd be responsible for your own mistakes hehe. If you have any question, feel free to PM If you really, really wanna toy/benchmark your strategy, send me a PM and I can rush the implementation of your strategy Additionally - The tournament will be postponed to 3 days after I've sent everyone their strategy in code form for any last minute changes and toying around. Sorry for all the delays!
  9. Well... I pushed him to make this quest, and god forbids me from not submitting an entry into a cooking quest! So I present: The Runny Chocolatey Brownie of Addiction! Ingredients: 8 Winderwild eggs (preferably the unfertilized unhatch-able chicken-like kind). Replace with Angien Eggs if you're filthy rich without a moral compass. Replace with Drachorn Eggs if you have a death wish. Just not Elemental Eggs *glares at Fyrd* Butter, two sticks. I have no idea how you'd even find them, perhaps Taurion might know where you can get some. Sugar, about 1.2 cups. Crushing some candy canes should do niceeely. Some flavorful herbs. I've heard they're called "vanilla". Maybe you can find them with a herb basket. Maybe you can't. Coffee extract. Or powder. Or Espresso if you're fancy. Popular with lab researchers. Perhaps you should visit the Golemus lab to find out more. Or not. I can't promise you won't be turned into an experiment. Flowers! Wait, no, flour! Go rob MaG, he collected a ton! Wait, no, that's still flower. Erm, perhaps the Golem Mill might have some? Anyway, you need 2 cups of this stuff. Salt. This shouldn't be hard to find. Could even bully someone and harvest their tears for their salt content! Or blood, blood is pretty salty too, right? CHOCOLATE! 1 bar (better be dark chocolate, 70%). Ask your date on Valentine. What, no date? Well, at least that would take care of your salt issues! Cocoa powder. 0.4 cup. Don't snort them. They may be addictive, but not THAT type of addictive. Utensils and an oven. A whip, mixing bowl, container bowls, a pot, spatula, measuring cups, baking tray, parchment paper. If you feel like this is a bit NSFW, you're thinking of the wrong type of whip. Steps Chop the chocolate. Doesn't matter how, they'll get melted later. Thin flakes makes it easier to melt, but not too thin, else it'll melt on the chopping board Put the butter into a small pot, and heat it slowly to a boil. Don't burn it. Crack 4 eggs into the mixing bowl. Separate the yolk from the remaining 4. Also put them into the bowl. Do whatever with the extra whites. Whip the eggs together, until harmonious. As harmonious as Ledah and MaG were when they schemed to kill Granos. Slowly pour the boiling butter over the egg, whipping vigorously to prevent the egg from cooking Put the chocolate into the hot mix, and whip some more. No, not BDSM style. Whip til the choco melts into a nice blend! Put in the vanilla, coffee extract, sugar crushed candy canes, cocoa powder, and salt, and continue mixing Put in the flour! Make sure to pick off the pedals... wait, no, that's flower again, urg! Make sure the flour don't clump, use your hand, a strainer, whatever. Now, get rid of the whip and use a spatula to fold the mixture together. The longer you mix, the chewier the final brownie will get Put your parchment paper over your baking tray. Some oil could be used to help it stick. Some trimming and folding can make things looks nice. Some social skill may help with that valentine chocolate. Just sayin :3 Pour the mixture into the tray. Put into oven. This is a very complicated step. No, really, it varies a LOT based on your equipment. Usually I'd say half an hour at around 220 Celsius. Or 493.15 for you weirdos with a Kelvin oven. Personally, I pour half. Bake for ~7 minutes. Pour remaining half. Bake for 8. Cover with foil. Bake for another 5-10 minutes. This is the result of repeatedly experimenting with my oven, which is technically not even an oven! You'll need to tinker a lot to get a just-right result to your liking. Including with ingredients. Take it out. Wait. Wait longer. Wait til it stop smoking, I don't care how good it smell damnit! Cut and enjoy. With tea. Or coffee. Depending on how "cultured" you are Why this makes me happy I've been using this recipe a lot. Tinkered with it, a lot. Changed multiple steps. Tried multiple techniques. Baked dozens. The thing is - I also barely ate any. This is a treat I make for family. Friends. Guests. I do like sweet, and I love what I made, but what makes me happy is to see others enjoys it (and choke on that sweet, sweet calories!). I'm still tweaking it batch-by-batch. The process of making, the experimentation, and most of all, the joys and appreciation, is what makes this dish special. So, while I'd love to have the MD community try it some day, the best I could do is to post pictures here These pics may have come from 3 different batches that I made in the past week - I recently tested the double baking process (that also changed a lot of the steps). It's just one improvement of, what I hope to be, many more in the future
  10. Hmn, what about we hide the unbind buttons by default. To unbind, you'd need to click an additional button to swap to unbind mode / show all unbind buttons.
  11. Looking for: Reindrach GG Drachorn Molima Morph Please PM me if you have any spare to sell/trade!
  12. Notable mention would be Steno, who did send in an outside-the-box submission jokingly stating that there's no way to tell, since the construction crew could've screwed up the walls and resulted in strange bounces! I was tempted to give him the creativity award, but sadly, as we all know, his current lack of access to a computer (and busy hosting various quests too), prevented him from giving me a theory on how the wall deforms could've looked like
  13. Here is the final list of all who submitted a correct solution! @Aia del Mana @Aelis @Dracoloth @Fyrd Argentus @Tissy @Trola @Yoshi Please let me know which spellstone you want here or via PM. I'll try to get them to you before the next anni Also: Lady Aia wins an extra GC for having a correct solution less than30 minutes after the quest went online! As for the anni crits - well, it's hard to say, rather, since there was two particular methods that people used to solve this problem: Observing that the balls slowly move towards the two corners, 1 cm at a time, every 2 bounces. Thus, it took 2020 (smaller edges) x 2 (bounces per cm) x 2 (back and forth) - 1 = 8079 bounces Tracing the bounces for smaller n/(n+1) rectangles, and finding a general formula of 4 * n - 1. As such, the winners were selected as the solutions that stood out the most to me, for each of this category. Hence: Tissy wins an anni, for a creative solution (that actually resembles a general case solution for any n x m rectangle and any starting launch angle, that I know of). While he did eventually returned to the 1cm logic, his way of reaching it stood out Yoshi wins an anni, for observing the pattern (with pictures demonstrating the bounces) for smaller rooms, before concluding on the general formula.
  14. 10. Ungod I'll... just assume I understand his schematics. It also seems that he's missing 6 empty spaces unaccounted for, if I'm reading his material summary correctly xD Regardless, a very creative approach, that comes with some actual masonry reasoning! - had it come with some actual rocks and such, or a small scale physical model with some stones, I'd have awarded a wp
  15. 9. Aelis He made some beautiful lego blocks, so I guess I'll not port it xD Also coincidentally, he used exactly 16 Z, T and L blocks! It's fancy, though sadly didn't pass my requirement for a WP
  16. 7. Dracoloth Yeah it takes some time to redo most normal submissions into a standard format
  17. 5. Nepgear Took some time re-doing his submission into picture form. It was fine, but this is a bit more clear
  18. 4. Kaya A submission hours before deadline, but nevertheless, simple yet effective.
  19. 3. Yoshi The first submission (and so far... the only submission that used my suggestion of a numbering format. With multiple revisions. He himself was the reason why I made the python script for visualization and scoring xD. (Note to Yoshi - you could've gotten 184 - and the second prize, as you did submit before Fyrd)
  20. 2. Fyrd A solution inspired by actual masonry, resulting in a brick-wall like pattern. However, it also amazes with how high of a score it attained!
  21. 1. Aia A solution with a high degree of symmetry, AND made extensive use of Z-shapes for the highest score!
×
×
  • Create New...