Giter Site home page Giter Site logo

rspeer / dominiate Goto Github PK

View Code? Open in Web Editor NEW
118.0 118.0 43.0 32.19 MB

A simulator for Dominion card game strategies

Home Page: http://rspeer.github.com/dominiate

License: MIT License

CoffeeScript 9.68% CSS 2.11% JavaScript 86.09% Makefile 0.02% HTML 1.96% Batchfile 0.01% Less 0.14%

dominiate's People

Contributors

aiannacc avatar amalloy avatar bilts avatar charles-toller avatar davio avatar drheld avatar jorbles avatar kcrca avatar michaeljb avatar robdennis avatar rspeer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dominiate's Issues

Minion Bug - Second Player discards hand always

After playing a second Minion the other player discards his had although he has only 4 cards in hand. Other players are only affected by Minion attacks if they have 5 or more cards in hand.

== Minion Chain's turn 10 ==
Minion Chain plays Minion.
Minion Chain discards the hand.
(Minion Chain shuffles.)
Minion Chain draws 4 cards: [Province, Minion, Copper, Minion].
Big Money discards the hand.
Big Money draws 4 cards: [Silver, Silver, Estate, Silver].
Minion Chain plays Minion.
Minion Chain discards the hand.
Minion Chain draws 4 cards: [Copper, Estate, Silver, Estate].
Big Money discards the hand.
Big Money draws 4 cards: [Estate, Copper, Gold, Copper].
Minion Chain plays Copper.
Minion Chain plays Silver.
Coins: 3, Potions: 0, Buys: 1
Coin Tokens left: 0
Minion Chain buys Silver.
Minion Chain draws 5 cards: [Copper, Silver, Copper, Copper, Estate].

Strategies run forever and buy nothing

First time trying this simulator, but no matter what strategies I choose, they run forever and don't seem to ever buy anything.

$ ./play.coffee strategies/SillyAI.coffee strategies/SillyAI.coffee 
strategies/SillyAI.coffee
strategies/SillyAI.coffee
(SillyAI shuffles.)
SillyAI draws 5 cards: [Estate, Estate, Estate, Copper, Copper].
(SillyAI shuffles.)
SillyAI draws 5 cards: [Copper, Copper, Estate, Copper, Copper].
Tableau: [Pawn, Workshop, Venture, Nomad Camp, Herbalist, Pirate Ship, Scout, Tactician, Peddler, Quarry]

== SillyAI's turn 1 ==
SillyAI plays Copper.
SillyAI plays Copper.
Coins: 2, Potions: 0, Buys: 1
SillyAI draws 5 cards: [Copper, Copper, Copper, Copper, Copper].

== SillyAI's turn 1 ==
SillyAI plays Copper.
SillyAI plays Copper.
SillyAI plays Copper.
SillyAI plays Copper.
Coins: 4, Potions: 0, Buys: 1
SillyAI draws 5 cards: [Copper, Copper, Copper, Estate, Estate].

== SillyAI's turn 2 ==
SillyAI plays Copper.
SillyAI plays Copper.
SillyAI plays Copper.
SillyAI plays Copper.
SillyAI plays Copper.
Coins: 5, Potions: 0, Buys: 1
(SillyAI shuffles.)
SillyAI draws 5 cards: [Estate, Copper, Copper, Copper, Copper].

== SillyAI's turn 2 ==
SillyAI plays Copper.
SillyAI plays Copper.
SillyAI plays Copper.
Coins: 3, Potions: 0, Buys: 1
(SillyAI shuffles.)
SillyAI draws 5 cards: [Copper, Copper, Estate, Copper, Copper].

Implement Forge

Ideally, Forge will prune its decisions so it doesn't have to consider all 2^n possibilities. Lots of the possibilities will be equivalent except for $0 cards, or will be pointless because they bring the total over $8 or $11.

Implement Stash

The hard part of this is that it adds a decision during shuffling, which can happen in the middle of another card resolving, and can result from code that's currently oblivious to the overall game state.

It's possible that we can get a satisfactory result from a simple decision that only knows about the player state.

Implement Embargo

The interesting part is guessing what your opponent wants.

I don't want to use Geronimoo's trick of peeking into the opponent's mind.

getVP of some cards return wrong values (e.g. Gardens)

It seems that when "state.current" is called inside of a cards getVP()-method 'current' always points to the first bot (the bot that finishes the game first).
This happens when getVP is called from within getFinalStatus().

The result is that wrong Points are given for example if the second Player uses gardens since state.current.getDeck().length will return the amount of cards of the first bot instead of the second bot.

I guess this affects all cards which use state.current inside the getVP method.

Poor Bishop choices

Strategy1 here is buying Bishops as soon as possible, and here it's trashing Silver instead of Estate:

== Strategy1's turn 1 ==
Strategy1 plays Copper.
Strategy1 plays Copper.
Strategy1 plays Copper.
Strategy1 plays Copper.
Coins: 4, Potions: 0, Buys: 1
Strategy1 buys Bishop.
Strategy1 draws 5 cards: [Copper, Estate, Copper, Copper, Estate].

...

== Strategy1's turn 2 ==
Strategy1 plays Copper.
Strategy1 plays Copper.
Strategy1 plays Copper.
Coins: 3, Potions: 0, Buys: 1
Strategy1 buys Silver.
(Strategy1 shuffles.)
Strategy1 draws 5 cards: [Estate, Bishop, Copper, Copper, Silver].

...

== Strategy1's turn 3 ==
Strategy1 plays Bishop.
...gaining 1 VP.
Strategy1 trashes Silver.
...gaining 1 VP.
Strategy2 trashes Estate.
Strategy1 plays Copper.
Strategy1 plays Copper.
Coins: 3, Potions: 0, Buys: 1
Strategy1 buys Silver.
Strategy1 draws 5 cards: [Estate, Estate, Copper, Copper, Copper].

Find choices that win instantly; avoid ones that lose instantly

The simulator should be able to avoid gaining a card that will cause it to lose the game. It should also try to gain/buy cards to win the game when possible (although some of the more interesting ways to do this are things it could only do by the relatively slow process of searching the game tree).

A forced gain with nothing wanted gains a Curse

If a player is being forced to gain a Card (ie they played Haggler), but the player doesn't want to gain any of the available choices (ie they bought a Silver with the Haggler in play, but don't want a Copper or Curse), the player gains a Curse. Might not always be Curse, but that's what showed up in my testing of Haggler. (maybe because Curse is the first card created in cards.coffee, so it's at the front of the card list?)

Obviously for Haggler this can be avoided by more sophisticated play rules, but that would not get rid of this underlying issue.

add "counters" metadata to each strategy as they are discovered

This data would become useful for someone trying to build a general ai that reacts.

For example, BM_Library very frequently beats DoubleMilitia so we would add a property to BM_Library as such:

counters: ['DoubleMilitia']

This information is useful to an experimenter trying to get ideas, just browsing and running the strategies.

This information may not be immediately used by this project, but could become useful to other projects.

Since everything counters SillyAI no need to mention what counters SillyAI.

This issue could be closed when at least half the strategies have recognized counters.

The counters list could be ordered in most significant counters to less significant.

Implement Native Village

There's a spot in @Mats reserved for the Native Village mat. The only hard part is going to be deciding when to take cards off the mat.

CoffeeScript Error: multiple object literal properties named "ai_playValue"

I'm trying to run my version of Dominate (which I just forked a few hours ago) on my local machine, but I am getting the following error:

$ ./play.coffee strategies/BigMoney.coffee strategies/ChapelWitch.coffee
SyntaxError: In /path/to/dominiate/cards.coffee, multiple object literal properties named "ai_playValue"
    at SyntaxError (unknown source)
    at Obj.compileNode (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:1187:19)
    at Obj.compile (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:46:21)
    at Value.compileNode (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:701:24)
    at Value.compile (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:46:21)
    at /usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:920:29
    at Call.compileNode (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:923:8)
    at Call.compile (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:46:21)
    at Block.compileNode (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:307:23)
    at Block.compileWithDeclarations (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:391:19)

I get the same error when I run make:

$ make
node_modules/.bin/lessc web/dominiate.less web/dominiate.css
coffee -c -j web/playWeb.js playWeb.coffee basicAI.coffee cards.coffee gameState.coffee
SyntaxError: In web/playWeb.js, multiple object literal properties named "ai_playValue"
    at SyntaxError (unknown source)
    at Obj.compileNode (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:1187:19)
    at Obj.compile (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:46:21)
    at Value.compileNode (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:701:24)
    at Value.compile (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:46:21)
    at /usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:920:29
    at Call.compileNode (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:923:8)
    at Call.compile (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:46:21)
    at Block.compileNode (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:307:23)
    at Block.compileWithDeclarations (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/nodes.js:391:19)
make: *** [web-coffee] Error 1

Version info:

$ coffee -v
CoffeeScript version 1.3.3
$ node -v
v0.6.18

Simulator never plays Lookout

in makeCard "Lookout",

  ai_playValue: (state, my) ->
    if state.gainsToEndGame >= 5 or state.cardInfo.Curse in my.draw
      895
    else
      -5

It should say

    if state.gainsToEndGame() >= 5 or state.cardInfo.Curse in my.draw

since state.gainsToEndGame is a function. Source

Ability to save strategies from the Web

Clearly, Dominiate would be more pleasant to use if you could save strategies to the Internet, retrieve them, and link to them.

I rather like the fact that Dominiate runs without a server (besides GitHub's web server). To be able to save strategies, then, we need an external place we can save to.

My current thought is to use our Wiki on GitHub to store strategies, which requires only a GitHub account (no particular permissions). I've figured out how to automatically generate Wiki posts where the user just needs to click "save". This would require people to have GitHub accounts to save things, though, which may be a mental barrier to entry.

gist.github.com allows anonymous posts, but then the URL you get is an arbitrary number, so you'd have to hold onto that number to save the strategy. I just had a wacky idea involving sending the resulting URL to TinyURL and giving it a name again. One problem with that is that you couldn't revise a strategy under the same name.

And I suppose a system that let you alter existing strategies, completely anonymously, would be vulnerable to griefing.

Any other ideas?

Implement Bishop

In the early game, the decisions are ordinary trashing, but trashing Duchies is useful, possibly even Provinces in the mid-game, and expensive non-victory cards should also be trashed in the late game.

Poor Vault choices

I was playing around with Vault today and noticed two poor choices. The following scenarios demonstrate the problem:

Scenario 1:
I have a Vault, two Golds, a Silver, and an Estate in my hand
I should not play Vault because it likely won't help me, but it may help my opponent

Scenario 2:
I have five Coppers in my hand
I have no Gold in my deck and perhaps no actions
My opponent plays Vault
I should choose not to discard 2 cards, because it's unlikely whatever I draw will make up for the loss of $2

The AI makes the wrong choice in both of these scenarios. The first one is probably Vault-specific. The second one likely applies to other cards as well.

Cards are probably being dropped on the floor

Trashing is now a specific action. If an effect trashes a card without using state.doTrash, it should be sure to append to the state.trash list itself. Otherwise, in a very realistic sense, it's dropping the card on the floor.

With trashing handled more consistently, we can now set the total number of cards in the game as an invariant and check it every turn. If the number decreases, cards are being dropped on the floor (and if it increases, cards are being duplicated).

While refactoring trashing, I caught a couple of cases where cards were being dropped (mostly by attempts to mutate a list with .concat, which does nothing). There are almost certainly other cases. We should create and check this invariant, and close this bug when we can get through many thousands of games while guaranteeing that no cards are lost.

Implement Apprentice

Doing Apprentice well would probably require looking ahead in the game state and planning more of the turn. But that takes time, so let's try to do Apprentice acceptably instead.

Implement Salvager

Some things to take into account:

  • Salvaging a good card to get to Province (or Colony)
  • Salvaging Provinces or Colonies when in the lead

Implement Inn

The play effect is straightforward, but there can be lots of possible choices for the on-gain decision.

Ability to link to a simulation

There should be a way to put information after the # in the URL that pre-populates the boxes with specific strategies and settings.

This would go particularly well with a way to save strategies (#18).

Occasionally makes poor decisions with Ambassador

The SillyAI will often play Ambassador because there is a card it wants to trash, such as Potion, but then its ambassadorPriority does not have a way of choosing that card.

This can probably be fixed simply by completing the priority list with a modified version of the trashPriority list.

Problems with state.supply[card]

Turns out adding (state.supply[card] ? 0) > 0 into upgradeChoices, instead of my current if not card2.isPrize band-aid will work. It looks like when the card object is created, it is added to state.supply--there are 10 of each of the prizes in the supply, and 30 of Diadem (since it is derived from Silver which is set to start at 30 in the supply), so anything that checks the supply will always find cards there (like the proposed fix for upgradeChoices). This problem also affects Ambassador; the Ambassador player can return a Prize (or ostensibly a card gained from the Black Market) and cause the other players to gain it.

For example:
Set a DoubleAmbassador player against a TournamentPlayer, have them each want to gain exactly 1 Remodel. Have the Ambassador player want to gain a Prize, like Bag of Gold, but not want to gain any Tournaments. Put "Bag of Gold,0" at the top of ambassadorPriority and make sure Ambassador is higher in actionPriority than Bag of Gold.
With those settings, you will see DoubleAmbassador Remodeling Coppers and Estates into Bag of Gold, and returning Bag of Gold when possible. TournamentPlayer will Remodel Coppers and Estates into Followers.

I'm working on it when I can. In practice it looks like the greatest danger will be a Tournament player using upgrading type cards--Tournament/Ambassador players probably won't be wanting to return Prizes anyway.

AI spends too much time evaluating impossible actions

I've been profiling the simulator. Web stuff aside, a very large amount of time is being spent in chooseByPriorityAndValue, particularly when it calls actionPriority.

actionPriority ends up evaluating the relative merits of every action in the game for the current game state every time it is called. This is very wasteful.

In most cases, simple AIs will have a very simple decision, e.g. do I play my Smithy? In many cases, the answer is always yes. As things stand, though, that AI is stuck considering how it'd rank its Smithy against a Spice Merchant, even if Spice Merchant isn't available in the game.

I'm not sure exactly how to fix this without really messing with how AIs are written, but it has a big impact on performance (around 20% of the sim run time, likely more for allocation/GC).

Implement Develop

The hard part is constructing the list of possible choices, taking into account price levels where there are no cards.

Implement Swindler

For Swindler in particular, we probably want to have a global list of cards ranked by their goodness. We could replace gainValue with it.

Giving your opponent more terminals than they can handle is also a good thing to do.

React with Secret Chamber; draw a reaction card

The player should be able to draw a reaction card using Secret Chamber and subsequently react with that card. We don't currently handle this. Simultaneously, the player needs to be able to react with, say, Moat, then react with Secret Chamber, placing Moat on top of the deck.

Cards should also be able to react to the same event twice. I can react with Secret Chamber, draw a Moat, react with Moat, then react with Secret Chamber again, placing Moat back on deck.

3+ player games on Web

We support them from the command line. We should have an interface for 3+-player games on the Web. This will probably require making the ACE edit box appear differently.

Courtyard holds onto money unnecessarily

The OBM Courtyard strategy plays far from optimally. If it has $7 in hand, for example, it doesn't seem to return a copper to its deck, even though the comments in the putOnDeckPriority say that it should.

Ability to define new cards from the Web

One way that Dominiate can really shine is allowing people to playtest new cards they propose (for example, on the Variants forum of forum.dominionstrategy.com).

People can run arbitrary CoffeeScript code on top of Dominiate already; that's almost everything they need to define new cards. We should have a system that supports this -- such as an optional box to define new cards in and get them added to the tableau. Probably depends on #21, for sanity.

Implement Possession

In addition to all the weird edge cases, an AI that's good at playing Possession will have to have an entirely different set of decision values when it's Possessing someone. I fully expect this to be the last card implemented.

Add another optimized Big Money variant

Hi rspeer,

after some try-and-error I found a Big Money variant, which is superior to BankWharf unless in Colony/Platinum games.

Bank + Ill-Gotten Gains work very well together.

{
name: 'BankIGG'
author: 'Spixi'
requires: ['Bank','Ill-Gotten Gains']
gainPriority: (state, my) -> [
"Colony" if my.countInDeck("Platinum") > 0
"Province"
"Duchy" if state.gainsToEndGame() <= 4
"Estate" if state.gainsToEndGame() <= 2
"Ill-Gotten Gains" if state.countInSupply("Curse") >= 1
"Bank"
"Platinum"
"Gold"
"Silver"
"Copper" if state.gainsToEndGame() <= 3
]
}

What do you think about this strategy? Should we include it to the predefined strategies?

Refactor card-specific game state

There should be a way for a card to store card-specific information in its own piece of the game state, instead of arbitrarily-named properties such as state.current.tacticians.

Pirate Ship bad decision bug

Pirate Ship when played doesn't choose to use it's money option until it reaches $5, which leads to it doing things like this:

== DoublePirateShip's turn 9 ==
DoublePirateShip plays Pirate Ship.
...attacking the other players.
...DoubleJack reveals [Copper, Jack of All Trades].
...DoublePirateShip trashes DoubleJack's Copper.
...DoubleJack discards [Jack of All Trades].
...DoublePirateShip takes a Coin token (4 on the mat).
DoublePirateShip plays Silver.
DoublePirateShip plays Silver.
DoublePirateShip plays Copper.
Coins: 5, Potions: 0, Buys: 1
DoublePirateShip buys Silver.
(DoublePirateShip shuffles.)
DoublePirateShip draws 5 cards: [Silver, Pirate Ship, Copper, Estate, Estate].

And this:
== DoublePirateShip's turn 11 ==
DoublePirateShip plays Pirate Ship.
...attacking the other players.
...DoubleJack reveals [Silver, Silver].
...DoublePirateShip trashes DoubleJack's Silver.
...DoubleJack discards [Silver].
...DoublePirateShip takes a Coin token (5 on the mat).
DoublePirateShip plays Silver.
DoublePirateShip plays Copper.
DoublePirateShip plays Copper.
Coins: 4, Potions: 0, Buys: 1
DoublePirateShip buys Silver.
DoublePirateShip draws 5 cards: [Silver, Copper, Silver, Copper, Copper].

Attacking other players when it should be buying Provinces.

Implement Scheme

Scheme needs its own decision at the beginning of the cleanup phase.

turn slow mode into "mostly fast mode"

The main reason one would want to run multiple games in slow mode is if you're not on Chrome, and therefore running lots of computation in JavaScript without returning control makes the whole browser sad.

We could avoid a lot of unnecessary DOM updates while still giving the diagnostic output of slow mode: update the score tracker less often, update the grapher less often, and stop logging games after the first 10.

At that point, clicking "Fast Mode" means you're okay with intense JavaScript operations that don't return control very often. The label would be "Fast Mode (makes some browsers sluggish)".

Strategies should have a list of cards they require

Each strategy should have an attribute called "require", containing a list of (names of) cards. The strategy is saying that it can't run unless those cards are in the supply.

Then, we can make actual 10-card kingdoms for our simulated games, ensuring that they contain all the cards that the players require. With meaningful kingdoms, we can then create a Bane pile for Young Witch, and a Black Market deck.

Poor Mint choices

The AI should be more careful about which treasures it chooses to play when buying Mint:

== Mint AI's turn 4 ==
Mint AI plays Silver.
Mint AI plays Quarry.
Mint AI plays Copper.
Mint AI plays Copper.
Mint AI plays Copper.
Coins: 6, Potions: 0, Buys: 1
Mint AI buys Mint.
...trashing a Copper.
...trashing a Copper.
...trashing a Copper.
...trashing a Quarry.
...trashing a Silver.
(Mint AI shuffles.)
Mint AI draws 5 cards: [Copper, Copper, Mint, Copper, Estate].

Implement Secret Chamber

I believe the reaction effect of Secret Chamber may be difficult to get right, but it will help to assume that we only want to reveal Secret Chamber once.

Implement Minion

The decision of whether to discard your hand can probably reuse code from Navigator, but this needs to be weighed against +$2 somehow.

Throne Room and King's Court don't nest correctly

Example:

ChapelPoorHouseThroneRoom draws 5 cards: [Poor House, Throne Room, Throne Room, Poor House, Chapel].

...


== ChapelPoorHouseThroneRoom's turn 11 ==
ChapelPoorHouseThroneRoom plays Throne Room.
...playing Throne Room (1 of 2).
...playing Poor House (1 of 2).
ChapelPoorHouseThroneRoom reveals the hand ([Poor House, Chapel]).
...playing Poor House (2 of 2).
ChapelPoorHouseThroneRoom reveals the hand ([Poor House, Chapel]).
...playing Poor House (2 of 2).
ChapelPoorHouseThroneRoom reveals the hand ([Poor House, Chapel]).
Coins: 12, Potions: 0, Buys: 1
ChapelPoorHouseThroneRoom buys Province.
(ChapelPoorHouseThroneRoom shuffles.)
ChapelPoorHouseThroneRoom draws 5 cards: [Province, Poor House, Province, Chapel, Throne Room].

When the Throne Room is played on the Throne Room, the second play of the nested TR becomes a play of Poor House instead. The root of this issue is the line action = state.current.ai.choose('multiplied', state, choices) in the King's Court implementation. It is interpreted as an assignment to a global variable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.